2
0
Эх сурвалжийг харах

* merged the wasm branch. Adds support for the wasm32 (WebAssembly 32-bit)
target.

git-svn-id: trunk@48955 -

nickysn 4 жил өмнө
parent
commit
fc32428639
100 өөрчлөгдсөн 11207 нэмэгдсэн , 268 устгасан
  1. 113 1
      .gitattributes
  2. 16 3
      Makefile
  3. 3 0
      Makefile.fpc
  4. 48 15
      compiler/Makefile
  5. 17 5
      compiler/Makefile.fpc
  6. 1 1
      compiler/aasmcnst.pas
  7. 27 0
      compiler/aasmtai.pas
  8. 98 2
      compiler/aggas.pas
  9. 4 0
      compiler/compinnr.pas
  10. 57 38
      compiler/dbgdwarf.pas
  11. 2 2
      compiler/entfile.pas
  12. 11 0
      compiler/fpcdefs.inc
  13. 6 0
      compiler/globals.pas
  14. 1 1
      compiler/hlcgobj.pas
  15. 7 0
      compiler/i8086/n8086mem.pas
  16. 3 0
      compiler/msg/errore.msg
  17. 1 1
      compiler/msgidx.inc
  18. 74 70
      compiler/msgtxt.inc
  19. 1 1
      compiler/ncal.pas
  20. 11 6
      compiler/ncgflw.pas
  21. 21 12
      compiler/ncgmem.pas
  22. 24 1
      compiler/ncgset.pas
  23. 3 0
      compiler/nset.pas
  24. 11 0
      compiler/options.pas
  25. 10 1
      compiler/pdecsub.pas
  26. 8 0
      compiler/pp.pas
  27. 6 12
      compiler/ppcjvm.lpi
  28. 74 0
      compiler/ppcwasm32.lpi
  29. 2 2
      compiler/pstatmnt.pas
  30. 1 1
      compiler/psub.pas
  31. 4 0
      compiler/psystem.pas
  32. 5 2
      compiler/symconst.pas
  33. 9 5
      compiler/systems.inc
  34. 16 12
      compiler/systems.pas
  35. 71 0
      compiler/systems/i_embed.pas
  36. 123 0
      compiler/systems/i_wasi.pas
  37. 98 1
      compiler/systems/t_embed.pas
  38. 263 0
      compiler/systems/t_wasi.pas
  39. 2 2
      compiler/tgobj.pas
  40. 2 0
      compiler/tokens.pas
  41. 22 7
      compiler/utils/Makefile
  42. 6 0
      compiler/utils/fpc.pp
  43. 265 0
      compiler/utils/mkwasmreg.pp
  44. 10 8
      compiler/utils/ppuutils/ppudump.pp
  45. 338 0
      compiler/wasm32/aasmcpu.pas
  46. 604 0
      compiler/wasm32/agbinaryen.pas
  47. 328 0
      compiler/wasm32/agllvmmc.pas
  48. 1107 0
      compiler/wasm32/agwat.pas
  49. 18 0
      compiler/wasm32/ccpuinnr.inc
  50. 129 0
      compiler/wasm32/cgcpu.pas
  51. 417 0
      compiler/wasm32/cpubase.pas
  52. 103 0
      compiler/wasm32/cpuinfo.pas
  53. 47 0
      compiler/wasm32/cpunode.pas
  54. 306 0
      compiler/wasm32/cpupara.pas
  55. 178 0
      compiler/wasm32/cpupi.pas
  56. 69 0
      compiler/wasm32/cputarg.pas
  57. 1882 0
      compiler/wasm32/hlcgcpu.pas
  58. 101 0
      compiler/wasm32/itcpugas.pas
  59. 36 0
      compiler/wasm32/itcpuwasm.pas
  60. 355 0
      compiler/wasm32/nwasmadd.pas
  61. 80 0
      compiler/wasm32/nwasmcal.pas
  62. 172 0
      compiler/wasm32/nwasmcnv.pas
  63. 494 0
      compiler/wasm32/nwasmcon.pas
  64. 263 0
      compiler/wasm32/nwasmflw.pas
  65. 213 0
      compiler/wasm32/nwasminl.pas
  66. 233 0
      compiler/wasm32/nwasmmat.pas
  67. 502 0
      compiler/wasm32/nwasmset.pas
  68. 451 0
      compiler/wasm32/rgcpu.pas
  69. 6 0
      compiler/wasm32/rwasmcon.inc
  70. 2 0
      compiler/wasm32/rwasmnor.inc
  71. 6 0
      compiler/wasm32/rwasmnum.inc
  72. 6 0
      compiler/wasm32/rwasmrni.inc
  73. 6 0
      compiler/wasm32/rwasmsri.inc
  74. 6 0
      compiler/wasm32/rwasmstd.inc
  75. 6 0
      compiler/wasm32/rwasmsup.inc
  76. 70 0
      compiler/wasm32/strinst.inc
  77. 351 0
      compiler/wasm32/symcpu.pas
  78. 321 0
      compiler/wasm32/tgcpu.pas
  79. 45 0
      compiler/wasm32/tripletcpu.pas
  80. 155 0
      compiler/wasm32/wasmdef.pas
  81. 23 0
      compiler/wasm32/wasmreg.dat
  82. 22 4
      installer/Makefile
  83. 6 3
      packages/Makefile
  84. 11 3
      packages/a52/Makefile
  85. 11 3
      packages/ami-extra/Makefile
  86. 11 3
      packages/amunits/Makefile
  87. 11 3
      packages/arosunits/Makefile
  88. 11 3
      packages/aspell/Makefile
  89. 11 3
      packages/bfd/Makefile
  90. 11 3
      packages/bzip2/Makefile
  91. 1 1
      packages/bzip2/fpmake.pp
  92. 11 3
      packages/cairo/Makefile
  93. 11 3
      packages/cdrom/Makefile
  94. 24 4
      packages/cdrom/examples/Makefile
  95. 11 3
      packages/chm/Makefile
  96. 1 1
      packages/chm/fpmake.pp
  97. 11 3
      packages/cocoaint/Makefile
  98. 11 3
      packages/dblib/Makefile
  99. 11 3
      packages/dbus/Makefile
  100. 24 4
      packages/dbus/examples/Makefile

+ 113 - 1
.gitattributes

@@ -680,6 +680,7 @@ compiler/ppcriscv32.lpi svneol=native#text/plain
 compiler/ppcriscv64.lpi svneol=native#text/plain
 compiler/ppcsparc.lpi svneol=native#text/plain
 compiler/ppcsparc64.lpi svneol=native#text/plain
+compiler/ppcwasm32.lpi svneol=native#text/plain
 compiler/ppcx64.lpi svneol=native#text/plain
 compiler/ppcx64llvm.lpi svneol=native#text/plain
 compiler/ppcxtensa.lpi svneol=native#text/plain
@@ -873,6 +874,7 @@ compiler/systems/i_palmos.pas svneol=native#text/plain
 compiler/systems/i_sinclairql.pas svneol=native#text/plain
 compiler/systems/i_sunos.pas svneol=native#text/plain
 compiler/systems/i_symbian.pas svneol=native#text/plain
+compiler/systems/i_wasi.pas svneol=native#text/plain
 compiler/systems/i_watcom.pas svneol=native#text/plain
 compiler/systems/i_wdosx.pas svneol=native#text/plain
 compiler/systems/i_wii.pas svneol=native#text/plain
@@ -909,6 +911,7 @@ compiler/systems/t_palmos.pas svneol=native#text/plain
 compiler/systems/t_sinclairql.pas svneol=native#text/plain
 compiler/systems/t_sunos.pas svneol=native#text/plain
 compiler/systems/t_symbian.pas svneol=native#text/plain
+compiler/systems/t_wasi.pas svneol=native#text/plain
 compiler/systems/t_watcom.pas svneol=native#text/plain
 compiler/systems/t_wdosx.pas svneol=native#text/plain
 compiler/systems/t_wii.pas svneol=native#text/plain
@@ -944,6 +947,7 @@ compiler/utils/mkjvmreg.pp svneol=native#text/plain
 compiler/utils/mkmpsreg.pp svneol=native#text/plain
 compiler/utils/mkppcreg.pp svneol=native#text/plain
 compiler/utils/mkspreg.pp svneol=native#text/plain
+compiler/utils/mkwasmreg.pp svneol=native#text/plain
 compiler/utils/mkx86inl.pp svneol=native#text/plain
 compiler/utils/mkx86ins.pp svneol=native#text/plain
 compiler/utils/mkx86reg.pp svneol=native#text/plain
@@ -962,6 +966,43 @@ compiler/utils/ppuutils/ppuxml.pp svneol=native#text/plain
 compiler/utils/samplecfg svneol=native#text/plain
 compiler/verbose.pas svneol=native#text/plain
 compiler/version.pas svneol=native#text/plain
+compiler/wasm32/aasmcpu.pas svneol=native#text/plain
+compiler/wasm32/agbinaryen.pas svneol=native#text/plain
+compiler/wasm32/agllvmmc.pas svneol=native#text/plain
+compiler/wasm32/agwat.pas svneol=native#text/plain
+compiler/wasm32/ccpuinnr.inc svneol=native#text/plain
+compiler/wasm32/cgcpu.pas svneol=native#text/plain
+compiler/wasm32/cpubase.pas svneol=native#text/plain
+compiler/wasm32/cpuinfo.pas svneol=native#text/plain
+compiler/wasm32/cpunode.pas svneol=native#text/plain
+compiler/wasm32/cpupara.pas svneol=native#text/plain
+compiler/wasm32/cpupi.pas svneol=native#text/plain
+compiler/wasm32/cputarg.pas svneol=native#text/plain
+compiler/wasm32/hlcgcpu.pas svneol=native#text/plain
+compiler/wasm32/itcpugas.pas svneol=native#text/plain
+compiler/wasm32/itcpuwasm.pas svneol=native#text/plain
+compiler/wasm32/nwasmadd.pas svneol=native#text/plain
+compiler/wasm32/nwasmcal.pas svneol=native#text/plain
+compiler/wasm32/nwasmcnv.pas svneol=native#text/plain
+compiler/wasm32/nwasmcon.pas svneol=native#text/plain
+compiler/wasm32/nwasmflw.pas svneol=native#text/plain
+compiler/wasm32/nwasminl.pas svneol=native#text/plain
+compiler/wasm32/nwasmmat.pas svneol=native#text/plain
+compiler/wasm32/nwasmset.pas svneol=native#text/plain
+compiler/wasm32/rgcpu.pas svneol=native#text/plain
+compiler/wasm32/rwasmcon.inc svneol=native#text/plain
+compiler/wasm32/rwasmnor.inc svneol=native#text/plain
+compiler/wasm32/rwasmnum.inc svneol=native#text/plain
+compiler/wasm32/rwasmrni.inc svneol=native#text/plain
+compiler/wasm32/rwasmsri.inc svneol=native#text/plain
+compiler/wasm32/rwasmstd.inc svneol=native#text/plain
+compiler/wasm32/rwasmsup.inc svneol=native#text/plain
+compiler/wasm32/strinst.inc svneol=native#text/plain
+compiler/wasm32/symcpu.pas svneol=native#text/plain
+compiler/wasm32/tgcpu.pas svneol=native#text/plain
+compiler/wasm32/tripletcpu.pas svneol=native#text/plain
+compiler/wasm32/wasmdef.pas svneol=native#text/plain
+compiler/wasm32/wasmreg.dat svneol=native#text/plain
 compiler/widestr.pas svneol=native#text/plain
 compiler/wpo.pas svneol=native#text/plain
 compiler/wpobase.pas svneol=native#text/plain
@@ -11965,7 +12006,6 @@ rtl/riscv64/setjump.inc svneol=native#text/plain
 rtl/riscv64/setjumph.inc svneol=native#text/plain
 rtl/riscv64/strings.inc svneol=native#text/plain
 rtl/riscv64/stringss.inc svneol=native#text/plain
-rtl/sinclairql/Makefile svneol=native#text/plain
 rtl/sinclairql/Makefile.fpc svneol=native#text/plain
 rtl/sinclairql/buildrtl.pp svneol=native#text/plain
 rtl/sinclairql/qdos.inc svneol=native#text/plain
@@ -12156,6 +12196,30 @@ rtl/unix/unxdeclh.inc svneol=native#text/plain
 rtl/unix/unxovl.inc svneol=native#text/plain
 rtl/unix/unxovlh.inc svneol=native#text/plain
 rtl/unix/x86.pp svneol=native#text/plain
+rtl/wasi/Makefile svneol=native#text/plain
+rtl/wasi/Makefile.fpc svneol=native#text/plain
+rtl/wasi/rtldefs.inc svneol=native#text/plain
+rtl/wasi/si_prc.pp svneol=native#text/plain
+rtl/wasi/sysdir.inc svneol=native#text/plain
+rtl/wasi/sysfile.inc svneol=native#text/plain
+rtl/wasi/sysheap.inc svneol=native#text/plain
+rtl/wasi/sysos.inc svneol=native#text/plain
+rtl/wasi/sysosh.inc svneol=native#text/plain
+rtl/wasi/system.pp svneol=native#text/plain
+rtl/wasi/wasiapi.pp svneol=native#text/plain
+rtl/wasi/wasiinc/wasiprocs.inc svneol=native#text/plain
+rtl/wasi/wasiinc/wasitypes.inc svneol=native#text/plain
+rtl/wasm32/cpuh.inc svneol=native#text/plain
+rtl/wasm32/cpuinnr.inc svneol=native#text/plain
+rtl/wasm32/int64p.inc svneol=native#text/plain
+rtl/wasm32/makefile.cpu svneol=native#text/plain
+rtl/wasm32/math.inc svneol=native#text/plain
+rtl/wasm32/set.inc svneol=native#text/plain
+rtl/wasm32/setjump.inc svneol=native#text/plain
+rtl/wasm32/setjumph.inc svneol=native#text/plain
+rtl/wasm32/strings.inc svneol=native#text/plain
+rtl/wasm32/stringss.inc svneol=native#text/plain
+rtl/wasm32/wasm32.inc svneol=native#text/plain
 rtl/watcom/Makefile svneol=native#text/plain
 rtl/watcom/Makefile.fpc svneol=native#text/plain
 rtl/watcom/classes.pp svneol=native#text/plain
@@ -19800,3 +19864,51 @@ utils/unicode/unihelper.lpi svneol=native#text/plain
 utils/unicode/unihelper.lpr svneol=native#text/pascal
 utils/unicode/weight_derivation.inc svneol=native#text/pascal
 utils/usubst.pp svneol=native#text/plain
+utils/wasmbin/Makefile svneol=native#text/plain
+utils/wasmbin/Makefile.fpc svneol=native#text/plain
+utils/wasmbin/README.md svneol=native#text/plain
+utils/wasmbin/fpmake.pp svneol=native#text/plain
+utils/wasmbin/lebutils.pas svneol=native#text/plain
+utils/wasmbin/parseutils.pas svneol=native#text/plain
+utils/wasmbin/testscan/asmsym1.wat svneol=native#text/plain
+utils/wasmbin/testscan/asmsym2.wat svneol=native#text/plain
+utils/wasmbin/testscan/asmsym3.wat svneol=native#text/plain
+utils/wasmbin/testscan/call_indirect1.wat svneol=native#text/plain
+utils/wasmbin/testscan/call_indirect2.wat svneol=native#text/plain
+utils/wasmbin/testscan/call_indirect3.wat svneol=native#text/plain
+utils/wasmbin/testscan/call_indirect4.wat svneol=native#text/plain
+utils/wasmbin/testscan/elem1.wat svneol=native#text/plain
+utils/wasmbin/testscan/elem2.wat svneol=native#text/plain
+utils/wasmbin/testscan/import1.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_f32.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_f32_neg.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_f64.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_f64_neg.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i32.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i32_neg.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i64.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i64_neg.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i64_neg_hex.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_const_i64_pos.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_if_value.wat svneol=native#text/plain
+utils/wasmbin/testscan/inst_unreachable.wat svneol=native#text/plain
+utils/wasmbin/wasa.lpi svneol=native#text/plain
+utils/wasmbin/wasa.pas svneol=native#text/plain
+utils/wasmbin/wasmbin.pas svneol=native#text/plain
+utils/wasmbin/wasmbincode.pas svneol=native#text/plain
+utils/wasmbin/wasmbindebug.pas svneol=native#text/plain
+utils/wasmbin/wasmbinwriter.pas svneol=native#text/plain
+utils/wasmbin/wasmld.lpi svneol=native#text/plain
+utils/wasmbin/wasmld.lpr svneol=native#text/plain
+utils/wasmbin/wasmlink.pas svneol=native#text/plain
+utils/wasmbin/wasmlinkchange.pas svneol=native#text/plain
+utils/wasmbin/wasmmodule.pas svneol=native#text/plain
+utils/wasmbin/wasmnormalize.pas svneol=native#text/plain
+utils/wasmbin/wasmtext.pas svneol=native#text/plain
+utils/wasmbin/wasmtool.lpi svneol=native#text/plain
+utils/wasmbin/wasmtool.lpr svneol=native#text/plain
+utils/wasmbin/wasmtoolutils.pas svneol=native#text/plain
+utils/wasmbin/watparser.pas svneol=native#text/plain
+utils/wasmbin/watscanner.pas svneol=native#text/plain
+utils/wasmbin/wattest.lpi svneol=native#text/plain
+utils/wasmbin/wattest.lpr svneol=native#text/plain

+ 16 - 3
Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: help
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -419,6 +419,9 @@ endif
 ifeq ($(CPU_TARGET),z80)
 PPSUF=z80
 endif
+ifeq ($(CPU_TARGET),wasm32)
+PPSUF=wasm32
+endif
 ifdef CROSSCOMPILE
 ifneq ($(CPU_TARGET),jvm)
 PPPRE=ppcross
@@ -784,7 +787,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_DIRS+=compiler rtl utils packages installer
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_DIRS+=compiler rtl utils packages installer
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_DIRS+=compiler rtl utils packages installer
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2745,7 +2751,14 @@ TARGET_DIRS_UTILS=1
 TARGET_DIRS_PACKAGES=1
 TARGET_DIRS_INSTALLER=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+TARGET_DIRS_COMPILER=1
+TARGET_DIRS_RTL=1
+TARGET_DIRS_UTILS=1
+TARGET_DIRS_PACKAGES=1
+TARGET_DIRS_INSTALLER=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 TARGET_DIRS_COMPILER=1
 TARGET_DIRS_RTL=1
 TARGET_DIRS_UTILS=1

+ 3 - 0
Makefile.fpc

@@ -97,6 +97,9 @@ endif
 ifeq ($(CPU_TARGET),z80)
 PPSUF=z80
 endif
+ifeq ($(CPU_TARGET),wasm32)
+PPSUF=wasm32
+endif
 
 # cross compilers uses full cpu_target, not just ppc-suffix
 # (except if the target cannot run a native compiler)

+ 48 - 15
compiler/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -350,10 +350,10 @@ endif
 override PACKAGE_NAME=compiler
 override PACKAGE_VERSION=3.3.1
 unexport FPC_VERSION FPC_COMPILERINFO
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
 ALLTARGETS=$(CYCLETARGETS)
 NO_NATIVE_COMPILER_OS_LIST=amstradcpc embedded freertos gba macosclassic msdos msxdos nds palmos symbian watcom wii win16 zxspectrum
-NO_NATIVE_COMPILER_CPU_LIST=avr i8086 jvm z80
+NO_NATIVE_COMPILER_CPU_LIST=avr i8086 jvm z80 wasm32
 ifneq ($(CPU_SOURCE),$(CPU_TARGET))
 ifneq ($(findstring $(CPU_TARGET),$(NO_NATIVE_COMPILER_CPU_LIST)),)
 NoNativeBinaries=1
@@ -552,6 +552,9 @@ endif
 ifeq ($(CPC_TARGET),z80)
 CPUSUF=z80
 endif
+ifeq ($(CPC_TARGET),wasm32)
+CPUSUF=wasm32
+endif
 NOCPUDEF=1
 MSGFILE=msg/error$(FPCLANG).msg
 SVNVERSION:=$(firstword $(wildcard $(addsuffix /svnversion$(SRCEXEEXT),$(SEARCHPATH))))
@@ -633,6 +636,9 @@ endif
 ifeq ($(PPC_TARGET),riscv64)
 override LOCALOPT+=-Furiscv
 endif
+ifeq ($(PPC_TARGET),wasm32)
+override LOCALOPT+=-dNOOPT
+endif
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 ifneq ($(findstring $(OS_TARGET),darwin linux dragonfly freebsd solaris),)
@@ -916,7 +922,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_DIRS+=utils
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_DIRS+=utils
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_DIRS+=utils
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1228,7 +1237,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_PROGRAMS+=pp
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_PROGRAMS+=pp
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_PROGRAMS+=pp
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1541,7 +1553,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_INCLUDEDIR+=$(CPC_TARGET)
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1853,7 +1868,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_UNITDIR+=$(COMPILERSOURCEDIR)
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2165,7 +2183,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_TARGETDIR+=$(CPU_UNITDIR)/bin/$(FULL_TARGET)
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2477,7 +2498,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_UNITTARGETDIR+=$(CPU_UNITDIR)/units/$(FULL_TARGET)
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -3551,7 +3575,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 REQUIRE_PACKAGES_RTL=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -3735,7 +3762,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif
@@ -4518,7 +4545,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 TARGET_DIRS_UTILS=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+TARGET_DIRS_UTILS=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 TARGET_DIRS_UTILS=1
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -4770,8 +4800,8 @@ endif
 ifdef TEMPWPONAME2PREFIX
 	$(MAKE) g$(TEMPWPONAME2) COMPILERTEMPNAME=$(TEMPWPONAME2)
 endif
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
-PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
+PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80 wasm32
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 .PHONY: $(PPC_TARGETS) $(INSTALL_TARGETS)$(SYMLINKINSTALL_TARGETS)
@@ -4875,7 +4905,10 @@ regdatmips : mips/mipsreg.dat
 regdatz80 : z80/z80reg.dat
 	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
 	cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80
+regdatwasm : wasm32/wasmreg.dat
+	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkwasmreg.pp
+	cd wasm32 && ..$(PATHSEP)utils$(PATHSEP)mkwasmreg$(SRCEXEEXT)
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80 regdatwasm
 intrdatx86 : x86/x86intr.dat
 		$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86inl.pp
 	cd x86 && ..$(PATHSEP)utils$(PATHSEP)mkx86inl$(SRCEXEEXT)

+ 17 - 5
compiler/Makefile.fpc

@@ -32,7 +32,7 @@ fpcdir=..
 unexport FPC_VERSION FPC_COMPILERINFO
 
 # Which platforms are ready for inclusion in the cycle
-CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
+CYCLETARGETS=i386 powerpc sparc arm x86_64 powerpc64 m68k armeb mipsel mips avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
 
 # All supported targets used for clean
 ALLTARGETS=$(CYCLETARGETS)
@@ -40,7 +40,7 @@ ALLTARGETS=$(CYCLETARGETS)
 # All OS targets that do not support native compiler
 NO_NATIVE_COMPILER_OS_LIST=amstradcpc embedded freertos gba macosclassic msdos msxdos nds palmos symbian watcom wii win16 zxspectrum
 # All CPU targets that do not support native compiler
-NO_NATIVE_COMPILER_CPU_LIST=avr i8086 jvm z80
+NO_NATIVE_COMPILER_CPU_LIST=avr i8086 jvm z80 wasm32
 
 # Don't compile a native compiler & utilities for targets
 # which do not support it
@@ -279,6 +279,9 @@ endif
 ifeq ($(CPC_TARGET),z80)
 CPUSUF=z80
 endif
+ifeq ($(CPC_TARGET),wasm32)
+CPUSUF=wasm32
+endif
 
 # Do not define the default -d$(CPU_TARGET) because that
 # will conflict with our -d$(CPC_TARGET)
@@ -410,6 +413,11 @@ ifeq ($(PPC_TARGET),riscv64)
 override LOCALOPT+=-Furiscv
 endif
 
+# WASM32 specific
+ifeq ($(PPC_TARGET),wasm32)
+override LOCALOPT+=-dNOOPT
+endif
+
 OPTWPOCOLLECT=-OWdevirtcalls,optvmts -FW$(BASEDIR)/pp1.wpo
 OPTWPOPERFORM=-Owdevirtcalls,optvmts -Fw$(BASEDIR)/pp1.wpo
 # symbol liveness WPO requires nm, smart linking and no stripping (the latter
@@ -613,8 +621,8 @@ endif
 # cpu targets
 #####################################################################
 
-PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80
-PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80
+PPC_TARGETS=i386 m68k powerpc sparc arm armeb x86_64 powerpc64 mips mipsel avr jvm i8086 aarch64 sparc64 riscv32 riscv64 xtensa z80 wasm32
+PPC_SUFFIXES=386 68k ppc sparc arm armeb x64 ppc64 mips mipsel avr jvm 8086 a64 sparc64 rv32 rv64 xtensa z80 wasm32
 INSTALL_TARGETS=$(addsuffix _exe_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 SYMLINKINSTALL_TARGETS=$(addsuffix _symlink_install,$(sort $(CYCLETARGETS) $(PPC_TARGETS)))
 
@@ -766,7 +774,11 @@ regdatz80 : z80/z80reg.dat
             $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkz80reg.pp
         cd z80 && ..$(PATHSEP)utils$(PATHSEP)mkz80reg$(SRCEXEEXT)
 
-regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80
+regdatwasm : wasm32/wasmreg.dat
+	    $(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkwasmreg.pp
+        cd wasm32 && ..$(PATHSEP)utils$(PATHSEP)mkwasmreg$(SRCEXEEXT)
+
+regdat : regdatx86 regdatarm regdatsp regdatavr regdataarch64 regdatmips regdatsp64 regdatz80 regdatwasm
 
 intrdatx86 : x86/x86intr.dat
 		$(COMPILER) -FE$(COMPILERUTILSDIR) $(COMPILERUTILSDIR)/mkx86inl.pp

+ 1 - 1
compiler/aasmcnst.pas

@@ -1165,7 +1165,7 @@ implementation
    class function ttai_typedconstbuilder.get_string_symofs(typ: tstringtype; winlikewidestring: boolean): pint;
      begin
        { darwin's linker does not support negative offsets }
-       if not(target_info.system in systems_darwin) and
+       if not(target_info.system in systems_darwin+systems_wasm) and
           { it seems that clang's assembler has a bug with the ADRP instruction... }
           (target_info.system<>system_aarch64_win64) then
          result:=0

+ 27 - 0
compiler/aasmtai.pas

@@ -90,6 +90,11 @@ interface
           ait_llvmmetadatanode, (* llvm metadata node: !id = !{type value, ...} *)
           ait_llvmmetadatareftypedconst, { reference to metadata inside a metadata constant }
           ait_llvmmetadatarefoperand, { llvm metadata referece: !metadataname !id }
+{$endif}
+{$ifdef wasm}
+          ait_importexport,
+          ait_local,
+          ait_functype,
 {$endif}
           { SEH directives used in ARM,MIPS and x86_64 COFF targets }
           ait_seh_directive,
@@ -232,6 +237,11 @@ interface
           'llvmmetadata',
           'llvmmetadatareftc',
           'llvmmetadatarefop',
+{$endif}
+{$ifdef wasm}
+          'importexport',
+          'local',
+          'functype',
 {$endif}
           'cfi',
           'seh_directive',
@@ -288,6 +298,11 @@ interface
        ,top_fenceflags
        ,top_roundingmode
 {$endif defined(riscv32) or defined(riscv64)}
+{$ifdef wasm}
+       ,top_functype
+       ,top_single
+       ,top_double
+{$endif wasm}
        );
 
       { kinds of operations that an instruction can perform on an operand }
@@ -341,6 +356,9 @@ interface
                      ait_llvmmetadatareftypedconst,
                      ait_llvmmetadatarefoperand,
 {$endif llvm}
+{$ifdef wasm}
+                     ait_importexport,ait_local,ait_functype,
+{$endif wasm}
                      ait_seh_directive,
                      ait_cfi,
                      ait_eabi_attribute
@@ -516,6 +534,11 @@ interface
             top_fenceflags : (fenceflags : TFenceFlags);
             top_roundingmode : (roundingmode : TRoundingMode);
         {$endif defined(riscv32) or defined(riscv64)}
+        {$ifdef wasm}
+            top_functype : (functype: TWasmFuncType);
+            top_single : (sval:single);
+            top_double : (dval:double);
+        {$endif wasm}
         end;
         poper=^toper;
 
@@ -2995,6 +3018,10 @@ implementation
               top_wstring:
                 donewidestring(pwstrval);
 {$endif jvm}
+{$ifdef wasm}
+              top_functype:
+                FreeAndNil(functype);
+{$endif wasm}
               else
                 ;
             end;

+ 98 - 2
compiler/aggas.pas

@@ -32,7 +32,10 @@ interface
 
     uses
       globtype,globals,
-      aasmbase,aasmtai,aasmdata,aasmcfi,
+      cpubase,aasmbase,aasmtai,aasmdata,aasmcfi,
+{$ifdef wasm}
+      aasmcpu,
+{$endif wasm}
       assemble;
 
     type
@@ -66,6 +69,9 @@ interface
         procedure WriteTree(p:TAsmList);override;
         procedure WriteAsmList;override;
         destructor destroy; override;
+{$ifdef WASM}
+        procedure WriteFuncType(functype: TWasmFuncType);
+{$endif WASM}
        private
         setcount: longint;
         procedure WriteDecodedSleb128(a: int64);
@@ -118,7 +124,7 @@ implementation
 {$ifdef m68k}
       cpuinfo,aasmcpu,
 {$endif m68k}
-      cpubase,objcasm;
+      objcasm;
 
     const
       line_length = 70;
@@ -549,6 +555,11 @@ implementation
            begin
              if (atype in [sec_stub]) then
                writer.AsmWrite('.section ');
+           end;
+         system_wasm32_wasi,
+         system_wasm32_embedded:
+           begin
+             writer.AsmWrite('.section ');
            end
          else
            begin
@@ -711,6 +722,37 @@ implementation
       end;
 
 
+{$ifdef WASM}
+    procedure TGNUAssembler.WriteFuncType(functype: TWasmFuncType);
+      var
+        wasm_basic_typ: TWasmBasicType;
+        first: boolean;
+      begin
+        writer.AsmWrite('(');
+        first:=true;
+        for wasm_basic_typ in functype.params do
+          begin
+            if first then
+              first:=false
+            else
+              writer.AsmWrite(',');
+            writer.AsmWrite(gas_wasm_basic_type_str[wasm_basic_typ]);
+          end;
+        writer.AsmWrite(') -> (');
+        first:=true;
+        for wasm_basic_typ in functype.results do
+          begin
+            if first then
+              first:=false
+            else
+              writer.AsmWrite(',');
+            writer.AsmWrite(gas_wasm_basic_type_str[wasm_basic_typ]);
+          end;
+        writer.AsmWrite(')');
+      end;
+{$endif WASM}
+
+
     procedure TGNUAssembler.WriteTree(p:TAsmList);
 
       function needsObject(hp : tai_symbol) : boolean;
@@ -798,6 +840,28 @@ implementation
             end;
         end;
 
+{$ifdef WASM}
+      procedure WriteFuncTypeDirective(hp:tai_functype);
+        begin
+          writer.AsmWrite(#9'.functype'#9);
+          writer.AsmWrite(hp.funcname);
+          writer.AsmWrite(' ');
+          WriteFuncType(hp.functype);
+          writer.AsmLn;
+        end;
+
+
+      procedure WriteImportExport(hp:tai_impexp);
+        var
+          symstypestr: string;
+        begin
+          Str(hp.symstype,symstypestr);
+          writer.AsmWriteLn(asminfo^.comment+'ait_importexport(extname='''+hp.extname+''', intname='''+hp.intname+''', extmodule='''+hp.extmodule+''', symstype='+symstypestr+')');
+          if hp.extmodule='' then
+            writer.AsmWriteLn(#9'.export_name '+hp.intname+', '+hp.extname);
+        end;
+{$endif WASM}
+
     var
       ch       : char;
       lasthp,
@@ -1377,6 +1441,10 @@ implementation
                  { the .localentry directive has to specify the size from the
                    start till here of the non-local entry code as second argument }
                  s:=', .-';
+               if ((target_info.system <> system_arm_linux) and (target_info.system <> system_arm_android)) then
+                 sepChar := '@'
+               else
+                 sepChar := '#';
                if replaceforbidden then
                  begin
                    { avoid string truncation }
@@ -1388,6 +1456,11 @@ implementation
                        writer.AsmWrite(#9'.globl ');
                        writer.AsmWriteLn(ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
                      end;
+                   if (tf_needs_symbol_type in target_info.flags) then
+                     begin
+                       writer.AsmWrite(#9'.type'#9 + ApplyAsmSymbolRestrictions(tai_symbolpair(hp).sym^));
+                       writer.AsmWriteLn(',' + sepChar + 'function');
+                     end;
                  end
                else
                  begin
@@ -1400,6 +1473,11 @@ implementation
                        writer.AsmWrite(#9'.globl ');
                        writer.AsmWriteLn(tai_symbolpair(hp).sym^);
                      end;
+                   if (tf_needs_symbol_type in target_info.flags) then
+                     begin
+                       writer.AsmWrite(#9'.type'#9 + tai_symbolpair(hp).sym^);
+                       writer.AsmWriteLn(',' + sepChar + 'function');
+                     end;
                  end;
              end;
            ait_symbol_end :
@@ -1548,6 +1626,24 @@ implementation
                end;
                writer.AsmLn;
              end;
+
+{$ifdef WASM}
+           ait_local:
+             begin
+               if tai_local(hp).first then
+                 writer.AsmWrite(#9'.local'#9)
+               else
+                 writer.AsmWrite(', ');
+               writer.AsmWrite(gas_wasm_basic_type_str[tai_local(hp).bastyp]);
+               if tai_local(hp).last then
+                 writer.AsmLn;
+             end;
+           ait_functype:
+             WriteFuncTypeDirective(tai_functype(hp));
+           ait_importexport:
+             WriteImportExport(tai_impexp(hp));
+{$endif WASM}
+
            else
              if not WriteComments(hp) then
                internalerror(2006012201);

+ 4 - 0
compiler/compinnr.pas

@@ -202,6 +202,10 @@ type
 {$if defined(Z80)}
      ,
      {$i ccpuinnr.inc}
+{$endif}
+{$if defined(WASM32)}
+     ,
+     {$i ccpuinnr.inc}
 {$endif}
    );
 

+ 57 - 38
compiler/dbgdwarf.pas

@@ -683,7 +683,10 @@ implementation
         DW_OP_HP_unknown := $e0,
         DW_OP_HP_is_value := $e1,DW_OP_HP_fltconst4 := $e2,
         DW_OP_HP_fltconst8 := $e3,DW_OP_HP_mod_range := $e4,
-        DW_OP_HP_unmod_range := $e5,DW_OP_HP_tls := $e6
+        DW_OP_HP_unmod_range := $e5,DW_OP_HP_tls := $e6,
+
+        { WebAssembly extensions. }
+        DW_OP_WASM_location = $ed
         );
 {$pop}
 
@@ -1055,12 +1058,14 @@ implementation
 
     function TDebugInfoDwarf.is_fbreg(reg: tregister): boolean;
       begin
-{$ifdef i8086}
+{$if defined(i8086)}
         result:=reg=NR_BP;
-{$else i8086}
+{$elseif defined(wasm)}
+        result:=reg=NR_LOCAL_FRAME_POINTER_REG;
+{$else}
         { always return false, because we don't emit DW_AT_frame_base attributes yet }
         result:=false;
-{$endif i8086}
+{$endif}
       end;
 
     function TDebugInfoDwarf.def_dwarf_lab(def: tdef): tasmsymbol;
@@ -2243,6 +2248,9 @@ implementation
       var
         labsym : tasmsymbol;
       begin
+        { end of the symbol }
+        labsym:=def_dwarf_lab(def);
+        current_asmdata.asmlists[al_dwarf_info].concat(tai_symbol_end.Create(labsym));
         { create a derived reference type for pass-by-reference parameters }
         { (gdb doesn't support DW_AT_variable_parameter yet)               }
         labsym:=def_dwarf_ref_lab(def);
@@ -3252,30 +3260,33 @@ implementation
         flist : TFPList;
         dbgname : String;
       begin
-        { insert DEBUGSTART and DEBUGEND labels }
-        dbgname:=make_mangledname('DEBUGSTART',current_module.localsymtable,'');
-        { Darwin's linker does not like two global labels both pointing to the
-          end of a section, which can happen in case of units without code ->
-          make them local; we don't need the debugtable stuff there either,
-          so it doesn't matter that they are not global.
-        }
-        if (target_info.system in systems_darwin) then
-          dbgname:='L'+dbgname;
-        new_section(current_asmdata.asmlists[al_start],sec_code,dbgname,0,secorder_begin);
-        if not(target_info.system in systems_darwin) then
-          current_asmdata.asmlists[al_start].concat(tai_symbol.Createname_global(dbgname,AT_METADATA,0,voidpointertype))
-        else
-          current_asmdata.asmlists[al_start].concat(tai_symbol.Createname(dbgname,AT_METADATA,0,voidpointertype));
+        if not (target_info.system in systems_wasm) then
+          begin
+            { insert DEBUGSTART and DEBUGEND labels }
+            dbgname:=make_mangledname('DEBUGSTART',current_module.localsymtable,'');
+            { Darwin's linker does not like two global labels both pointing to the
+              end of a section, which can happen in case of units without code ->
+              make them local; we don't need the debugtable stuff there either,
+              so it doesn't matter that they are not global.
+            }
+            if (target_info.system in systems_darwin) then
+              dbgname:='L'+dbgname;
+            new_section(current_asmdata.asmlists[al_start],sec_code,dbgname,0,secorder_begin);
+            if not(target_info.system in systems_darwin) then
+              current_asmdata.asmlists[al_start].concat(tai_symbol.Createname_global(dbgname,AT_METADATA,0,voidpointertype))
+            else
+              current_asmdata.asmlists[al_start].concat(tai_symbol.Createname(dbgname,AT_METADATA,0,voidpointertype));
 
-        dbgname:=make_mangledname('DEBUGEND',current_module.localsymtable,'');
-        { See above. }
-        if (target_info.system in systems_darwin) then
-          dbgname:='L'+dbgname;
-        new_section(current_asmdata.asmlists[al_end],sec_code,dbgname,0,secorder_end);
-        if not(target_info.system in systems_darwin) then
-          current_asmdata.asmlists[al_end].concat(tai_symbol.Createname_global(dbgname,AT_METADATA,0,voidpointertype))
-        else
-          current_asmdata.asmlists[al_end].concat(tai_symbol.Createname(dbgname,AT_METADATA,0,voidpointertype));
+            dbgname:=make_mangledname('DEBUGEND',current_module.localsymtable,'');
+            { See above. }
+            if (target_info.system in systems_darwin) then
+              dbgname:='L'+dbgname;
+            new_section(current_asmdata.asmlists[al_end],sec_code,dbgname,0,secorder_end);
+            if not(target_info.system in systems_darwin) then
+              current_asmdata.asmlists[al_end].concat(tai_symbol.Createname_global(dbgname,AT_METADATA,0,voidpointertype))
+            else
+              current_asmdata.asmlists[al_end].concat(tai_symbol.Createname(dbgname,AT_METADATA,0,voidpointertype));
+          end;
 
         { insert .Ldebug_abbrev0 label }
         templist:=TAsmList.create;
@@ -3570,19 +3581,27 @@ implementation
         if (m_objectivec1 in current_settings.modeswitches) then
           append_attribute(DW_AT_APPLE_major_runtime_vers,DW_FORM_data1,[1]);
 
-        dbgname:=make_mangledname('DEBUGSTART',current_module.localsymtable,'');
-        if (target_info.system in systems_darwin) then
+        if target_info.system in systems_wasm then
           begin
-            bind:=AB_LOCAL;
-            dbgname:='L'+dbgname;
+            append_attribute(DW_AT_low_pc,DW_FORM_data4,[0]);
+            { todo: append DW_AT_ranges }
           end
         else
-          bind:=AB_GLOBAL;
-        append_labelentry(DW_AT_low_pc,current_asmdata.DefineAsmSymbol(dbgname,bind,AT_METADATA,voidpointertype));
-        dbgname:=make_mangledname('DEBUGEND',current_module.localsymtable,'');
-        if (target_info.system in systems_darwin) then
-          dbgname:='L'+dbgname;
-        append_labelentry(DW_AT_high_pc,current_asmdata.DefineAsmSymbol(dbgname,bind,AT_METADATA,voidpointertype));
+          begin
+            dbgname:=make_mangledname('DEBUGSTART',current_module.localsymtable,'');
+            if (target_info.system in systems_darwin) then
+              begin
+                bind:=AB_LOCAL;
+                dbgname:='L'+dbgname;
+              end
+            else
+              bind:=AB_GLOBAL;
+            append_labelentry(DW_AT_low_pc,current_asmdata.DefineAsmSymbol(dbgname,bind,AT_METADATA,voidpointertype));
+            dbgname:=make_mangledname('DEBUGEND',current_module.localsymtable,'');
+            if (target_info.system in systems_darwin) then
+              dbgname:='L'+dbgname;
+            append_labelentry(DW_AT_high_pc,current_asmdata.DefineAsmSymbol(dbgname,bind,AT_METADATA,voidpointertype));
+          end;
 
         finish_entry;
 
@@ -3666,7 +3685,7 @@ implementation
       begin
         { Reference all DEBUGINFO sections from the main .fpc section }
         { to prevent eliminating them by smartlinking                 }
-        if (target_info.system in ([system_powerpc_macosclassic]+systems_darwin)) then
+        if (target_info.system in ([system_powerpc_macosclassic]+systems_darwin+systems_wasm)) then
           exit;
         new_section(list,sec_fpc,'links',0);
 

+ 2 - 2
compiler/entfile.pas

@@ -156,7 +156,7 @@ const
     { 14 } 32 {'jvm'},
     { 15 } 16 {'i8086'},
     { 16 } 64 {'aarch64'},
-    { 17 } 32 {'wasm'},
+    { 17 } 32 {'wasm32'},
     { 18 } 64 {'sparc64'},
     { 19 } 32 {'riscv32'},
     { 20 } 64 {'riscv64'},
@@ -182,7 +182,7 @@ const
     { 14 } 64 {'jvm'},
     { 15 } 16 {'i8086'},
     { 16 } 64 {'aarch64'},
-    { 17 } 64 {'wasm'},
+    { 17 } 64 {'wasm32'},
     { 18 } 64 {'sparc64'},
     { 19 } 32 {'riscv32'},
     { 20 } 64 {'riscv64'},

+ 11 - 0
compiler/fpcdefs.inc

@@ -398,3 +398,14 @@
   {$define cpucg64shiftsupport}
   {$define symansistr}
 {$endif}
+
+{$ifdef wasm32}
+  {$define wasm}
+  {$define cpu32bit}
+  {$define cpu64bitalu}
+  {$define cpu32bitaddr}
+  {$define cpuhighleveltarget}
+  {$define symansistr}
+  {$define SUPPORT_GET_FRAME}
+{$endif}
+

+ 6 - 0
compiler/globals.pas

@@ -589,6 +589,12 @@ interface
         asmcputype : cpu_none;
         fputype : fpu_soft;
   {$endif z80}
+  {$ifdef wasm}
+        cputype : cpu_none;
+        optimizecputype : cpu_none;
+        asmcputype : cpu_none;
+        fputype : fpu_standard;
+  {$endif wasm}
 {$endif not GENERIC_CPU}
         asmmode : asmmode_standard;
 {$ifndef jvm}

+ 1 - 1
compiler/hlcgobj.pas

@@ -4677,7 +4677,7 @@ implementation
             they can be interpreted as all different starting symbols of
             subsections and be reordered }
           if (item<>firstitem) and
-             (target_info.system in systems_darwin) then
+             (target_info.system in (systems_darwin+systems_wasm)) then
             begin
               { the .set already defines the symbol, so can't emit a tai_symbol as that will redefine it }
               if global then

+ 7 - 0
compiler/i8086/n8086mem.pas

@@ -48,6 +48,7 @@ interface
        { tx86vecnode doesn't work for i8086, so we inherit tcgvecnode }
        ti8086vecnode = class(tcgvecnode)
         protected
+         function get_address_type: tdef;override;
          function first_arraydef: tnode;override;
          procedure update_reference_reg_mul(maybe_const_reg: tregister; regsize: tdef; l: aint);override;
        end;
@@ -186,6 +187,12 @@ implementation
                              TI8086VECNODE
 *****************************************************************************}
 
+    function ti8086vecnode.get_address_type: tdef;
+      begin
+        result:=tx86pointerdef(cpointerdef).getreusablex86(resultdef,x86pt_near);
+      end;
+
+
     function ti8086vecnode.first_arraydef: tnode;
       var
         arraydef: tcpuarraydef;

+ 3 - 0
compiler/msg/errore.msg

@@ -4233,6 +4233,9 @@ x*2Tlinux_Linux
 Z*2Tembedded_Embedded
 Z*2Tzxspectrum_ZX Spectrum
 Z*2Tmsxdos_MSX-DOS
+# wasm32 targets
+W*2Tembedded_Embedded
+W*2Twasi_The WebAssembly System Interface (WASI)
 # end of targets section
 **1u<x>_Undefines the symbol <x>
 **1U_Unit options:

+ 1 - 1
compiler/msgidx.inc

@@ -1139,7 +1139,7 @@ const
   option_info=11024;
   option_help_pages=11025;
 
-  MsgTxtSize = 87216;
+  MsgTxtSize = 87287;
 
   MsgIdxMax : array[1..20] of longint=(
     28,107,361,131,99,63,146,36,223,68,

+ 74 - 70
compiler/msgtxt.inc

@@ -1861,157 +1861,161 @@ const msgtxt : array[0..000363,1..240] of char=(
   'Z*2Tembedded_Embedded'#010+
   'Z*2Tzxspectrum_ZX Spectrum'#010+
   'Z*2Tmsxdos_MSX-DOS'#010+
-  '**1u<x>_','Undefines the symbol <x>'#010+
+  'W*2Tembe','dded_Embedded'#010+
+  'W*2Twasi_The WebAssembly System Interface (WASI)'#010+
+  '**1u<x>_Undefines the symbol <x>'#010+
   '**1U_Unit options:'#010+
   '**2Un_Do not check where the unit name matches the file name'#010+
-  '**2Ur_Generate release unit files (never automatically recompiled)'#010+
+  '**2Ur_Generate release unit files (never automatically recompile','d)'#010+
   '**2Us_Compile a system unit'#010+
-  '**1v<x>_Be verbose. <x> is a combination',' of the following letters:'#010+
+  '**1v<x>_Be verbose. <x> is a combination of the following letters:'#010+
   '**2*_e : Show errors (default)       0 : Show nothing (except errors)'#010+
   '**2*_w : Show warnings               u : Show unit info'#010+
-  '**2*_n : Show notes                  t : Show tried/used files'#010+
-  '**2*_h : Show hints     ','             c : Show conditionals'#010+
+  '**2*_n : Show no','tes                  t : Show tried/used files'#010+
+  '**2*_h : Show hints                  c : Show conditionals'#010+
   '**2*_i : Show general info           d : Show debug info'#010+
   '**2*_l : Show linenumbers            r : Rhide/GCC compatibility mode'#010+
-  '**2*_s : Show time stamps            q : Show message numbers'#010+
-  '**2*_a : Show ev','erything             x : Show info about invoked too'+
-  'ls'#010+
+  '**2*_s ',': Show time stamps            q : Show message numbers'#010+
+  '**2*_a : Show everything             x : Show info about invoked tools'+
+  #010+
   '**2*_b : Write file names messages   p : Write tree.log with parse tre'+
   'e'#010+
-  '**2*_    with full path              v : Write fpcdebug.txt with'#010+
-  '**2*_z : Write output to stderr          lots of',' debugging info'#010+
+  '**2*_    with full path              v : W','rite fpcdebug.txt with'#010+
+  '**2*_z : Write output to stderr          lots of debugging info'#010+
   '**2*_m<x>,<y> : Do not show messages numbered <x> and <y>'#010+
   'F*1V<x>_Append '#039'-<x>'#039' to the used compiler binary name (e.g. f'+
   'or version)'#010+
-  '**1W<x>_Target-specific options (targets)'#010+
+  '**1W<x>_Target-specif','ic options (targets)'#010+
   '3*2WA_Specify native type application (Windows)'#010+
-  '4*','2WA_Specify native type application (Windows)'#010+
+  '4*2WA_Specify native type application (Windows)'#010+
   'A*2WA_Specify native type application (Windows)'#010+
   '3*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'P*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  'p*2Wb_Create a bundle instead of a library',' (Darwin)'#010+
+  'P*2Wb_Create a bundle i','nstead of a library (Darwin)'#010+
+  'p*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'a*2Wb_Create a bundle instead of a library (Darwin)'#010+
   'A*2Wb_Create a bundle instead of a library (Darwin)'#010+
   '4*2Wb_Create a bundle instead of a library (Darwin)'#010+
-  '3*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  '3*2WB<x>_Set image bas','e to <x> (Windows, Symbian)'#010+
+  '3*2','WB_Create a relocatable image (Windows, Symbian)'#010+
+  '3*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
   '4*2WB_Create a relocatable image (Windows)'#010+
   '4*2WB<x>_Set image base to <x> (Windows)'#010+
   'A*2WB_Create a relocatable image (Windows, Symbian)'#010+
-  'A*2WB<x>_Set image base to <x> (Windows, Symbian)'#010+
-  'Z*2WB<x>_Set image base to',' <x> (ZX Spectrum)'#010+
+  'A*2WB','<x>_Set image base to <x> (Windows, Symbian)'#010+
+  'Z*2WB<x>_Set image base to <x> (ZX Spectrum)'#010+
   '3*2WC_Specify console type application (EMX, OS/2, Windows)'#010+
   '4*2WC_Specify console type application (Windows)'#010+
-  'A*2WC_Specify console type application (Windows)'#010+
+  'A*2WC_Specify console type application (W','indows)'#010+
   'P*2WC_Specify console type application (Classic Mac OS)'#010+
-  '3*2WD_U','se DEFFILE to export functions of DLL or EXE (Windows)'#010+
+  '3*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
   '4*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
-  'A*2WD_Use DEFFILE to export functions of DLL or EXE (Windows)'#010+
+  'A*2WD_Use DEFFILE to export functions of DLL or EXE ','(Windows)'#010+
   '3*2We_Use external resources (Darwin)'#010+
-  '4*2We_Use external reso','urces (Darwin)'#010+
+  '4*2We_Use external resources (Darwin)'#010+
   'a*2We_Use external resources (Darwin)'#010+
   'A*2We_Use external resources (Darwin)'#010+
   'P*2We_Use external resources (Darwin)'#010+
   'p*2We_Use external resources (Darwin)'#010+
-  '3*2WF_Specify full-screen type application (EMX, OS/2)'#010+
-  '3*2WG_Specify grap','hic type application (EMX, OS/2, Windows)'#010+
+  '3*','2WF_Specify full-screen type application (EMX, OS/2)'#010+
+  '3*2WG_Specify graphic type application (EMX, OS/2, Windows)'#010+
   '4*2WG_Specify graphic type application (Windows)'#010+
   'A*2WG_Specify graphic type application (Windows)'#010+
-  'P*2WG_Specify graphic type application (Classic Mac OS)'#010+
+  'P*2WG_Specify graphic type ap','plication (Classic Mac OS)'#010+
   '3*2Wi_Use internal resources (Darwin)'#010+
-  '4*2Wi_','Use internal resources (Darwin)'#010+
+  '4*2Wi_Use internal resources (Darwin)'#010+
   'a*2Wi_Use internal resources (Darwin)'#010+
   'A*2Wi_Use internal resources (Darwin)'#010+
   'P*2Wi_Use internal resources (Darwin)'#010+
-  'p*2Wi_Use internal resources (Darwin)'#010+
-  '3*2WI_Turn on/off the usage of import sections (Windows)',#010+
+  'p*2Wi_Use internal reso','urces (Darwin)'#010+
+  '3*2WI_Turn on/off the usage of import sections (Windows)'#010+
   '4*2WI_Turn on/off the usage of import sections (Windows)'#010+
   'A*2WI_Turn on/off the usage of import sections (Windows)'#010+
-  '8*2Wh_Use huge code for units (ignored for models with CODE in a uniqu'+
-  'e segment)'#010+
+  '8*2Wh_Use huge code for units (ignored for models with',' CODE in a uni'+
+  'que segment)'#010+
   '8*2Wm<x>_Set memory model'#010+
-  '8*3WmTiny_Tiny mem','ory model'#010+
+  '8*3WmTiny_Tiny memory model'#010+
   '8*3WmSmall_Small memory model (default)'#010+
   '8*3WmMedium_Medium memory model'#010+
   '8*3WmCompact_Compact memory model'#010+
   '8*3WmLarge_Large memory model'#010+
-  '8*3WmHuge_Huge memory model'#010+
-  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (D','ar'+
-  'win)'#010+
+  '8*3WmHuge_Huge memory m','odel'#010+
+  '3*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
+  'n)'#010+
   '4*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
   'p*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
   'n)'#010+
-  'P*2WM<x>_Minimum Mac OS X deployment version: 10.4, 10.5.1, ... (Darwi'+
-  'n)'#010+
-  '3*2WN_Do not g','enerate relocation code, needed for debugging (Windows'+
-  ')'#010+
+  'P*2WM<x>_Minimum',' Mac OS X deployment version: 10.4, 10.5.1, ... (Dar'+
+  'win)'#010+
+  '3*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
   '4*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2WN_Do not generate relocation code, needed for debugging (Windows)'#010+
-  'A*2Wp<x>_Specify the controller type; see fp','c -i or fpc -iu for poss'+
-  'ible values'#010+
-  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'A*2WN_Do not generate relocation code, need','ed for debugging (Windows'+
+  ')'#010+
+  'A*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  'R*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'm*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  'V*2Wp<x>_Specify the controller type; see fp','c -i or fpc -iu for poss'+
+  'R*2Wp<x>_Specify the controller type; see fpc -i or f','pc -iu for poss'+
   'ible values'#010+
+  'V*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
+  'le values'#010+
   'x*2Wp<x>_Specify the controller type; see fpc -i or fpc -iu for possib'+
   'le values'#010+
-  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (iphonesim)'#010+
-  '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ..','. (iphonesim)'+
+  '3*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ','... (iphonesim)'+
   #010+
+  '4*2WP<x>_Minimum iOS deployment version: 8.0, 8.0.2, ... (iphonesim)'#010+
   'a*2WP<x>_Minimum iOS deployment version: 7.0, 7.1.2, ... (Darwin)'#010+
   'A*2WP<x>_Minimum iOS deployment version: 3.0, 5.0.1, ... (Darwin)'#010+
-  '3*2WR_Generate relocation code (Windows)'#010+
+  '3*2WR_Generate relocati','on code (Windows)'#010+
   '4*2WR_Generate relocation code (Windows)'#010+
-  'A*2WR_Genera','te relocation code (Windows)'#010+
+  'A*2WR_Generate relocation code (Windows)'#010+
   '8*2Wt<x>_Set the target executable format'#010+
   '8*3Wtexe_Create a DOS .EXE file (default)'#010+
-  '8*3Wtcom_Create a DOS .COM file (requires tiny memory model)'#010+
+  '8*3Wtcom_Create a DOS .COM file (requires tiny memory mo','del)'#010+
   'P*2WT_Specify MPW tool type application (Classic Mac OS)'#010+
-  '6*2WQ<x>_','Set executable metadata format (Sinclair QL)'#010+
+  '6*2WQ<x>_Set executable metadata format (Sinclair QL)'#010+
   '6*3WQqhdr_Set metadata to QDOS File Header style (default)'#010+
   '6*3WQxtcc_Set metadata to XTcc style'#010+
-  '**2WX_Enable executable stack (Linux)'#010+
+  '**2WX_Enable executable stac','k (Linux)'#010+
   '**1X_Executable options:'#010+
-  '**2X9_Generate linkerscript for GNU ','Binutils ld older than version 2'+
-  '.19.1 (Linux)'#010+
+  '**2X9_Generate linkerscript for GNU Binutils ld older than version 2.1'+
+  '9.1 (Linux)'#010+
   '**2Xa_Generate code which allows to use more than 2 GB static data on '+
   '64 Bit targets (Linux)'#010+
-  '**2Xc_Pass --shared/-dynamic to the linker (BeOS, Darwin, FreeBSD, Lin'+
-  'ux)'#010+
-  '**2Xd_Do not search default',' library path (sometimes required for cro'+
-  'ss-compiling when not using -XR)'#010+
+  '**2Xc_Pass --shared/-dynamic t','o the linker (BeOS, Darwin, FreeBSD, L'+
+  'inux)'#010+
+  '**2Xd_Do not search default library path (sometimes required for cross'+
+  '-compiling when not using -XR)'#010+
   '**2Xe_Use external linker'#010+
   '**2Xf_Substitute pthread library name for linking (BSD)'#010+
-  '**2Xg_Create debuginfo in a separate file and add a debuglink section '+
-  'to executable'#010,
+  '**2Xg_Create ','debuginfo in a separate file and add a debuglink sectio'+
+  'n to executable'#010+
   '**2XD_Try to link units dynamically      (defines FPC_LINK_DYNAMIC)'#010+
   '**2Xi_Use internal linker'#010+
   'L*2XlS<x>_LLVM utilties suffix (e.g. -7 in case clang is called clang-'+
   '7)'#010+
-  '**2XLA_Define library substitutions for linking'#010+
-  '**2XLO_Define order of li','brary linking'#010+
+  '**','2XLA_Define library substitutions for linking'#010+
+  '**2XLO_Define order of library linking'#010+
   '**2XLD_Exclude default order of standard libraries'#010+
   '**2Xm_Generate link map'#010+
   '**2XM<x>_Set the name of the '#039'main'#039' program routine (default i'+
   's '#039'main'#039')'#010+
-  '**2Xn_Use target system native linker instead of GNU ld (Solaris, AIX)'+
-  #010+
-  'F*2Xp<x>','_First search for the compiler binary in the directory <x>'#010+
+  '**2Xn_Us','e target system native linker instead of GNU ld (Solaris, AI'+
+  'X)'#010+
+  'F*2Xp<x>_First search for the compiler binary in the directory <x>'#010+
   '**2XP<x>_Prepend the binutils names with the prefix <x>'#010+
-  '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed for cross comp'+
-  'ile, see the ld manual for more information) (BeOS, Linux)'#010,
+  '**2Xr<x>_Set the linker'#039's rlink-path to <x> (needed fo','r cross co'+
+  'mpile, see the ld manual for more information) (BeOS, Linux)'#010+
   '**2XR<x>_Prepend <x> to all linker search paths (BeOS, Darwin, FreeBSD'+
   ', Linux, Mac OS, Solaris)'#010+
   '**2Xs_Strip all symbols from executable'#010+
-  '**2XS_Try to link units statically (default, defines FPC_LINK_STATIC)'#010+
-  '**2Xt_Link with static libraries (','-static is passed to linker)'#010+
+  '**2XS_Try to link units staticall','y (default, defines FPC_LINK_STATIC'+
+  ')'#010+
+  '**2Xt_Link with static libraries (-static is passed to linker)'#010+
   '**2Xu_Generate executable in UF2 format  (embedded targets only)'#010+
   '**2Xv_Generate table for Virtual Entry calls'#010+
-  '**2XV_Use VLink as external linker       (default on Amiga, MorphOS)'#010+
-  '**2XX_Try to smartlink units    ','         (defines FPC_LINK_SMART)'#010+
+  '**2XV_Use VLink as external li','nker       (default on Amiga, MorphOS)'+
+  #010+
+  '**2XX_Try to smartlink units             (defines FPC_LINK_SMART)'#010+
   '**1*_'#010+
   '**1?_Show this help'#010+
   '**1h_Shows this help without waiting'

+ 1 - 1
compiler/ncal.pas

@@ -4252,7 +4252,7 @@ implementation
                                  hp.parasym.paraloc[callerside].location^.reference.offset)) or
                                (paramanager.use_fixed_stack and
                                 (node_complexity(hpcurr.left)<node_complexity(hp.left))) then
-{$elseif defined(jvm)}
+{$elseif defined(jvm) or defined(wasm)}
                             if (hpcurr.parasym.paraloc[callerside].location^.reference.offset<hp.parasym.paraloc[callerside].location^.reference.offset) then
 {$else jvm}
                             if (node_complexity(hpcurr.left)<node_complexity(hp.left)) then

+ 11 - 6
compiler/ncgflw.pas

@@ -24,6 +24,11 @@ unit ncgflw;
 
 {$i fpcdefs.inc}
 
+{$if defined(jvm) or defined(wasm)}
+  {$define SkipABIEH}
+{$endif}
+
+
 interface
 
     uses
@@ -75,9 +80,9 @@ interface
 
        tcgraisenode = class(traisenode)
          function pass_1: tnode;override;
-{$ifndef jvm}
+{$ifndef SkipABIEH}
          procedure pass_generate_code;override;
-{$endif jvm}
+{$endif SkipABIEH}
        end;
 
        tcgtryexceptnode = class(ttryexceptnode)
@@ -115,9 +120,9 @@ implementation
       cpubase,
       tgobj,paramgr,
       cgobj,hlcgobj,nutils
-{$ifndef jvm}
+{$ifndef SkipABIEH}
       ,psabiehpi
-{$endif jvm}
+{$endif}
       ;
 {*****************************************************************************
                          Second_While_RepeatN
@@ -1123,7 +1128,7 @@ implementation
           end;
       end;
 
-{$ifndef jvm}
+{$ifndef SkipABIEH}
     { has to be factored out as well }
     procedure tcgraisenode.pass_generate_code;
       var
@@ -1170,7 +1175,7 @@ implementation
             include(flowcontrol,fc_catching_exceptions);
           end;
       end;
-{$endif jvm}
+{$endif SkipABIEH}
 
 
 begin

+ 21 - 12
compiler/ncgmem.pas

@@ -61,6 +61,7 @@ interface
          procedure rangecheck_array;
          procedure rangecheck_string;
        protected
+         function get_address_type: tdef;virtual;
          {# This routine is used to calculate the address of the reference.
             On entry reg contains the index in the array,
            and l contains the size of each element in the array.
@@ -624,6 +625,12 @@ implementation
        end;
 
 
+     function tcgvecnode.get_address_type: tdef;
+       begin
+         result:=cpointerdef.getreusable(resultdef);
+       end;
+
+
      { this routine must, like any other routine, not change the contents }
      { of base/index registers of references, as these may be regvars.    }
      { The register allocator can coalesce one LOC_REGISTER being moved   }
@@ -636,10 +643,11 @@ implementation
        var
          hreg: tregister;
        begin
+         hlcg.g_ptrtypecast_reg(current_asmdata.CurrAsmList,regsize,get_address_type,maybe_const_reg);
          if l<>1 then
            begin
-             hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
-             cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,maybe_const_reg,hreg);
+             hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,get_address_type);
+             hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_IMUL,get_address_type,l,maybe_const_reg,hreg);
              maybe_const_reg:=hreg;
            end;
          if location.reference.base=NR_NO then
@@ -648,8 +656,8 @@ implementation
            location.reference.index:=maybe_const_reg
          else
           begin
-            hreg:=cg.getaddressregister(current_asmdata.CurrAsmList);
-            cg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,location.reference,hreg);
+            hreg:=hlcg.getaddressregister(current_asmdata.CurrAsmList,get_address_type);
+            hlcg.a_loadaddr_ref_reg(current_asmdata.CurrAsmList,resultdef,get_address_type,location.reference,hreg);
             reference_reset_base(location.reference,hreg,0,location.reference.temppos,location.reference.alignment,location.reference.volatility);
             { insert new index register }
             location.reference.index:=maybe_const_reg;
@@ -685,25 +693,26 @@ implementation
            end;
          if (l > 8*sizeof(aint)) then
            internalerror(200608051);
+         hlcg.g_ptrtypecast_reg(current_asmdata.CurrAsmList,regsize,get_address_type,maybe_const_reg);
          sref.ref := location.reference;
-         hreg := cg.getaddressregister(current_asmdata.CurrAsmList);
-         cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,OS_ADDR,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
-         cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,OS_ADDR,l,hreg);
+         hreg := hlcg.getaddressregister(current_asmdata.CurrAsmList,get_address_type);
+         hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SUB,get_address_type,tarraydef(left.resultdef).lowrange,maybe_const_reg,hreg);
+         hlcg.a_op_const_reg(current_asmdata.CurrAsmList,OP_IMUL,get_address_type,l,hreg);
          { keep alignment for index }
          sref.ref.alignment := left.resultdef.alignment;
          if not ispowerof2(packedbitsloadsize(l),temp) then
            internalerror(2006081201);
          alignpower:=temp;
-         offsetreg := cg.getaddressregister(current_asmdata.CurrAsmList);
-         cg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,OS_ADDR,3+alignpower,hreg,offsetreg);
-         cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,OS_ADDR,alignpower,offsetreg);
+         offsetreg := hlcg.getaddressregister(current_asmdata.CurrAsmList,get_address_type);
+         hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_SHR,get_address_type,3+alignpower,hreg,offsetreg);
+         hlcg.a_op_const_reg(current_asmdata.CurrAsmList,OP_SHL,get_address_type,alignpower,offsetreg);
          if (sref.ref.base = NR_NO) then
            sref.ref.base := offsetreg
          else if (sref.ref.index = NR_NO) then
            sref.ref.index := offsetreg
          else
            begin
-             cg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,OS_ADDR,sref.ref.base,offsetreg);
+             hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_ADD,get_address_type,sref.ref.base,offsetreg);
              sref.ref.base := offsetreg;
            end;
 
@@ -721,7 +730,7 @@ implementation
            sref.bitindexreg:=hreg;
 {$pop}
 
-         cg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,OS_INT,(1 shl (3+alignpower))-1,sref.bitindexreg);
+         hlcg.a_op_const_reg(current_asmdata.CurrAsmList,OP_AND,ossinttype,(1 shl (3+alignpower))-1,sref.bitindexreg);
          sref.startbit := 0;
          sref.bitlen := resultdef.packedbitsize;
          if (left.location.loc = LOC_REFERENCE) then

+ 24 - 1
compiler/ncgset.pas

@@ -96,6 +96,9 @@ implementation
       symconst,symdef,symsym,defutil,
       pass_2,tgobj,
       nbas,ncon,ncgflw,
+{$ifdef WASM}
+      hlcgcpu,aasmcpu,
+{$endif WASM}
       ncgutil,hlcgobj;
 
 
@@ -491,6 +494,18 @@ implementation
                          ((tenumdef(left.resultdef).min < aint(tsetdef(right.resultdef).setbase)) or
                           (tenumdef(left.resultdef).max > aint(tsetdef(right.resultdef).setmax)))) then
                        begin
+{$ifdef WASM}
+                         needslabel := True;
+
+                         thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList, opdef, OC_A, tsetdef(right.resultdef).setmax-tsetdef(right.resultdef).setbase, pleftreg);
+
+                         current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
+                         thlcgwasm(hlcg).incblock;
+                         thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+                         hlcg.a_load_const_reg(current_asmdata.CurrAsmList, uopdef, 0, location.register);
+                         current_asmdata.CurrAsmList.concat(taicpu.op_none(a_else));
+{$else WASM}
                          current_asmdata.getjumplabel(l);
                          current_asmdata.getjumplabel(l2);
                          needslabel := True;
@@ -501,13 +516,21 @@ implementation
                          hlcg.a_jmp_always(current_asmdata.CurrAsmList, l2);
 
                          hlcg.a_label(current_asmdata.CurrAsmList, l);
+{$endif WASM}
                        end;
 
                      hlcg.a_bit_test_reg_loc_reg(current_asmdata.CurrAsmList,opdef,right.resultdef,uopdef,
                        pleftreg,right.location,location.register);
 
                      if needslabel then
-                       hlcg.a_label(current_asmdata.CurrAsmList, l2);
+                       begin
+{$ifdef WASM}
+                         current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
+                         thlcgwasm(hlcg).decblock;
+{$else WASM}
+                         hlcg.a_label(current_asmdata.CurrAsmList, l2);
+{$endif WASM}
+                       end
                    end;
 {$ifndef cpuhighleveltarget}
                  location.size := def_cgsize(resultdef);

+ 3 - 0
compiler/nset.pas

@@ -61,6 +61,9 @@ interface
        tcaseblock = record
           { label (only used in pass_generate_code) }
           blocklabel : tasmlabel;
+{$ifdef WASM}
+          BlockBr : Integer;
+{$endif WASM}
 
           { shortcut - set to true if blocklabel isn't actually unique to the
             case block due to one of the following conditions:

+ 11 - 0
compiler/options.pas

@@ -916,6 +916,9 @@ begin
 {$endif}
 {$ifdef z80}
       'Z',
+{$endif}
+{$ifdef wasm32}
+      'W',
 {$endif}
       '*' : show:=true;
      end;
@@ -4027,6 +4030,14 @@ procedure read_arguments(cmd:TCmdStr);
         def_system_macro('FPC_COMP_IS_INT64');
       {$endif z80}
 
+      {$ifdef wasm32}
+        def_system_macro('CPUWASM');
+        def_system_macro('CPUWASM32');
+        def_system_macro('CPU32');
+        def_system_macro('FPC_CURRENCY_IS_INT64');
+        def_system_macro('FPC_COMP_IS_INT64');
+      {$endif wasm32}
+
       {$if defined(cpu8bitalu)}
         def_system_macro('CPUINT8');
       {$elseif defined(cpu16bitalu)}

+ 10 - 1
compiler/pdecsub.pas

@@ -2429,7 +2429,7 @@ type
    end;
 const
   {Should contain the number of procedure directives we support.}
-  num_proc_directives=53;
+  num_proc_directives=54;
   proc_direcdata:array[1..num_proc_directives] of proc_dir_rec=
    (
     (
@@ -2495,6 +2495,15 @@ const
       mutexclpocall : [];
       mutexclpotype : [potype_constructor,potype_destructor,potype_class_constructor,potype_class_destructor];
       mutexclpo     : [po_assembler,po_external]
+    ),(
+      idtok:_DISCARDRESULT;
+      pd_flags : [pd_interface,pd_implemen,pd_body,pd_procvar];
+      handler  : nil;
+      pocall   : pocall_none;
+      pooption : [po_discardresult];
+      mutexclpocall : [];
+      mutexclpotype : [potype_function,potype_constructor,potype_destructor,potype_class_constructor,potype_class_destructor];
+      mutexclpo     : []
     ),(
       idtok:_DISPID;
       pd_flags : [pd_dispinterface];

+ 8 - 0
compiler/pp.pas

@@ -41,6 +41,7 @@ program pp;
   RISCV64             generate a compiler for the RiscV64 architecture
   SPARC               generate a compiler for SPARC
   SPARC64             generate a compiler for SPARC64
+  WASM32              generate a compiler for WebAssembly 32-bit
   X86_64              generate a compiler for the AMD x86-64 architecture
   XTENSA              generate a compiler for XTENSA
   Z80                 generate a compiler for Z80
@@ -194,6 +195,13 @@ program pp;
   {$endif CPUDEFINED}
   {$define CPUDEFINED}
 {$endif Z80}
+{$ifdef WASM32}
+  {$ifdef CPUDEFINED}
+    {$fatal ONLY one of the switches for the CPU type must be defined}
+  {$endif CPUDEFINED}
+  {$define CPUDEFINED}
+{$endif WASM32}
+
 {$ifndef CPUDEFINED}
   {$fatal A CPU type switch must be defined}
 {$endif CPUDEFINED}

+ 6 - 12
compiler/ppcjvm.lpi

@@ -1,7 +1,7 @@
-<?xml version="1.0"?>
+<?xml version="1.0" encoding="UTF-8"?>
 <CONFIG>
   <ProjectOptions>
-    <Version Value="9"/>
+    <Version Value="11"/>
     <PathDelim Value="\"/>
     <General>
       <Flags>
@@ -19,19 +19,17 @@
     </BuildModes>
     <PublishOptions>
       <Version Value="2"/>
-      <IncludeFileFilter Value="*.(pas|pp|inc|lfm|lpr|lrs|lpi|lpk|sh|xml)"/>
-      <ExcludeFileFilter Value="*.(bak|ppu|ppw|o|so);*~;backup"/>
     </PublishOptions>
     <RunParams>
-      <local>
-        <FormatVersion Value="1"/>
-      </local>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default"/>
+      </Modes>
     </RunParams>
     <Units Count="1">
       <Unit0>
         <Filename Value="pp.pas"/>
         <IsPartOfProject Value="True"/>
-        <UnitName Value="pp"/>
       </Unit0>
     </Units>
   </ProjectOptions>
@@ -63,12 +61,8 @@
       <ConfigFile>
         <StopAfterErrCount Value="50"/>
       </ConfigFile>
-      <CompilerMessages>
-        <UseMsgFile Value="True"/>
-      </CompilerMessages>
       <CustomOptions Value="-djvm
 -dnoopt"/>
-      <CompilerPath Value="$(CompPath)"/>
     </Other>
   </CompilerOptions>
 </CONFIG>

+ 74 - 0
compiler/ppcwasm32.lpi

@@ -0,0 +1,74 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<CONFIG>
+  <ProjectOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <General>
+      <Flags>
+        <MainUnitHasUsesSectionForAllUnits Value="False"/>
+        <MainUnitHasCreateFormStatements Value="False"/>
+        <MainUnitHasTitleStatement Value="False"/>
+        <LRSInOutputDirectory Value="False"/>
+      </Flags>
+      <SessionStorage Value="InProjectDir"/>
+      <MainUnit Value="0"/>
+      <Title Value="ppcwasm32"/>
+    </General>
+    <BuildModes Count="1">
+      <Item1 Name="default" Default="True"/>
+    </BuildModes>
+    <PublishOptions>
+      <Version Value="2"/>
+    </PublishOptions>
+    <RunParams>
+      <FormatVersion Value="2"/>
+      <Modes Count="1">
+        <Mode0 Name="default"/>
+      </Modes>
+    </RunParams>
+    <Units Count="1">
+      <Unit0>
+        <Filename Value="pp.pas"/>
+        <IsPartOfProject Value="True"/>
+      </Unit0>
+    </Units>
+  </ProjectOptions>
+  <CompilerOptions>
+    <Version Value="11"/>
+    <PathDelim Value="\"/>
+    <Target>
+      <Filename Value="wasm32\pp"/>
+    </Target>
+    <SearchPaths>
+      <IncludeFiles Value="wasm32"/>
+      <OtherUnitFiles Value="wasm32;systems"/>
+      <UnitOutputDirectory Value="wasm32\lazbuild"/>
+    </SearchPaths>
+    <Parsing>
+      <SyntaxOptions>
+        <CStyleOperator Value="False"/>
+        <AllowLabel Value="False"/>
+        <CPPInline Value="False"/>
+        <UseAnsiStrings Value="False"/>
+      </SyntaxOptions>
+    </Parsing>
+    <Other>
+      <Verbosity>
+        <ShowWarn Value="False"/>
+        <ShowNotes Value="False"/>
+        <ShowHints Value="False"/>
+      </Verbosity>
+      <ConfigFile>
+        <StopAfterErrCount Value="50"/>
+      </ConfigFile>
+      <CustomOptions Value="-dwasm32
+-dnoopt
+-dEXTDEBUG"/>
+      <OtherDefines Count="3">
+        <Define0 Value="wasm32"/>
+        <Define1 Value="noopt"/>
+        <Define2 Value="EXTDEBUG"/>
+      </OtherDefines>
+    </Other>
+  </CompilerOptions>
+</CONFIG>

+ 2 - 2
compiler/pstatmnt.pas

@@ -381,9 +381,9 @@ implementation
              { variable must be an ordinal, int64 is not allowed for 32bit targets }
              if (
                  not(is_ordinal(hloopvar.resultdef))
-    {$ifndef cpu64bitaddr}
+    {$if not defined(cpu64bitaddr) and not defined(cpu64bitalu)}
                  or is_64bitint(hloopvar.resultdef)
-    {$endif not cpu64bitaddr}
+    {$endif not cpu64bitaddr and not cpu64bitalu}
                ) and
                (hloopvar.resultdef.typ<>undefineddef)
                then

+ 1 - 1
compiler/psub.pas

@@ -2398,7 +2398,7 @@ implementation
 
         { check if the definitions of certain types are available which might not be available in older rtls and
           which are assigned "on the fly" in types_dec }
-{$ifndef jvm}
+{$if not defined(jvm) and not defined(wasm)}
         if not assigned(rec_exceptaddr) then
           Message1(cg_f_internal_type_not_found,'TEXCEPTADDR');
         if not assigned(rec_tguid) then

+ 4 - 0
compiler/psystem.pas

@@ -386,6 +386,10 @@ implementation
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
 {$endif jvm}
+{$ifdef wasm}
+        create_fpu_types;
+        s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);
+{$endif wasm}
 {$ifdef xtensa}
         create_fpu_types;
         s64currencytype:=corddef.create(scurrency,low(int64),high(int64),true);

+ 5 - 2
compiler/symconst.pas

@@ -435,7 +435,9 @@ type
       "varargs" modifier or Mac-Pascal ".." parameter }
     po_variadic,
     { implicitly return same type as the class instance to which the message is sent }
-    po_objc_related_result_type
+    po_objc_related_result_type,
+    { procedure returns value (like a function), that should be discarded }
+    po_discardresult
   );
   tprocoptions=set of tprocoption;
 
@@ -1101,7 +1103,8 @@ inherited_objectoptions : tobjectoptions = [oo_has_virtual,oo_has_private,oo_has
       'po_is_auto_setter',{po_is_auto_setter}
       'po_noinline',{po_noinline}
       'C-style array-of-const', {po_variadic}
-      'objc-related-result-type' {po_objc_related_result_type}
+      'objc-related-result-type', {po_objc_related_result_type}
+      'po_discardresult' { po_discardresult }
     );
 
 implementation

+ 9 - 5
compiler/systems.inc

@@ -51,7 +51,7 @@
              cpu_jvm,                      { 14 }
              cpu_i8086,                    { 15 }
              cpu_aarch64,                  { 16 }
-             cpu_wasm,                     { 17 }
+             cpu_wasm32,                   { 17 }
              cpu_sparc64,                  { 18 }
              cpu_riscv32,                  { 19 }
              cpu_riscv64,                  { 20 }
@@ -181,7 +181,7 @@
              system_i8086_win16,        { 89 }
              system_i8086_embedded,     { 90 }
              system_arm_aros,           { 91 }
-             system_wasm_wasm32,        { 92 }
+             system_wasm32_embedded,    { 92 }
              system_sparc64_linux,      { 93 }
              system_sparc64_solaris,    { 94 }
              system_arm_netbsd,         { 95 }
@@ -202,7 +202,8 @@
              system_z80_msxdos,         { 110 }
              system_aarch64_darwin,     { 111 }
              system_z80_amstradcpc,     { 112 }
-             system_m68k_sinclairql     { 113 }
+             system_m68k_sinclairql,    { 113 }
+             system_wasm32_wasi         { 114 }
        );
 
      type
@@ -254,7 +255,7 @@
              ,as_solaris_as
              ,as_m68k_vasm
              ,as_m68k_as_aout
-             ,as_wasm_binaryen
+             ,as_wasm32_binaryen
              ,as_powerpc_gas_legacy    { for systems with very old GAS versions only, which don't support eg. named sections }
              ,as_clang_llvm
              ,as_clang_gas             { machine code assembler in gas style assembled by clang }
@@ -262,6 +263,8 @@
              ,as_sdcc_sdasz80
              ,as_z80_vasm
              ,as_z80_rel
+             ,as_wasm32_wabt
+             ,as_wasm32_llvm_mc        { WebAssembly code assembled by llvm-mc (llvm machine code playground) }
        );
 
        tlink = (ld_none,
@@ -307,7 +310,8 @@
              ld_zxspectrum,
              ld_msxdos,
              ld_amstradcpc,
-             ld_sinclairql
+             ld_sinclairql,
+             ld_wasi
        );
 
        tar = (ar_none

+ 16 - 12
compiler/systems.pas

@@ -85,7 +85,7 @@ interface
           id          : tasm;
           idtxt       : string[12];
           asmbin      : string[16];
-          asmcmd      : string[70];
+          asmcmd      : string[100];
           supported_targets : set of tsystem;
           flags        : set of tasmflags;
           labelprefix : string[3];
@@ -187,7 +187,7 @@ interface
        { using packed causes bus errors on processors which require alignment }
        tsysteminfo = record
           system       : tsystem;
-          name         : string[34];
+          name         : string[39];
           shortname    : string[12];
           flags        : set of tsystemflags;
           cpu          : tsystemcpu;
@@ -199,20 +199,20 @@ interface
           smartext,
           unitext,
           unitlibext,
-          asmext       : string[4];
+          asmext       : string[5];
           objext       : string[6];
           resext       : string[4];
           resobjext    : string[7];
           sharedlibext : string[10];
           staticlibext,
-          staticlibprefix : string[4];
+          staticlibprefix : string[6];
           sharedlibprefix : string[4];
           sharedClibext : string[10];
           staticClibext,
-          staticClibprefix : string[4];
+          staticClibprefix : string[6];
           sharedClibprefix : string[4];
           importlibprefix : string[10];
-          importlibext : string[4];
+          importlibext : string[6];
           Cprefix      : string[2];
           newline      : string[2];
           dirsep       : char;
@@ -293,6 +293,9 @@ interface
                          system_aarch64_darwin];
        systems_darwin = systems_ios + systems_iphonesym + systems_macosx;
 
+       { all WebAssembly systems }
+       systems_wasm = [system_wasm32_embedded,system_wasm32_wasi];
+
        {all solaris systems }
        systems_solaris = [system_sparc_solaris, system_i386_solaris,
                           system_x86_64_solaris];
@@ -369,7 +372,7 @@ interface
                                          system_arm_wince,
                                          system_x86_64_win64,
                                          system_i8086_win16,
-                                         system_aarch64_win64]+systems_linux+systems_android;
+                                         system_aarch64_win64]+systems_linux+systems_android+systems_wasm;
 
        { all systems that reference symbols in other binaries using indirect imports }
        systems_indirect_var_imports = systems_all_windows+[system_i386_nativent];
@@ -390,7 +393,8 @@ interface
                                    system_i386_openbsd,system_x86_64_openbsd,
                                    system_riscv32_linux,system_riscv64_linux,
                                    system_aarch64_win64,
-                                   system_z80_zxspectrum,system_z80_msxdos
+                                   system_z80_zxspectrum,system_z80_msxdos,
+                                   system_wasm32_wasi
                                   ]+systems_darwin+systems_amigalike;
 
        { all systems that use the PE+ header in the PE/COFF file
@@ -460,7 +464,7 @@ interface
        cpu2str : array[TSystemCpu] of string[10] =
             ('','i386','m68k','alpha','powerpc','sparc','vm','ia64','x86_64',
              'mips','arm', 'powerpc64', 'avr', 'mipsel','jvm', 'i8086',
-             'aarch64', 'wasm', 'sparc64', 'riscv32', 'riscv64', 'xtensa',
+             'aarch64', 'wasm32', 'sparc64', 'riscv32', 'riscv64', 'xtensa',
              'z80');
 
        abiinfo : array[tabi] of tabiinfo = (
@@ -1151,9 +1155,9 @@ begin
   {$endif cpuaarch64}
 {$endif aarch64}
 
-{$ifdef wasm}
-  default_target(system_wasm_wasm32);
-{$endif wasm}
+{$ifdef wasm32}
+  default_target(system_wasm32_wasi);
+{$endif wasm32}
 
 {$ifdef z80}
   default_target(system_z80_embedded);

+ 71 - 0
compiler/systems/i_embed.pas

@@ -784,6 +784,77 @@ unit i_embed;
             llvmdatalayout : 'todo';
           );
 
+       system_wasm32_embedded_info : tsysteminfo =
+          (
+            system       : system_wasm32_embedded;
+            name         : 'Embedded';
+            shortname    : 'embedded';
+            flags        : [tf_under_development,tf_needs_symbol_size,tf_needs_symbol_type,
+                            tf_files_case_sensitive,tf_no_generic_stackcheck,
+                            tf_smartlink_sections,
+                            { avoid the creation of threadvar tables }
+                            tf_section_threadvars];
+            cpu          : cpu_wasm32;
+            unit_env     : '';
+            extradefines : '';
+            exeext       : '.wasm';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.wat';
+            objext       : '.o';
+            resext       : '';
+            resobjext    : '.o';
+            sharedlibext : ''; // keep it empty! The sharedlibext drives the export module name
+                               // if this is populated, then the name should be cleared when generating import
+            staticlibext : '.a';
+            staticlibprefix : '';
+            sharedlibprefix : '';
+            sharedClibext : '.wasm';
+            staticClibext : '.wasm';
+            staticClibprefix : '';
+            sharedClibprefix : '';
+            importlibprefix : '';
+            importlibext : '.wasm';
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_wasm32_llvm_mc;
+            assemextern  : as_wasm32_llvm_mc;
+            link         : ld_none;
+            linkextern   : ld_embedded;
+            ar           : ar_none;
+            res          : res_none;
+            dbg          : dbg_dwarf2;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign       : 4;
+                loopalign       : 4;
+                jumpalign       : 0;
+                jumpalignskipmax    : 0;
+                coalescealign   : 0;
+                coalescealignskipmax: 0;
+                constalignmin   : 0;
+                constalignmax   : 4;
+                varalignmin     : 4;
+                varalignmax     : 4;
+                localalignmin   : 4;
+                localalignmax   : 4;
+                recordalignmin  : 0;
+                recordalignmax  : 2;
+                maxCrecordalign : 4
+              );
+            first_parm_offset : 0;
+            stacksize   : 262144;
+            stackalign   : 4;
+            abi          : abi_default;
+            llvmdatalayout : 'todo';
+          );
+
  implementation
 
 initialization

+ 123 - 0
compiler/systems/i_wasi.pas

@@ -0,0 +1,123 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    This unit implements support information structures for WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ ****************************************************************************
+}
+
+unit i_wasi;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       systems,rescmn;
+
+    const
+       res_wasmraw_info : tresinfo =
+           (
+             id     : res_none; // todo: not implemented. but could be as memory
+             resbin : 'fpcwasmres';
+             rescmd : '-o $OBJ $DBG';
+             rcbin  : '';
+             rccmd  : '';
+             resourcefileclass : nil;
+             resflags : [res_no_compile];
+           );
+
+        system_wasm32_wasi_info : tsysteminfo =
+          (
+            system       : system_wasm32_wasi;
+            name         : 'The WebAssembly System Interface (WASI)';
+            shortname    : 'Wasi';
+            flags        : [tf_under_development,tf_needs_symbol_size,tf_needs_symbol_type,
+                            tf_files_case_sensitive,tf_no_generic_stackcheck,
+                            tf_smartlink_sections,
+                            { avoid the creation of threadvar tables }
+                            tf_section_threadvars];
+            cpu          : cpu_wasm32;
+            unit_env     : '';
+            extradefines : '';
+            exeext       : '.wasm';
+            defext       : '.def';
+            scriptext    : '.sh';
+            smartext     : '.sl';
+            unitext      : '.ppu';
+            unitlibext   : '.ppl';
+            asmext       : '.wat';
+            objext       : '.o';
+            resext       : '';
+            resobjext    : '.o';
+            sharedlibext : ''; // keep it empty! The sharedlibext drives the export module name
+                               // if this is populated, then the name should be cleared when generating import
+            staticlibext : '.a';
+            staticlibprefix : '';
+            sharedlibprefix : '';
+            sharedClibext : '.wasm';
+            staticClibext : '.wasm';
+            staticClibprefix : '';
+            sharedClibprefix : '';
+            importlibprefix : '';
+            importlibext : '.wasm';
+            Cprefix      : '';
+            newline      : #10;
+            dirsep       : '/';
+            assem        : as_wasm32_llvm_mc;
+            assemextern  : as_wasm32_llvm_mc;
+            link         : ld_none;
+            linkextern   : ld_wasi; // there's no linker, only object files for WASM
+            ar           : ar_none;
+            res          : res_none;
+            dbg          : dbg_dwarf2;
+            script       : script_unix;
+            endian       : endian_little;
+            alignment    :
+              (
+                procalign       : 4;
+                loopalign       : 4;
+                jumpalign       : 0;
+                jumpalignskipmax    : 0;
+                coalescealign   : 0;
+                coalescealignskipmax: 0;
+                constalignmin   : 0;
+                constalignmax   : 4;
+                varalignmin     : 4;
+                varalignmax     : 4;
+                localalignmin   : 4;
+                localalignmax   : 4;
+                recordalignmin  : 0;
+                recordalignmax  : 2;
+                maxCrecordalign : 4
+              );
+            first_parm_offset : 0;
+            stacksize   : 262144;
+            stackalign   : 4;
+            abi          : abi_default;
+            llvmdatalayout : 'todo';
+          );
+
+
+  implementation
+
+initialization
+{$ifdef CPUWASM32}
+  {$ifdef wasi}
+    set_source_info(system_wasm32_wasi_info);
+  {$endif wasi}
+{$endif CPUWASM32}
+end.

+ 98 - 1
compiler/systems/t_embed.pas

@@ -33,7 +33,10 @@ implementation
        SysUtils,
        cutils,cfileutl,cclasses,
        globtype,globals,systems,verbose,comphook,cscript,fmodule,i_embed,link,
-       cpuinfo;
+{$ifdef wasm32}
+       t_wasi,import,export,
+{$endif wasm32}
+       cpuinfo,aasmbase;
 
     type
        TlinkerEmbedded=class(texternallinker)
@@ -59,6 +62,17 @@ implementation
 {          function postprocessexecutable(const fn : string;isdll:boolean):boolean;}
        end;
 
+       { TLinkerEmbedded_Wasm }
+
+       TLinkerEmbedded_Wasm=class(texternallinker)
+       public
+         constructor Create;override;
+         procedure SetDefaultInfo;override;
+
+         //function  MakeExecutable:boolean;override;
+         function  MakeSharedLibrary:boolean;override;
+       end;
+
 
 
 {*****************************************************************************
@@ -2026,6 +2040,82 @@ function TlinkerEmbedded_SdccSdld.MakeExecutable: boolean;
     MakeExecutable:=success;   { otherwise a recursive call to link method }
   end;
 
+{*****************************************************************************
+                              TlinkerEmbedded_Wasm
+*****************************************************************************}
+
+constructor TLinkerEmbedded_Wasm.Create;
+  begin
+    inherited Create;
+  end;
+
+procedure TLinkerEmbedded_Wasm.SetDefaultInfo;
+  begin
+    Info.DllCmd[1] := 'wasm-ld $SONAME $GCSECTIONS -o $EXE';
+    //Info.DllCmd[2] := 'wasmtool --exportrename $INPUT $EXE';
+  end;
+
+function TLinkerEmbedded_Wasm.MakeSharedLibrary: boolean;
+  var
+    GCSectionsStr  : ansistring;
+    binstr, cmdstr : Tcmdstr;
+    InitStr,
+    FiniStr,
+    SoNameStr      : string[80];
+    mapstr,ltostr  : TCmdStr;
+    success        : Boolean;
+
+    tmp : TCmdStrListItem;
+    tempFileName : ansistring;
+  begin
+    //Result := true;
+    //Result:=inherited MakeSharedLibrary;
+    if (cs_link_smart in current_settings.globalswitches) and
+       create_smartlink_sections then
+     GCSectionsStr:='--gc-sections'
+    else
+      GCSectionsStr:='';
+
+    SoNameStr:='';
+    SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
+    Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+
+    tmp := TCmdStrListItem(ObjectFiles.First);
+    while Assigned(tmp) do begin
+      cmdstr := tmp.Str+ ' ' + cmdstr;
+      tmp := TCmdStrListItem(tmp.Next);
+    end;
+
+    if HasExports then
+      cmdstr := cmdstr + ' --export-dynamic'; //' --export-dynamic';
+
+    cmdstr := cmdstr + ' --no-entry --allow-undefined';
+
+    if (cs_link_strip in current_settings.globalswitches) then
+     begin
+       { only remove non global symbols and debugging info for a library }
+       cmdstr := cmdstr + ' --strip-all';
+     end;
+
+    //Replace(cmdstr,'$OPT',Info.ExtraOptions);
+    //Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
+    //Replace(cmdstr,'$INIT',InitStr);
+    //Replace(cmdstr,'$FINI',FiniStr);
+    Replace(cmdstr,'$SONAME',SoNameStr);
+    //Replace(cmdstr,'$MAP',mapstr);
+    //Replace(cmdstr,'$LTO',ltostr);
+    Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+    writeln(utilsprefix+binstr,' ',cmdstr);
+    success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
+
+    //SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
+    //Replace(cmdstr,'$INPUT',current_module.objfilename );
+    //Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+    //DoExec(FindUtil(utilsprefix+binstr),cmdstr,false,false);
+
+    MakeSharedLibrary:=success;
+  end;
+
 
 {*****************************************************************************
                                      Initialize
@@ -2089,4 +2179,11 @@ initialization
   RegisterLinker(ld_embedded,TlinkerEmbedded_SdccSdld);
   RegisterTarget(system_z80_embedded_info);
 {$endif z80}
+
+{$ifdef wasm32}
+  RegisterTarget(system_wasm32_embedded_info);
+  RegisterImport(system_wasm32_embedded, timportlibwasi);
+  RegisterExport(system_wasm32_embedded, texportlibwasi);
+  RegisterLinker(ld_embedded, TLinkerEmbedded_Wasm);
+{$endif wasm32}
 end.

+ 263 - 0
compiler/systems/t_wasi.pas

@@ -0,0 +1,263 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    This unit implements support import,export,link routines
+    for the WASI target
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit t_wasi;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  systems,
+
+  globtype, globals,
+  aasmbase,
+  cfileutl, cutils, cclasses,
+
+  import, export, aasmdata, aasmcpu,
+  fmodule, ogbase,
+
+  symsym, symdef,
+
+  link,
+
+  i_wasi, tgcpu;
+
+type
+
+  { texportlibwasi }
+
+  texportlibwasi=class(texportlib)
+      procedure preparelib(const s : string);override;
+      procedure exportprocedure(hp : texported_item);override;
+      procedure exportvar(hp : texported_item);override;
+      procedure generatelib;override;
+    end;
+
+  { timportlibwasi }
+  timportlibwasi = class(timportlib)
+      procedure generatelib;override;
+    end;
+
+  { tlinkerwasi }
+
+  tlinkerwasi=class(texternallinker)
+  public
+    constructor Create;override;
+    procedure SetDefaultInfo;override;
+
+    procedure InitSysInitUnitName;override;
+
+    function  MakeExecutable:boolean;override;
+    function  MakeSharedLibrary:boolean;override;
+  end;
+
+
+implementation
+
+uses
+  SysUtils,
+  verbose;
+
+{ timportlibwasi }
+
+  procedure timportlibwasi.generatelib;
+    begin
+    end;
+
+{ tlinkerwasi }
+
+constructor tlinkerwasi.Create;
+begin
+  inherited Create;
+end;
+
+procedure tlinkerwasi.SetDefaultInfo;
+begin
+  Info.DllCmd[1] := 'wasm-ld $SONAME $GCSECTIONS $MAP -o $EXE';
+  //Info.DllCmd[2] := 'wasmtool --exportrename $INPUT $EXE';
+end;
+
+procedure tlinkerwasi.InitSysInitUnitName;
+begin
+  sysinitunit:='si_prc';
+end;
+
+function tlinkerwasi.MakeExecutable:boolean;
+var
+  GCSectionsStr  : ansistring;
+  binstr, cmdstr : Tcmdstr;
+  InitStr,
+  FiniStr,
+  SoNameStr      : string[80];
+  mapstr,ltostr  : TCmdStr;
+  success        : Boolean;
+
+  tmp : TCmdStrListItem;
+  tempFileName : ansistring;
+begin
+  if not(cs_link_nolink in current_settings.globalswitches) then
+    Message1(exec_i_linking,current_module.exefilename);
+
+  { Create some replacements }
+  mapstr:='';
+  if (cs_link_map in current_settings.globalswitches) then
+    mapstr:='-Map '+maybequoted(ChangeFileExt(current_module.exefilename,'.map'));
+  if (cs_link_smart in current_settings.globalswitches) and
+     create_smartlink_sections then
+   GCSectionsStr:='--gc-sections'
+  else
+    GCSectionsStr:='';
+
+  SoNameStr:='';
+  SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
+  Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+
+  tmp := TCmdStrListItem(ObjectFiles.First);
+  while Assigned(tmp) do begin
+    cmdstr := tmp.Str+ ' ' + cmdstr;
+    tmp := TCmdStrListItem(tmp.Next);
+  end;
+
+//  if HasExports then
+//    cmdstr := cmdstr + ' --export-dynamic'; //' --export-dynamic';
+
+  cmdstr := cmdstr + ' --no-entry';
+
+  if (cs_link_strip in current_settings.globalswitches) then
+   begin
+     { only remove non global symbols and debugging info for a library }
+     cmdstr := cmdstr + ' --strip-all';
+   end;
+
+  //Replace(cmdstr,'$OPT',Info.ExtraOptions);
+  //Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
+  //Replace(cmdstr,'$INIT',InitStr);
+  //Replace(cmdstr,'$FINI',FiniStr);
+  Replace(cmdstr,'$SONAME',SoNameStr);
+  Replace(cmdstr,'$MAP',mapstr);
+  //Replace(cmdstr,'$LTO',ltostr);
+  Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+  success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
+
+  //SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
+  //Replace(cmdstr,'$INPUT',current_module.objfilename );
+  //Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+  //DoExec(FindUtil(utilsprefix+binstr),cmdstr,false,false);
+
+  MakeExecutable:=success;
+end;
+
+function tlinkerwasi.MakeSharedLibrary: boolean;
+var
+  GCSectionsStr  : ansistring;
+  binstr, cmdstr : Tcmdstr;
+  InitStr,
+  FiniStr,
+  SoNameStr      : string[80];
+  mapstr,ltostr  : TCmdStr;
+  success        : Boolean;
+
+  tmp : TCmdStrListItem;
+  tempFileName : ansistring;
+begin
+  //Result := true;
+  //Result:=inherited MakeSharedLibrary;
+  if (cs_link_smart in current_settings.globalswitches) and
+     create_smartlink_sections then
+   GCSectionsStr:='--gc-sections'
+  else
+    GCSectionsStr:='';
+
+  SoNameStr:='';
+  SplitBinCmd(Info.DllCmd[1],binstr,cmdstr);
+  Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+
+  tmp := TCmdStrListItem(ObjectFiles.First);
+  while Assigned(tmp) do begin
+    cmdstr := tmp.Str+ ' ' + cmdstr;
+    tmp := TCmdStrListItem(tmp.Next);
+  end;
+
+  if HasExports then
+    cmdstr := cmdstr + ' --export-dynamic'; //' --export-dynamic';
+
+  cmdstr := cmdstr + ' --no-entry --allow-undefined';
+
+  if (cs_link_strip in current_settings.globalswitches) then
+   begin
+     { only remove non global symbols and debugging info for a library }
+     cmdstr := cmdstr + ' --strip-all';
+   end;
+
+  //Replace(cmdstr,'$OPT',Info.ExtraOptions);
+  //Replace(cmdstr,'$RES',maybequoted(outputexedir+Info.ResName));
+  //Replace(cmdstr,'$INIT',InitStr);
+  //Replace(cmdstr,'$FINI',FiniStr);
+  Replace(cmdstr,'$SONAME',SoNameStr);
+  //Replace(cmdstr,'$MAP',mapstr);
+  //Replace(cmdstr,'$LTO',ltostr);
+  Replace(cmdstr,'$GCSECTIONS',GCSectionsStr);
+  writeln(utilsprefix+binstr,' ',cmdstr);
+  success:=DoExec(FindUtil(utilsprefix+binstr),cmdstr,true,false);
+
+  //SplitBinCmd(Info.DllCmd[2],binstr,cmdstr);
+  //Replace(cmdstr,'$INPUT',current_module.objfilename );
+  //Replace(cmdstr,'$EXE',maybequoted(current_module.exefilename));
+  //DoExec(FindUtil(utilsprefix+binstr),cmdstr,false,false);
+
+  MakeSharedLibrary:=success;
+end;
+
+{ texportlibwasi }
+
+procedure texportlibwasi.preparelib(const s: string);
+begin
+  //nothing to happen. wasm files are modules
+end;
+
+procedure texportlibwasi.exportprocedure(hp: texported_item);
+var
+  nm : TSymStr;
+begin
+  nm := tprocdef(tprocsym(hp.sym).ProcdefList[0]).mangledname;
+  current_asmdata.asmlists[al_exports].Concat(tai_impexp.create(hp.name^, nm, ie_Func));
+end;
+
+procedure texportlibwasi.exportvar(hp: texported_item);
+begin
+  //inherited exportvar(hp);
+end;
+
+procedure texportlibwasi.generatelib;
+begin
+  //inherited generatelib;
+end;
+
+initialization
+  RegisterTarget(system_wasm32_wasi_info);
+  RegisterImport(system_wasm32_wasi, timportlibwasi);
+  RegisterExport(system_wasm32_wasi, texportlibwasi);
+  RegisterLinker(ld_wasi, tlinkerwasi);
+
+end.

+ 2 - 2
compiler/tgobj.pas

@@ -99,7 +99,7 @@ unit tgobj;
           procedure gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); virtual;
           procedure gettemp(list: TAsmList; size: asizeint; alignment: shortint; temptype: ttemptype; out ref : treference);
           procedure gettempmanaged(list: TAsmList; def:tdef;temptype:ttemptype;out ref : treference);
-          procedure ungettemp(list: TAsmList; const ref : treference);
+          procedure ungettemp(list: TAsmList; const ref : treference); virtual;
 
           function sizeoftemp(list: TAsmList; const ref: treference): asizeint;
           function changetemptype(list: TAsmList; const ref:treference;temptype:ttemptype):boolean;
@@ -184,7 +184,7 @@ implementation
        tempfreelist:=nil;
        templist:=nil;
        { we could create a new child class for this but I don't if it is worth the effort (FK) }
-{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm) or defined(aarch64) or defined(xtensa)}
+{$if defined(powerpc) or defined(powerpc64) or defined(avr) or defined(jvm) or defined(aarch64) or defined(xtensa) or defined(wasm32)}
        direction:=1;
 {$else}
        direction:=-1;

+ 2 - 0
compiler/tokens.pas

@@ -305,6 +305,7 @@ type
     _OBJCCATEGORY,
     _OBJCPROTOCOL,
     _WEAKEXTERNAL,
+    _DISCARDRESULT,
     _DISPINTERFACE,
     _UNIMPLEMENTED,
     _IMPLEMENTATION,
@@ -647,6 +648,7 @@ const
       (str:'OBJCCATEGORY'  ;special:false;keyword:[m_objectivec1];op:NOTOKEN), { Objective-C category }
       (str:'OBJCPROTOCOL'  ;special:false;keyword:[m_objectivec1];op:NOTOKEN), { Objective-C protocol }
       (str:'WEAKEXTERNAL'  ;special:false;keyword:[m_none];op:NOTOKEN),
+      (str:'DISCARDRESULT' ;special:false;keyword:[m_none];op:NOTOKEN),
       (str:'DISPINTERFACE' ;special:false;keyword:[m_class];op:NOTOKEN),
       (str:'UNIMPLEMENTED' ;special:false;keyword:[m_none];op:NOTOKEN),
       (str:'IMPLEMENTATION';special:false;keyword:alllanguagemodes-[m_iso,m_extpas];op:NOTOKEN),

+ 22 - 7
compiler/utils/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -623,7 +623,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_PROGRAMS+=fpc ppufiles ppudump ppumove mka64ins mkarmins mkx86ins msg2inc mkx86inl mkz80ins
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -935,7 +938,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override CLEAN_UNITS+=ppu crc
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override CLEAN_UNITS+=ppu crc
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override CLEAN_UNITS+=ppu crc
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1248,7 +1254,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_UNITDIR+=..
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_UNITDIR+=..
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_UNITDIR+=..
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1560,7 +1569,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override COMPILER_SOURCEDIR+=..
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override COMPILER_SOURCEDIR+=..
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override COMPILER_SOURCEDIR+=..
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2636,7 +2648,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 REQUIRE_PACKAGES_RTL=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2820,7 +2835,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 6 - 0
compiler/utils/fpc.pp

@@ -184,6 +184,10 @@ program fpc;
      ppcbin:='ppcxtensa';
      processorname:='xtensa';
 {$endif xtensa}
+{$ifdef wasm32}
+     ppcbin:='ppcwasm32';
+     processorname:='wasm32';
+{$endif wasm32}
      versionstr:='';                      { Default is just the name }
      if ParamCount = 0 then
        begin
@@ -271,6 +275,8 @@ program fpc;
                              cpusuffix:='xtensa'
                            else if processorstr='z80' then
                              cpusuffix:='z80'
+                           else if processorstr='wasm32' then
+                             cpusuffix:='wasm32'
                            else
                              error('Illegal processor type "'+processorstr+'"');
 

+ 265 - 0
compiler/utils/mkwasmreg.pp

@@ -0,0 +1,265 @@
+{
+    Copyright (c) 1998-2002 by Peter Vreman and Florian Klaempfl
+
+    Convert wasmreg.dat to several .inc files for usage with
+    the Free pascal compiler
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+program mkwasmreg;
+
+const Version = '1.00';
+      max_regcount = 200;
+
+var s : string;
+    i : longint;
+    line : longint;
+    regcount:byte;
+    regcount_bsstart:byte;
+    names,
+    regtypes,
+    subtypes,
+    supregs,
+    numbers,
+    stdnames : array[0..max_regcount-1] of string[63];
+    regnumber_index,
+    std_regname_index : array[0..max_regcount-1] of byte;
+
+function tostr(l : longint) : string;
+
+begin
+  str(l,tostr);
+end;
+
+function readstr : string;
+
+  var
+     result : string;
+
+  begin
+     result:='';
+     while (s[i]<>',') and (i<=length(s)) do
+       begin
+          result:=result+s[i];
+          inc(i);
+       end;
+     readstr:=result;
+  end;
+
+
+procedure readcomma;
+  begin
+     if s[i]<>',' then
+       begin
+         writeln('Missing "," at line ',line);
+         writeln('Line: "',s,'"');
+         halt(1);
+       end;
+     inc(i);
+  end;
+
+
+procedure skipspace;
+
+  begin
+     while (s[i] in [' ',#9]) do
+       inc(i);
+  end;
+
+procedure openinc(var f:text;const fn:string);
+begin
+  writeln('creating ',fn);
+  assign(f,fn);
+  rewrite(f);
+  writeln(f,'{ don''t edit, this file is generated from wasmreg.dat }');
+end;
+
+
+procedure closeinc(var f:text);
+begin
+  writeln(f);
+  close(f);
+end;
+
+procedure build_regnum_index;
+
+var h,i,j,p,t:byte;
+
+begin
+  {Build the registernumber2regindex index.
+   Step 1: Fill.}
+  for i:=0 to regcount-1 do
+    regnumber_index[i]:=i;
+  {Step 2: Sort. We use a Shell-Metzner sort.}
+  p:=regcount_bsstart;
+  repeat
+    for h:=0 to regcount-p-1 do
+      begin
+        i:=h;
+        repeat
+          j:=i+p;
+          if numbers[regnumber_index[j]]>=numbers[regnumber_index[i]] then
+            break;
+          t:=regnumber_index[i];
+          regnumber_index[i]:=regnumber_index[j];
+          regnumber_index[j]:=t;
+          if i<p then
+            break;
+          dec(i,p);
+        until false;
+      end;
+    p:=p shr 1;
+  until p=0;
+end;
+
+procedure build_std_regname_index;
+
+var h,i,j,p,t:byte;
+
+begin
+  {Build the registernumber2regindex index.
+   Step 1: Fill.}
+  for i:=0 to regcount-1 do
+    std_regname_index[i]:=i;
+  {Step 2: Sort. We use a Shell-Metzner sort.}
+  p:=regcount_bsstart;
+  repeat
+    for h:=0 to regcount-p-1 do
+      begin
+        i:=h;
+        repeat
+          j:=i+p;
+          if stdnames[std_regname_index[j]]>=stdnames[std_regname_index[i]] then
+            break;
+          t:=std_regname_index[i];
+          std_regname_index[i]:=std_regname_index[j];
+          std_regname_index[j]:=t;
+          if i<p then
+            break;
+          dec(i,p);
+        until false;
+      end;
+    p:=p shr 1;
+  until p=0;
+end;
+
+
+procedure read_spreg_file;
+
+var infile:text;
+
+begin
+   { open dat file }
+   assign(infile,'wasmreg.dat');
+   reset(infile);
+   while not(eof(infile)) do
+     begin
+        { handle comment }
+        readln(infile,s);
+        inc(line);
+        while (s[1]=' ') do
+         delete(s,1,1);
+        if (s='') or (s[1]=';') then
+          continue;
+
+        i:=1;
+        names[regcount]:=readstr;
+        readcomma;
+        regtypes[regcount]:=readstr;
+        readcomma;
+        subtypes[regcount]:=readstr;
+        readcomma;
+        supregs[regcount]:=readstr;
+        readcomma;
+        stdnames[regcount]:=readstr;
+        { Create register number }
+        if supregs[regcount][1]<>'$' then
+          begin
+            writeln('Missing $ before number, at line ',line);
+            writeln('Line: "',s,'"');
+            halt(1);
+          end;
+        numbers[regcount]:=regtypes[regcount]+copy(subtypes[regcount],2,255)+'00'+copy(supregs[regcount],2,255);
+        if i<length(s) then
+          begin
+            writeln('Extra chars at end of line, at line ',line);
+            writeln('Line: "',s,'"');
+            halt(1);
+          end;
+        inc(regcount);
+        if regcount>max_regcount then
+          begin
+            writeln('Error: Too much registers, please increase maxregcount in source');
+            halt(2);
+          end;
+     end;
+   close(infile);
+end;
+
+procedure write_inc_files;
+
+var
+    norfile,stdfile,supfile,
+    numfile,confile,
+    rnifile,srifile:text;
+    first:boolean;
+
+begin
+  { create inc files }
+  openinc(confile,'rwasmcon.inc');
+  openinc(supfile,'rwasmsup.inc');
+  openinc(numfile,'rwasmnum.inc');
+  openinc(stdfile,'rwasmstd.inc');
+  openinc(norfile,'rwasmnor.inc');
+  openinc(rnifile,'rwasmrni.inc');
+  openinc(srifile,'rwasmsri.inc');
+  first:=true;
+  for i:=0 to regcount-1 do
+    begin
+      if not first then
+        begin
+          writeln(numfile,',');
+          writeln(stdfile,',');
+          writeln(rnifile,',');
+          writeln(srifile,',');
+        end
+      else
+        first:=false;
+      writeln(supfile,'RS_',names[i],' = ',supregs[i],';');
+      writeln(confile,'NR_'+names[i],' = ','tregister(',numbers[i],')',';');
+      write(numfile,'tregister(',numbers[i],')');
+      write(stdfile,'''',stdnames[i],'''');
+      write(rnifile,regnumber_index[i]);
+      write(srifile,std_regname_index[i]);
+    end;
+  write(norfile,regcount);
+  close(confile);
+  close(supfile);
+  closeinc(numfile);
+  closeinc(stdfile);
+  closeinc(norfile);
+  closeinc(rnifile);
+  closeinc(srifile);
+  writeln('Done!');
+  writeln(regcount,' registers procesed');
+end;
+
+
+begin
+   writeln('Register Table Converter Version ',Version);
+   line:=0;
+   regcount:=0;
+   read_spreg_file;
+   regcount_bsstart:=1;
+   while 2*regcount_bsstart<regcount do
+     regcount_bsstart:=regcount_bsstart*2;
+   build_regnum_index;
+   build_std_regname_index;
+   write_inc_files;
+end.

+ 10 - 8
compiler/utils/ppuutils/ppudump.pp

@@ -82,7 +82,7 @@ const
     { 14 } 'jvm',
     { 15 } 'i8086',
     { 16 } 'aarch64',
-    { 17 } 'wasm',
+    { 17 } 'wasm32',
     { 18 } 'sparc64',
     { 19 } 'riscv32',
     { 20 } 'riscv64',
@@ -109,7 +109,7 @@ const
     { 14 } false {'jvm'},
     { 15 } false {'i8086'},
     { 16 } false {'aarch64'},
-    { 17 } false {'wasm'},
+    { 17 } false {'wasm32'},
     { 18 } false {'sparc64'},
     { 19 } false {'riscv32'},
     { 20 } false {'riscv64'},
@@ -233,7 +233,8 @@ const
   { 110 } 'MSX-DOS-Z80',
   { 111 } 'Darwin-AArch64',
   { 112 } 'AmstradCPC-Z80',
-  { 113 } 'SinclairQL-m68k'
+  { 113 } 'SinclairQL-m68k',
+  { 114 } 'WASI-WASM32'
   );
 
 const
@@ -387,8 +388,8 @@ type
        cpu_variant_armv8
       );
 
-  tcpu_wasm = (
-       cpu_variant_wasm_none);
+  tcpu_wasm32 = (
+       cpu_variant_wasm32_none);
 
   tcpu_sparc64 = (
     cpu_variant_sparc64_none,
@@ -448,8 +449,8 @@ type
           (cpu_i8086 : tcpu_i8086;);
        cpu_aarch64:                 { 16 }
           (cpu_aarch64 : tcpu_aarch64;);
-       cpu_wasm:                    { 17 }
-          (cpu_wasm : tcpu_wasm;);
+       cpu_wasm32:                  { 17 }
+          (cpu_wasm32 : tcpu_wasm32;);
        cpu_sparc64:                 { 18 }
           (cpu_sparc64 : tcpu_sparc64;);
        cpu_riscv32:                 { 19 }
@@ -2996,7 +2997,8 @@ const
      (mask:po_is_auto_setter;  str: 'Automatically generated setter'),
      (mask:po_noinline;        str: 'Never inline'),
      (mask:po_variadic;        str: 'C VarArgs with array-of-const para'),
-     (mask:po_objc_related_result_type; str: 'Objective-C related result type')
+     (mask:po_objc_related_result_type; str: 'Objective-C related result type'),
+     (mask:po_discardresult;   str: 'Discard result')
   );
 var
   proctypeoption  : tproctypeoption;

+ 338 - 0
compiler/wasm32/aasmcpu.pas

@@ -0,0 +1,338 @@
+{
+    Copyright (c) 2019 by Free Pascal and Lazarus foundation
+
+    Contains the assembler object for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit aasmcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  cclasses,
+  globtype,globals,verbose,
+  aasmbase,aasmtai,aasmdata,aasmsym,
+  cgbase,cgutils,cpubase,cpuinfo,
+  widestr;
+
+    { fake, there are no "mov reg,reg" instructions here }
+    const
+      { "mov reg,reg" source operand number }
+      O_MOV_SOURCE = 0;
+      { "mov reg,reg" source operand number }
+      O_MOV_DEST = 0;
+
+    type
+
+      { taicpu }
+
+      taicpu = class(tai_cpu_abstract_sym)
+         constructor op_none(op : tasmop);
+
+         constructor op_reg(op : tasmop;_op1 : tregister);
+         constructor op_const(op : tasmop;_op1 : aint);
+         constructor op_ref(op : tasmop;const _op1 : treference);
+         constructor op_sym(op : tasmop;_op1 : tasmsymbol);
+
+         constructor op_sym_const(op : tasmop;_op1 : tasmsymbol;_op2 : aint);
+
+         constructor op_single(op : tasmop;_op1 : single);
+         constructor op_double(op : tasmop;_op1 : double);
+
+         constructor op_functype(op : tasmop; _op1: TWasmFuncType);
+
+         procedure loadfunctype(opidx:longint;ft:TWasmFuncType);
+         procedure loadsingle(opidx:longint;f:single);
+         procedure loaddouble(opidx:longint;d:double);
+
+         { register allocation }
+         function is_same_reg_move(regtype: Tregistertype):boolean; override;
+
+         { register spilling code }
+         function spilling_get_operation_type(opnr: longint): topertype;override;
+      end;
+
+      tai_align = class(tai_align_abstract)
+        { nothing to add }
+      end;
+
+      TImpExpType= (
+        ie_Func,   // functions
+        ie_Table,  // tables (arrays of methods)
+        ie_Memory, // memory reference
+        ie_Global  // global variables
+      );
+
+      // the actual use is defined by the assembly section used
+
+      { timpexp_ai }
+
+      tai_impexp = class(tai)
+        extname : ansistring; // external name
+        intname : ansistring; // internal name
+        extmodule : ansistring; // external unit name
+        symstype: TImpExpType;
+        constructor create(const aextname, aintname: ansistring; asymtype: timpexptype); overload;
+        constructor create(const aextmodule, aextname, aintname: ansistring; asymtype: timpexptype); overload;
+      end;
+
+      // local variable declaration
+
+      { tai_local }
+
+      tai_local = class(tai)
+        bastyp: TWasmBasicType;
+        name : string;
+        first: boolean;
+        last: boolean;
+        constructor create(abasictype: TWasmBasicType; const aname: string = '');
+      end;
+
+      { tai_functype }
+
+      tai_functype = class(tai)
+        funcname: string;
+        functype: TWasmFuncType;
+        constructor create(const afuncname: string; afunctype: TWasmFuncType);
+        destructor destroy;override;
+      end;
+
+    procedure InitAsm;
+    procedure DoneAsm;
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+
+implementation
+
+    { tai_functype }
+
+    constructor tai_functype.create(const afuncname: string; afunctype: TWasmFuncType);
+      begin
+        inherited Create;
+        typ:=ait_functype;
+        funcname:=afuncname;
+        functype:=afunctype;
+      end;
+
+
+    destructor tai_functype.destroy;
+      begin
+        functype.free;
+        inherited;
+      end;
+
+    { tai_local }
+
+    constructor tai_local.create(abasictype: TWasmBasicType; const aname: string);
+      begin
+        inherited Create;
+        bastyp := abasictype;
+        typ := ait_local;
+        name := aname;
+      end;
+
+    { timpexp_ai }
+
+      constructor tai_impexp.create(const aextname, aintname: ansistring;
+          asymtype: timpexptype);
+        begin
+          create('', aextname, aintname, asymtype);;
+        end;
+
+      constructor tai_impexp.create(const aextmodule, aextname, aintname: ansistring; asymtype: timpexptype);
+        begin
+          inherited create;
+          typ := ait_importexport;
+          extmodule := aextmodule;
+          extname := aextname;
+          intname := aintname;
+          symstype:= asymtype;
+        end;
+
+{*****************************************************************************
+                                 taicpu Constructors
+*****************************************************************************}
+
+    constructor taicpu.op_none(op : tasmop);
+      begin
+        inherited create(op);
+      end;
+
+
+    constructor taicpu.op_reg(op : tasmop;_op1 : tregister);
+      begin
+        inherited create(op);
+        ops:=1;
+{$ifdef EXTDEBUG}
+        if getregtype(_op1)=R_INVALIDREGISTER then
+          InternalError(2021011901);
+{$endif EXTDEBUG}
+        loadreg(0,_op1);
+      end;
+
+
+    constructor taicpu.op_ref(op : tasmop;const _op1 : treference);
+      begin
+        inherited create(op);
+        ops:=1;
+        loadref(0,_op1);
+        if op in [a_local_get,a_local_set,a_local_tee] then
+          begin
+            if (_op1.base<>NR_LOCAL_STACK_POINTER_REG) or (_op1.index<>NR_NO) then
+              internalerror(2021010201);
+          end
+        else
+          begin
+            if (_op1.base<>NR_NO) or (_op1.index<>NR_NO) then
+              internalerror(2021010202);
+          end;
+      end;
+
+
+    constructor taicpu.op_const(op : tasmop;_op1 : aint);
+      begin
+        inherited create(op);
+        ops:=1;
+        loadconst(0,_op1);
+      end;
+
+
+    constructor taicpu.op_sym(op : tasmop;_op1 : tasmsymbol);
+      begin
+        inherited create(op);
+        ops:=1;
+        loadsymbol(0,_op1,0);
+      end;
+
+
+    constructor taicpu.op_sym_const(op: tasmop; _op1: tasmsymbol; _op2: aint);
+      begin
+        inherited create(op);
+        ops:=2;
+        loadsymbol(0,_op1,0);
+        loadconst(1,_op2);
+      end;
+
+
+    constructor taicpu.op_single(op: tasmop; _op1: single);
+      begin
+        inherited create(op);
+        ops:=1;
+        loadsingle(0,_op1);
+      end;
+
+
+    constructor taicpu.op_double(op: tasmop; _op1: double);
+      begin
+        inherited create(op);
+        ops:=1;
+        loaddouble(0,_op1);
+      end;
+
+    constructor taicpu.op_functype(op: tasmop; _op1: TWasmFuncType);
+      begin
+       inherited create(op);
+       ops:=1;
+       loadfunctype(0,_op1);
+      end;
+
+    procedure taicpu.loadfunctype(opidx: longint; ft: TWasmFuncType);
+      begin
+       allocate_oper(opidx+1);
+       with oper[opidx]^ do
+        begin
+          if typ<>top_functype then
+            clearop(opidx);
+          functype:=ft;
+          typ:=top_functype;
+        end;
+      end;
+
+
+    procedure taicpu.loadsingle(opidx:longint;f:single);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_single then
+             clearop(opidx);
+           sval:=f;
+           typ:=top_single;
+         end;
+      end;
+
+
+    procedure taicpu.loaddouble(opidx: longint; d: double);
+      begin
+        allocate_oper(opidx+1);
+        with oper[opidx]^ do
+         begin
+           if typ<>top_double then
+             clearop(opidx);
+           dval:=d;
+           typ:=top_double;
+         end;
+      end;
+
+
+    function taicpu.is_same_reg_move(regtype: Tregistertype):boolean;
+      begin
+        result:=false;
+      end;
+
+
+    function taicpu.spilling_get_operation_type(opnr: longint): topertype;
+      begin
+        if opcode in AsmOp_Store then
+          result:=operand_write
+        else
+          result:=operand_read;
+      end;
+
+
+    function spilling_create_load(const ref:treference;r:tregister):Taicpu;
+      begin
+       internalerror(2010122614);
+       result:=nil;
+      end;
+
+
+    function spilling_create_store(r:tregister; const ref:treference):Taicpu;
+      begin
+       internalerror(2010122615);
+       result:=nil;
+      end;
+
+
+    procedure InitAsm;
+      begin
+      end;
+
+
+    procedure DoneAsm;
+      begin
+      end;
+
+initialization
+  cai_cpu:=taicpu;
+  cai_align:=tai_align;
+  casmdata:=TAsmData;
+end.

+ 604 - 0
compiler/wasm32/agbinaryen.pas

@@ -0,0 +1,604 @@
+{
+    Copyright (c) 2017 by Karoly Balogh
+
+    This unit implements the Binaryen assembler writer
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit agbinaryen;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cclasses,systems,
+      globtype,globals,
+      symconst,symbase,symdef,symsym,
+      aasmbase,aasmtai,aasmdata,aasmcpu,
+      assemble;
+
+    type
+      TBinaryenAssemblerOutputFile=class(TExternalAssemblerOutputFile)
+        procedure RemoveAsm; override;
+      end;
+
+      TBinaryenInstrWriter = class;
+      {# This is a derived class which is used to write
+         Binaryen-styled assembler.
+      }
+
+      { TBinaryenAssembler }
+
+      TBinaryenAssembler=class(texternalassembler)
+       protected
+        jasminjar: tcmdstr;
+        asmfiles: TCmdStrList;
+
+        procedure WriteExtraHeader(obj: tabstractrecorddef);
+        procedure WriteInstruction(hp: tai);
+
+        function CreateNewAsmWriter: TExternalAssemblerOutputFile; override;
+       public
+        constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+        procedure WriteTree(p:TAsmList);override;
+        procedure WriteAsmList;override;
+        destructor destroy; override;
+       protected
+        InstrWriter: TBinaryenInstrWriter;
+      end;
+
+
+      {# This is the base class for writing instructions.
+
+         The WriteInstruction() method must be overridden
+         to write a single instruction to the assembler
+         file.
+      }
+
+      { TBinaryenInstrWriter }
+
+      TBinaryenInstrWriter = class
+        constructor create(_owner: TBinaryenAssembler);
+        procedure WriteInstruction(hp : tai); virtual;
+       protected
+        owner: TBinaryenAssembler;
+      end;
+
+
+implementation
+
+    uses
+      SysUtils,
+      cutils,cfileutl,cscript,
+      fmodule,finput,verbose,
+      symtype,symcpu,symtable,
+      itcpuwasm,cpubase,cpuinfo,cgutils,
+      widestr
+      ;
+
+    const
+      line_length = 70;
+
+    type
+      t64bitarray = array[0..7] of byte;
+      t32bitarray = array[0..3] of byte;
+
+{****************************************************************************}
+{                          Support routines                                  }
+{****************************************************************************}
+
+   function fixline(s:string):string;
+   {
+     return s with all leading and ending spaces and tabs removed
+   }
+     var
+       i,j,k : integer;
+     begin
+       i:=length(s);
+       while (i>0) and (s[i] in [#9,' ']) do
+        dec(i);
+       j:=1;
+       while (j<i) and (s[j] in [#9,' ']) do
+        inc(j);
+       for k:=j to i do
+        if s[k] in [#0..#31,#127..#255] then
+         s[k]:='.';
+       fixline:=Copy(s,j,i-j+1);
+     end;
+
+
+   function constastr(p: pchar; len: longint): ansistring;
+     var
+       i,runstart,runlen: longint;
+
+       procedure flush;
+         begin
+           if runlen>0 then
+             begin
+               setlength(result,length(result)+runlen);
+               move(p[runstart],result[length(result)-runlen+1],runlen);
+               runlen:=0;
+             end;
+         end;
+
+     begin
+       result:='"';
+       runlen:=0;
+       runstart:=0;
+       for i:=0 to len-1 do
+         begin
+           { escape control codes }
+           case p[i] of
+             { LF and CR must be escaped specially, because \uXXXX parsing
+               happens in the pre-processor, so it's the same as actually
+               inserting a newline in the middle of a string constant }
+             #10:
+               begin
+                 flush;
+                 result:=result+'\n';
+               end;
+             #13:
+               begin
+                 flush;
+                 result:=result+'\r';
+               end;
+             '"','\':
+               begin
+                 flush;
+                 result:=result+'\'+p[i];
+               end
+             else if p[i]<#32 then
+               begin
+                 flush;
+                 result:=result+'\u'+hexstr(ord(p[i]),4);
+               end
+             else if p[i]<#127 then
+               begin
+                 if runlen=0 then
+                   runstart:=i;
+                 inc(runlen);
+               end
+             else
+               begin
+                 { see comments in njvmcon }
+                 flush;
+                 result:=result+'\u'+hexstr(ord(p[i]),4)
+               end;
+           end;
+         end;
+       flush;
+       result:=result+'"';
+     end;
+
+
+
+{****************************************************************************}
+{                       Binaryen Output File                                   }
+{****************************************************************************}
+
+    procedure TBinaryenAssemblerOutputFile.RemoveAsm;
+      var
+        g : file;
+      begin
+        inherited;
+        if cs_asm_leave in current_settings.globalswitches then
+         exit;
+        while not TBinaryenAssembler(owner).asmfiles.empty do
+          begin
+            if cs_asm_extern in current_settings.globalswitches then
+             AsmRes.AddDeleteCommand(TBinaryenAssembler(owner).asmfiles.GetFirst)
+            else
+             begin
+               assign(g,TBinaryenAssembler(owner).asmfiles.GetFirst);
+               {$I-}
+                erase(g);
+               {$I+}
+               if ioresult<>0 then;
+             end;
+          end;
+      end;
+
+
+{****************************************************************************}
+{                       Binaryen Assembler writer                              }
+{****************************************************************************}
+
+    destructor TBinaryenAssembler.Destroy;
+      begin
+        InstrWriter.free;
+        asmfiles.free;
+        inherited destroy;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteTree(p:TAsmList);
+      var
+        ch       : char;
+        hp       : tai;
+        hp1      : tailineinfo;
+        s        : ansistring;
+        i,pos    : longint;
+        InlineLevel : longint;
+        do_line  : boolean;
+      begin
+        if not assigned(p) then
+         exit;
+
+        InlineLevel:=0;
+        { lineinfo is only needed for al_procedures (PFV) }
+        do_line:=(cs_asm_source in current_settings.globalswitches);
+        hp:=tai(p.first);
+        while assigned(hp) do
+         begin
+           prefetch(pointer(hp.next)^);
+           if not(hp.typ in SkipLineInfo) then
+            begin
+              hp1 := hp as tailineinfo;
+              current_filepos:=hp1.fileinfo;
+               { no line info for inlined code }
+               if do_line and (inlinelevel=0) then
+                begin
+                  { load infile }
+                  if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
+                   begin
+                     infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
+                     if assigned(infile) then
+                      begin
+                        { open only if needed !! }
+                        if (cs_asm_source in current_settings.globalswitches) then
+                         infile.open;
+                      end;
+                     { avoid unnecessary reopens of the same file !! }
+                     lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
+                     { be sure to change line !! }
+                     lastfileinfo.line:=-1;
+                   end;
+
+                { write source }
+                  if (cs_asm_source in current_settings.globalswitches) and
+                     assigned(infile) then
+                   begin
+                     if (infile<>lastinfile) then
+                       begin
+                         writer.AsmWriteLn(asminfo^.comment+'['+infile.name+']');
+                         if assigned(lastinfile) then
+                           lastinfile.close;
+                       end;
+                     if (hp1.fileinfo.line<>lastfileinfo.line) and
+                        ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
+                       begin
+                         if (hp1.fileinfo.line<>0) and
+                            ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
+                           writer.AsmWriteLn(asminfo^.comment+'['+tostr(hp1.fileinfo.line)+'] '+
+                             fixline(infile.GetLineStr(hp1.fileinfo.line)));
+                         { set it to a negative value !
+                         to make that is has been read already !! PM }
+                         if (infile.linebuf^[hp1.fileinfo.line]>=0) then
+                           infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
+                       end;
+                   end;
+                  lastfileinfo:=hp1.fileinfo;
+                  lastinfile:=infile;
+                end;
+            end;
+
+           case hp.typ of
+
+             ait_comment :
+               Begin
+                 writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWritePChar(tai_comment(hp).str);
+                 writer.AsmLn;
+               End;
+
+             ait_regalloc :
+               begin
+                 if (cs_asm_regalloc in current_settings.globalswitches) then
+                   begin
+                     writer.AsmWrite(#9+asminfo^.comment+'Register ');
+                     repeat
+                       writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
+                       if (hp.next=nil) or
+                          (tai(hp.next).typ<>ait_regalloc) or
+                          (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
+                         break;
+                       hp:=tai(hp.next);
+                       writer.AsmWrite(',');
+                     until false;
+                     writer.AsmWrite(' ');
+                     writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
+                   end;
+               end;
+
+             ait_tempalloc :
+               begin
+                 if (cs_asm_tempalloc in current_settings.globalswitches) then
+                   begin
+  {$ifdef EXTDEBUG}
+                     if assigned(tai_tempalloc(hp).problem) then
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
+                     else
+  {$endif EXTDEBUG}
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tempallocstr[tai_tempalloc(hp).allocation]);
+                   end;
+               end;
+
+             ait_align :
+               begin
+
+               end;
+
+             ait_section :
+               begin
+
+               end;
+
+             ait_datablock :
+               begin
+//                 internalerror(2010122701);
+               end;
+
+             ait_const:
+               begin
+                 writer.AsmWriteln('constant');
+//                 internalerror(2010122702);
+               end;
+
+             ait_realconst :
+               begin
+                 internalerror(2010122703);
+               end;
+
+             ait_string :
+               begin
+                 pos:=0;
+                  for i:=1 to tai_string(hp).len do
+                   begin
+                     if pos=0 then
+                      begin
+                        writer.AsmWrite(#9'strconst: '#9'"');
+                        pos:=20;
+                      end;
+                     ch:=tai_string(hp).str[i-1];
+                     case ch of
+                        #0, {This can't be done by range, because a bug in FPC}
+                   #1..#31,
+                #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                       '"' : s:='\"';
+                       '\' : s:='\\';
+                     else
+                      s:=ch;
+                     end;
+                     writer.AsmWrite(s);
+                     inc(pos,length(s));
+                     if (pos>line_length) or (i=tai_string(hp).len) then
+                      begin
+                        writer.AsmWriteLn('"');
+                        pos:=0;
+                      end;
+                   end;
+               end;
+
+             ait_label :
+               begin
+                 if (tai_label(hp).labsym.is_used) then
+                  begin
+                    writer.AsmWrite(tai_label(hp).labsym.name);
+                    writer.AsmWriteLn(':');
+                  end;
+               end;
+
+             ait_symbol :
+               begin
+                  if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
+                    begin
+                    end
+                  else
+                   begin
+                     writer.AsmWrite('data symbol: ');
+                     writer.AsmWriteln(tai_symbol(hp).sym.name);
+//                     internalerror(2010122706);
+                   end;
+               end;
+             ait_symbol_end :
+               begin
+               end;
+
+             ait_instruction :
+               begin
+                 WriteInstruction(hp);
+               end;
+
+             ait_force_line,
+             ait_function_name : ;
+
+             ait_cutobject :
+               begin
+               end;
+
+             ait_marker :
+               if tai_marker(hp).kind=mark_NoLineInfoStart then
+                 inc(InlineLevel)
+               else if tai_marker(hp).kind=mark_NoLineInfoEnd then
+                 dec(InlineLevel);
+
+             ait_directive :
+               begin
+                 { the CPU directive is probably not supported by the JVM assembler,
+                   so it's commented out }
+                 if tai_directive(hp).directive=asd_cpu then
+                   writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
+                 if tai_directive(hp).name<>'' then
+                   writer.AsmWrite(tai_directive(hp).name);
+                 writer.AsmLn;
+               end;
+
+             else
+               internalerror(2010122707);
+           end;
+           hp:=tai(hp.next);
+         end;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteExtraHeader(obj: tabstractrecorddef);
+      begin
+      end;
+
+
+    procedure TBinaryenAssembler.WriteInstruction(hp: tai);
+      begin
+        InstrWriter.WriteInstruction(hp);
+      end;
+
+
+    function TBinaryenAssembler.CreateNewAsmWriter: TExternalAssemblerOutputFile;
+      begin
+        Result:=TBinaryenAssemblerOutputFile.Create(self);
+      end;
+
+
+    constructor TBinaryenAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited;
+        InstrWriter:=TBinaryenInstrWriter.Create(self);
+        asmfiles:=TCmdStrList.Create;
+      end;
+
+
+    procedure TBinaryenAssembler.WriteAsmList;
+      var
+        hal : tasmlisttype;
+      begin
+        writer.MarkEmpty;
+        WriteExtraHeader(nil);
+
+      for hal:=low(TasmlistType) to high(TasmlistType) do
+        begin
+          if not (current_asmdata.asmlists[hal].empty) then
+            begin
+              writer.AsmWriteLn(asminfo^.comment+'Begin asmlist '+AsmlistTypeStr[hal]);
+              writetree(current_asmdata.asmlists[hal]);
+              writer.AsmWriteLn(asminfo^.comment+'End asmlist '+AsmlistTypeStr[hal]);
+            end;
+        end;
+
+        writer.AsmLn;
+      end;
+
+
+{****************************************************************************}
+{                         Binaryen Instruction Writer                          }
+{****************************************************************************}
+
+     constructor TBinaryenInstrWriter.create(_owner: TBinaryenAssembler);
+       begin
+         inherited create;
+         owner := _owner;
+       end;
+
+    function getreferencestring(var ref : treference) : ansistring;
+      begin
+{        if (ref.arrayreftype<>art_none) or
+           (ref.index<>NR_NO) then
+          internalerror(2010122809);}
+        if assigned(ref.symbol) then
+          begin
+            // global symbol or field -> full type and name
+            // ref.base can be <> NR_NO in case an instance field is loaded.
+            // This register is not part of this instruction, it will have
+            // been placed on the stack by the previous one.
+            if (ref.offset<>0) then
+              internalerror(2010122811);
+            result:=ref.symbol.name;
+          end
+        else
+          begin
+            // local symbol -> stack slot, stored in offset
+            if ref.base<>NR_STACK_POINTER_REG then
+              internalerror(2010122810);
+            result:=tostr(ref.offset);
+          end;
+      end;
+
+
+    function getopstr(const o:toper) : ansistring;
+      begin
+        case o.typ of
+          top_reg:
+            // should have been translated into a memory location by the
+            // register allocator)
+            if (cs_no_regalloc in current_settings.globalswitches) then
+              getopstr:=std_regname(o.reg)
+            else
+              internalerror(2010122803);
+          top_const:
+            str(o.val,result);
+          top_ref:
+            getopstr:=getreferencestring(o.ref^);
+          else
+            internalerror(2010122802);
+        end;
+      end;
+
+
+    procedure TBinaryenInstrWriter.WriteInstruction(hp: tai);
+      var
+        s: ansistring;
+        i: byte;
+        sep: ansistring;
+      begin
+        s:=#9+wasm_op2str[taicpu(hp).opcode];
+        if taicpu(hp).ops<>0 then
+          begin
+            sep:=#9;
+            for i:=0 to taicpu(hp).ops-1 do
+              begin
+                 s:=s+sep+getopstr(taicpu(hp).oper[i]^);
+                 sep:=' ';
+              end;
+          end;
+        owner.writer.AsmWriteLn(s);
+      end;
+
+{****************************************************************************}
+{                         Binaryen Instruction Writer                        }
+{****************************************************************************}
+
+  const
+    as_wasm_binaryen_info : tasminfo =
+       (
+         id     : as_wasm32_binaryen;
+         idtxt  : 'BINARYEN';
+         asmbin : 'wasm-as';
+         asmcmd : '$ASM $EXTRAOPT';
+         supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
+         flags : [];
+         labelprefix : 'L';
+         labelmaxlen : -1;
+         comment : ';; ';
+         dollarsign : '$';
+       );
+
+
+initialization
+  RegisterAssembler(as_wasm_binaryen_info,TBinaryenAssembler);
+end.

+ 328 - 0
compiler/wasm32/agllvmmc.pas

@@ -0,0 +1,328 @@
+{
+    Copyright (c) 1998-2020 by the Free Pascal team
+
+    This unit implements the llvm-mc ("llvm machine code playground")
+    assembler writer for WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+unit agllvmmc;
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    systems,cgutils,
+    globtype,globals,
+    symbase,symdef,symtype,symconst,symcpu,
+    aasmbase,aasmtai,aasmdata,aasmcpu,
+    assemble,aggas;
+
+  type
+
+    { TLLVMMachineCodePlaygroundAssembler }
+
+    TLLVMMachineCodePlaygroundAssembler=class(TGNUassembler)
+    protected
+      procedure WriteImports;
+
+      function sectionname(atype:TAsmSectiontype;const aname:string;aorder:TAsmSectionOrder):string;override;
+    public
+      constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+      procedure WriteAsmList;override;
+    end;
+
+    { TWASM32InstrWriter }
+
+    TWASM32InstrWriter = class(TCPUInstrWriter)
+      procedure WriteInstruction(hp : tai);override;
+    end;
+
+implementation
+
+  uses
+    cutils,
+    fmodule,finput,
+    itcpugas,
+    cpubase,
+    hlcgobj,hlcgcpu,
+    verbose;
+
+  { TLLVMMachineCodePlaygroundAssembler }
+
+
+  procedure TLLVMMachineCodePlaygroundAssembler.WriteImports;
+    var
+      i    : integer;
+      proc : tprocdef;
+      list : TAsmList;
+      cur_unit: tused_unit;
+    begin
+      for i:=0 to current_module.deflist.Count-1 do
+        if tdef(current_module.deflist[i]).typ = procdef then
+          begin
+            proc := tprocdef(current_module.deflist[i]);
+            if (po_external in proc.procoptions) and assigned(proc.import_dll) then
+              begin
+                //WriteProcDef(proc);
+                list:=TAsmList.Create;
+                thlcgwasm(hlcg).g_procdef(list,proc);
+                WriteTree(list);
+                list.free;
+                writer.AsmWrite(#9'.import_module'#9);
+                writer.AsmWrite(proc.mangledname);
+                writer.AsmWrite(', ');
+                writer.AsmWriteLn(proc.import_dll^);
+                writer.AsmWrite(#9'.import_name'#9);
+                writer.AsmWrite(proc.mangledname);
+                writer.AsmWrite(', ');
+                writer.AsmWriteLn(proc.import_name^);
+              end;
+          end;
+      list:=TAsmList.Create;
+      cur_unit:=tused_unit(usedunits.First);
+      while assigned(cur_unit) do
+        begin
+          if (cur_unit.u.moduleflags * [mf_init,mf_finalize])<>[] then
+            begin
+              if mf_init in cur_unit.u.moduleflags then
+                list.Concat(tai_functype.create(make_mangledname('INIT$',cur_unit.u.globalsymtable,''),TWasmFuncType.Create([],[])));
+              if mf_finalize in cur_unit.u.moduleflags then
+                list.Concat(tai_functype.create(make_mangledname('FINALIZE$',cur_unit.u.globalsymtable,''),TWasmFuncType.Create([],[])));
+            end;
+          for i:=0 to cur_unit.u.deflist.Count-1 do
+            if assigned(cur_unit.u.deflist[i]) and (tdef(cur_unit.u.deflist[i]).typ = procdef) then
+              begin
+                proc := tprocdef(cur_unit.u.deflist[i]);
+                if (not proc.owner.iscurrentunit or (po_external in proc.procoptions)) and
+                   ((proc.paras.Count=0) or (proc.has_paraloc_info in [callerside,callbothsides])) then
+                  thlcgwasm(hlcg).g_procdef(list,proc);
+              end;
+          cur_unit:=tused_unit(cur_unit.Next);
+        end;
+      WriteTree(list);
+      list.free;
+    end;
+
+
+  function TLLVMMachineCodePlaygroundAssembler.sectionname(atype: TAsmSectiontype; const aname: string; aorder: TAsmSectionOrder): string;
+    begin
+      if (atype=sec_fpc) or (atype=sec_threadvar) then
+        atype:=sec_data;
+      Result:=inherited sectionname(atype, aname, aorder)+',"",@';
+    end;
+
+
+  constructor TLLVMMachineCodePlaygroundAssembler.CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+    begin
+      inherited;
+      InstrWriter:=TWASM32InstrWriter.create(self);
+    end;
+
+
+  procedure TLLVMMachineCodePlaygroundAssembler.WriteAsmList;
+    begin
+      inherited;
+      { print all global procedures/functions }
+      writer.AsmWriteLn(#9'.globaltype'#9+STACK_POINTER_SYM+', i32');
+      WriteImports;
+    end;
+
+
+  { TWASM32InstrWriter }
+
+
+  procedure TWASM32InstrWriter.WriteInstruction(hp: tai);
+
+    function getreferencestring(var ref : treference) : ansistring;
+      begin
+        if assigned(ref.symbol) then
+          begin
+            // global symbol or field -> full type and name
+            // ref.base can be <> NR_NO in case an instance field is loaded.
+            // This register is not part of this instruction, it will have
+            // been placed on the stack by the previous one.
+            result:=ref.symbol.name;
+            if ref.base<>NR_NO then
+              result:=result+'+'+std_regname(ref.base);
+            if ref.index<>NR_NO then
+              result:=result+'+'+std_regname(ref.index);
+            if ref.offset>0 then
+              result:=result+'+'+tostr(ref.offset)
+            else if ref.offset<0 then
+              result:=result+tostr(ref.offset);
+          end
+        else
+          begin
+            // local symbol -> stack slot, stored in offset
+            result:='';
+            if (ref.base<>NR_STACK_POINTER_REG) and (ref.base<>NR_NO) then
+              result:=std_regname(ref.base);
+            if ref.index<>NR_NO then
+              if result<>'' then
+                result:=result+'+'+std_regname(ref.index)
+              else
+                result:=std_regname(ref.index);
+            if ref.offset>0 then
+              begin
+                if result<>'' then
+                  result:=result+'+'+tostr(ref.offset)
+                else
+                  result:=tostr(ref.offset);
+              end
+            else if ref.offset<0 then
+              result:=result+tostr(ref.offset);
+            if result='' then
+              result:='0';
+          end;
+      end;
+
+    function constfloat(rawfloat: int64; fraction_bits, exponent_bits, exponent_bias: Integer): ansistring;
+      var
+        sign: boolean;
+        fraction: int64;
+        exponent, fraction_hexdigits: integer;
+      begin
+        fraction_hexdigits := (fraction_bits + 3) div 4;
+        sign:=(rawfloat shr (fraction_bits+exponent_bits))<>0;
+        fraction:=rawfloat and ((int64(1) shl fraction_bits)-1);
+        exponent:=(rawfloat shr fraction_bits) and ((1 shl exponent_bits)-1);
+        if sign then
+          result:='-'
+        else
+          result:='';
+        if (exponent=(1 shl exponent_bits)-1) then
+          begin
+            if fraction=0 then
+              result:=result+'inf'
+            else
+              begin
+                result:=result+'nan';
+                if fraction<>((int64(1) shl fraction_bits)-1) then
+                  result:=result+':0x'+HexStr(fraction,fraction_hexdigits);
+              end;
+          end
+        else
+          result:=result+'0x1.'+HexStr(fraction,fraction_hexdigits)+'p'+tostr(exponent-exponent_bias);
+      end;
+
+    function constsingle(s: single): ansistring;
+      type
+        tsingleval = record
+          case byte of
+            1: (s: single);
+            2: (i: longword);
+        end;
+      begin
+        result:=constfloat(tsingleval(s).i,23,8,127);
+      end;
+
+    function constdouble(d: double): ansistring;
+      type
+        tdoubleval = record
+          case byte of
+            1: (d: double);
+            2: (i: int64);
+        end;
+      begin
+        result:=constfloat(tdoubleval(d).i,52,11,1023);
+      end;
+
+    function getopstr(const o:toper) : ansistring;
+      var
+        d: double;
+        s: single;
+      begin
+        case o.typ of
+          top_reg:
+            // should have been translated into a memory location by the
+            // register allocator)
+            if (cs_no_regalloc in current_settings.globalswitches) then
+              getopstr:=std_regname(o.reg)
+            else
+              internalerror(2010122803);
+          top_const:
+            str(o.val,result);
+          top_ref:
+            getopstr:=getreferencestring(o.ref^);
+          top_single:
+            begin
+              result:=constsingle(o.sval);
+            end;
+          top_double:
+            begin
+              result:=constdouble(o.dval);
+            end;
+          {top_string:
+            begin
+              result:=constastr(o.pcval,o.pcvallen);
+            end;
+          top_wstring:
+            begin
+              result:=constwstr(o.pwstrval^.data,getlengthwidestring(o.pwstrval));
+            end}
+          else
+            internalerror(2010122802);
+        end;
+      end;
+
+    var
+      cpu : taicpu;
+      i   : integer;
+      writer: TExternalAssemblerOutputFile;
+    begin
+      writer:=owner.writer;
+      cpu := taicpu(hp);
+      writer.AsmWrite(#9#9);
+      writer.AsmWrite(gas_op2str[cpu.opcode]);
+
+      if cpu.ops<>0 then
+        begin
+          for i:=0 to cpu.ops-1 do
+            begin
+              writer.AsmWrite(#9);
+              if cpu.oper[i]^.typ=top_functype then
+                owner.WriteFuncType(cpu.oper[i]^.functype)
+              else
+                writer.AsmWrite(getopstr(cpu.oper[i]^));
+            end;
+        end;
+      writer.AsmLn;
+    end;
+
+
+  const
+    as_wasm32_llvm_mc_info : tasminfo =
+       (
+         id     : as_wasm32_llvm_mc;
+         idtxt  : 'LLVM-MC';
+         asmbin : 'llvm-mc';
+         asmcmd : '--assemble --arch=wasm32 -mattr=+sign-ext --filetype=obj -o $OBJ $EXTRAOPT $ASM';
+         supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
+         flags : [af_smartlink_sections];
+         labelprefix : '.L';
+         labelmaxlen : -1;
+         comment : '# ';
+         dollarsign : '$';
+       );
+
+initialization
+  RegisterAssembler(as_wasm32_llvm_mc_info,TLLVMMachineCodePlaygroundAssembler);
+end.
+

+ 1107 - 0
compiler/wasm32/agwat.pas

@@ -0,0 +1,1107 @@
+{
+    Copyright (c) 1998-2010 by the Free Pascal team
+
+    This unit implements the WebAssembly text assembler
+    The text is in S-expression format and should be consumable
+    By either Binaryen or Wabt
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit agwat;
+
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    cclasses,systems, cgutils,
+    globtype,globals,
+    symconst,symbase,symdef,symsym, symtype,symcpu,
+    aasmbase,aasmtai,aasmdata,aasmcpu,
+    assemble
+    ,cutils
+    ,cpubase, cgbase
+    ,fmodule
+    ,verbose, itcpuwasm
+    ,cfileutl, tgcpu;
+
+  type
+     TWatInstrWriter = class;
+
+     {# This is a derived class which is used to write
+        Binaryen-styled assembler.
+     }
+
+     { TWatAssembler }
+
+     { TWabtTextAssembler }
+
+     TWabtTextAssembler=class(texternalassembler)
+     protected
+       dataofs  : integer;
+
+       procedure WriteOutGlobalInt32(const aname: string; val: integer; isconst: boolean = true);
+
+       procedure WriteInstruction(hp: tai);
+       procedure WriteProcDef(pd: tprocdef; stub: Boolean = false; stubUnreachable: Boolean = true);
+       procedure WriteProcParams(pd: tprocdef);
+       procedure WriteProcResult(pd: tprocdef);
+       procedure WriteSymtableProcdefs(st: TSymtable);
+       procedure WriteSymtableVarSyms(st: TSymtable);
+       procedure WriteTempAlloc(p:TAsmList);
+       procedure WriteExports(p: TAsmList);
+       procedure WriteUnitExports(st: TSymtable);
+       procedure WriteImports;
+
+       procedure WriteOutPChar(p: pchar; ofs, len: integer);
+       procedure WriteConstString(lbl: tai_label; str: tai_string);
+       procedure WriteConstants(p: TAsmList);
+     public
+       constructor CreateWithWriter(info: pasminfo; wr: TExternalAssemblerOutputFile; freewriter, smart: boolean); override;
+       procedure WriteTree(p:TAsmList);override;
+       procedure WriteAsmList;override;
+       Function  DoAssemble:boolean;override;
+     end;
+
+
+     {# This is the base class for writing instructions.
+
+        The WriteInstruction() method must be overridden
+        to write a single instruction to the assembler
+        file.
+     }
+
+     { TBinaryenInstrWriter }
+
+     { TWatInstrWriter }
+
+     TWatInstrWriter = class
+       constructor create(_owner: TWabtTextAssembler);
+       procedure WriteInstruction(hp : tai); virtual;
+      protected
+       owner: TWabtTextAssembler;
+     end;
+
+implementation
+
+    type
+      t64bitarray = array[0..7] of byte;
+      t32bitarray = array[0..3] of byte;
+
+
+    const
+      line_length = 70;
+
+  {****************************************************************************}
+  {                          Support routines                                  }
+  {****************************************************************************}
+
+     function fixline(s:string):string;
+     {
+       return s with all leading and ending spaces and tabs removed
+     }
+       var
+         i,j,k : integer;
+       begin
+         i:=length(s);
+         while (i>0) and (s[i] in [#9,' ']) do
+          dec(i);
+         j:=1;
+         while (j<i) and (s[j] in [#9,' ']) do
+          inc(j);
+         for k:=j to i do
+          if s[k] in [#0..#31,#127..#255] then
+           s[k]:='.';
+         fixline:=Copy(s,j,i-j+1);
+       end;
+
+     function GetWasmName(const st: TSymStr): ansistring;
+     begin
+       Result := '$'+st;
+       Replace(Result, '(','');
+       Replace(Result, ')','');
+     end;
+
+     function getreferencestring(var ref : treference) : ansistring;
+       begin
+         if (ref.index<>NR_NO) then
+           internalerror(2010122809);
+         if assigned(ref.symbol) then
+           begin
+             // global symbol or field -> full type and name
+             // ref.base can be <> NR_NO in case an instance field is loaded.
+             // This register is not part of this instruction, it will have
+             // been placed on the stack by the previous one.
+             result:=GetWasmName(ref.symbol.name);
+           end
+         else
+           begin
+             // local symbol -> stack slot, stored in offset
+             if ref.base<>NR_STACK_POINTER_REG then
+               internalerror(2010122810);
+             result:=tostr(ref.offset);
+           end;
+       end;
+
+     function constsingle(s: single): ansistring;
+       begin
+         // wat2wasm is using strtof() internally
+         str(s, result); //'0x'+hexstr(longint(t32bitarray(s)),8);
+       end;
+
+     function constdouble(d: double): ansistring;
+        begin
+          // force interpretation as double (since we write it out as an
+          // integer, we never have to swap the endianess). We have to
+          // include the sign separately because of the way Java parses
+          // hex numbers (0x8000000000000000 is not a valid long)
+          //result:=hexstr(abs(int64(t64bitarray(d))),16);
+          //if int64(t64bitarray(d))<0 then
+          //  result:='-'+result;
+          //result:='0dx'+result;
+          str(d, result);
+        end;
+
+    function getopstr(const o:toper) : ansistring;
+      var
+        d: double;
+        s: single;
+      begin
+        case o.typ of
+          top_reg:
+            // should have been translated into a memory location by the
+            // register allocator)
+            if (cs_no_regalloc in current_settings.globalswitches) then
+              getopstr:=std_regname(o.reg)
+            else
+              internalerror(2010122803);
+          top_const:
+            str(o.val,result);
+          top_ref:
+            getopstr:=getreferencestring(o.ref^);
+          top_single:
+            begin
+              result:=constsingle(o.sval);
+            end;
+          top_double:
+            begin
+              result:=constdouble(o.dval);
+            end;
+          {top_string:
+            begin
+              result:=constastr(o.pcval,o.pcvallen);
+            end;
+          top_wstring:
+            begin
+              result:=constwstr(o.pwstrval^.data,getlengthwidestring(o.pwstrval));
+            end}
+          else
+            internalerror(2010122802);
+        end;
+      end;
+
+  { TWabtTextAssembler }
+
+                procedure TWabtTextAssembler.WriteOutGlobalInt32(const aname: string;
+          val: integer; isconst: boolean);
+          begin
+             writer.AsmWrite(#9);
+             writer.AsmWrite('(global $');
+             writer.AsmWrite(aname);
+             if not isconst then
+               writer.AsmWrite(' (mut i32)')
+             else
+               writer.AsmWrite(' i32');
+             writer.AsmWrite(' (i32.const ');
+             writer.AsmWrite( tostr(val));
+             writer.AsmWrite(')');
+             writer.AsmWriteLn(')');
+          end;
+
+    procedure TWabtTextAssembler.WriteInstruction(hp: tai);
+    var
+      cpu : taicpu;
+      i   : integer;
+      isprm : boolean;
+    begin
+      //writer.AsmWriteLn('instr');
+      cpu := taicpu(hp);
+      writer.AsmWrite(#9#9);
+      writer.AsmWrite(wasm_op2str[cpu.opcode] );
+
+      if (cpu.opcode = a_call_indirect) then begin
+        // special wat2wasm syntax "call_indirect (type x)"
+        writer.AsmWrite(#9);
+        // todo: fix
+        //isprm := true;
+        //for i:=1 to length(cpu.typecode) do
+        //  if cpu.typecode[i]=':' then
+        //     isprm:=false
+        //  else begin
+        //    if isprm then writer.AsmWrite('(param ')
+        //    else writer.AsmWrite('(result ');
+        //    case cpu.typecode[i] of
+        //      'i': writer.AsmWrite('i32');
+        //      'I': writer.AsmWrite('i64');
+        //      'f': writer.AsmWrite('f32');
+        //      'F': writer.AsmWrite('f64');
+        //    end;
+        //    writer.AsmWrite(')');
+        //  end;
+        writer.AsmLn;
+        exit;
+      end;
+
+
+      if (cpu.opcode = a_if)  then
+        writer.AsmWrite(' (result i32)') //todo: this is a hardcode, but shouldn't
+      else
+
+      cpu := taicpu(hp);
+      if cpu.ops<>0 then
+        begin
+          for i:=0 to cpu.ops-1 do
+            begin
+              writer.AsmWrite(#9);
+
+              if (cpu.opcode in AsmOp_LoadStore) and (cpu.oper[i]^.typ = top_ref) then
+                writer.AsmWrite('offset='+tostr( cpu.oper[i]^.ref^.offset))
+              else
+                writer.AsmWrite(getopstr(cpu.oper[i]^));
+
+            end;
+        end;
+
+      if (cpu.opcode = a_call_indirect) then
+        // special wat2wasm syntax "call_indirect (type x)"
+        writer.AsmWrite(')');
+
+      writer.AsmLn;
+    end;
+
+    procedure TWabtTextAssembler.WriteProcDef(pd: tprocdef; stub: Boolean; stubUnreachable: Boolean);
+    var
+      i : integer;
+    begin
+      if not assigned(tcpuprocdef(pd).exprasmlist) and
+         not(po_abstractmethod in pd.procoptions) and
+         ((pd.proctypeoption in [potype_unitinit,potype_unitfinalize])) then
+      begin
+        exit;
+      end;
+
+      writer.AsmWriteLn('');
+      if stub and stubUnreachable then begin
+        writer.AsmWriteLn(#9';;.weak');
+      end;
+
+      writer.AsmWrite(#9'(func ');
+
+      writer.AsmWrite( GetWasmName( pd.mangledname ));
+      //procsym.RealName ));
+      //writer.AsmWriteln(MethodDefinition(pd));
+      {if jvmtypeneedssignature(pd) then
+        begin
+          writer.AsmWrite('.signature "');
+          writer.AsmWrite(tcpuprocdef(pd).jvmmangledbasename(true));
+          writer.AsmWriteln('"');
+        end;}
+      writer.AsmLn;
+      WriteProcParams(pd);
+      WriteProcResult(pd);
+
+      if not stub then begin
+        //WriteTempAlloc(tcpuprocdef(pd).exprasmlist);
+        WriteTree(tcpuprocdef(pd).exprasmlist);
+      end else begin
+        if stubUnreachable then
+          writer.AsmWriteLn(#9#9'unreachable');
+      end;
+      writer.AsmWriteln(#9')');
+      writer.AsmLn;
+    end;
+
+    procedure TWabtTextAssembler.WriteProcParams(pd: tprocdef);
+      var
+        i : integer;
+        prm : tcpuparavarsym;
+      begin
+        if not Assigned(pd) or
+           not Assigned(pd.paras) or
+           (pd.paras.Count=0) then
+          exit;
+
+        for i:=0 to pd.paras.Count-1 do
+          begin
+            prm := tcpuparavarsym(pd.paras[i]);
+            writer.AsmWrite(#9#9'(param'#9);
+            case prm.paraloc[callerside].Size of
+              OS_8..OS_32, OS_S8..OS_S32:
+                writer.AsmWrite('i32');
+              OS_64, OS_S64:
+                writer.AsmWrite('i64');
+              OS_F32:
+                writer.AsmWrite('f32');
+              OS_F64:
+                writer.AsmWrite('f64');
+            else
+              // unsupported calleeside parameter type
+              Internalerror(2019093001);
+            end;
+            writer.AsmWrite(')');
+            writer.AsmLn;
+          end;
+      end;
+
+    procedure TWabtTextAssembler.WriteProcResult(pd: tprocdef);
+      var
+        bt : TWasmBasicType;
+      begin
+        if not assigned(pd) or
+          not Assigned(pd.returndef) or
+          (pd.returndef.size = 0)
+          then exit;
+
+        if not defToWasmBasic(pd.returndef, bt) then
+          bt := wbt_i32;
+
+        writer.AsmWrite(#9#9'(result'#9);
+        case bt of
+          wbt_i64: writer.AsmWrite('i64');
+          wbt_f32: writer.AsmWrite('f32');
+          wbt_f64: writer.AsmWrite('f64');
+        else
+          writer.AsmWrite('i32');
+        end;
+        writer.AsmWrite(')');
+        writer.AsmLn;
+      end;
+
+    procedure TWabtTextAssembler.WriteTree(p: TAsmList);
+      var
+        ch       : char;
+        hp       : tai;
+        hp1      : tailineinfo;
+        s        : ansistring;
+        i,pos    : longint;
+        InlineLevel : longint;
+        do_line  : boolean;
+      const
+        WasmBasicTypeStr : array [TWasmBasicType] of string = ('i32','i64','f32','f64');
+
+      begin
+        if not assigned(p) then
+         exit;
+
+        InlineLevel:=0;
+        { lineinfo is only needed for al_procedures (PFV) }
+        do_line:=(cs_asm_source in current_settings.globalswitches);
+        hp:=tai(p.first);
+        while assigned(hp) do
+         begin
+           prefetch(pointer(hp.next)^);
+           if not(hp.typ in SkipLineInfo) then
+            begin
+              hp1 := hp as tailineinfo;
+              current_filepos:=hp1.fileinfo;
+               { no line info for inlined code }
+               if do_line and (inlinelevel=0) then
+                begin
+                  { load infile }
+                  if lastfileinfo.fileindex<>hp1.fileinfo.fileindex then
+                   begin
+                     infile:=current_module.sourcefiles.get_file(hp1.fileinfo.fileindex);
+                     if assigned(infile) then
+                      begin
+                        { open only if needed !! }
+                        if (cs_asm_source in current_settings.globalswitches) then
+                         infile.open;
+                      end;
+                     { avoid unnecessary reopens of the same file !! }
+                     lastfileinfo.fileindex:=hp1.fileinfo.fileindex;
+                     { be sure to change line !! }
+                     lastfileinfo.line:=-1;
+                   end;
+
+                { write source }
+                  if (cs_asm_source in current_settings.globalswitches) and
+                     assigned(infile) then
+                   begin
+                     if (infile<>lastinfile) then
+                       begin
+                         writer.AsmWriteLn(asminfo^.comment+'['+infile.name+']');
+                         if assigned(lastinfile) then
+                           lastinfile.close;
+                       end;
+                     if (hp1.fileinfo.line<>lastfileinfo.line) and
+                        ((hp1.fileinfo.line<infile.maxlinebuf) or (InlineLevel>0)) then
+                       begin
+                         if (hp1.fileinfo.line<>0) and
+                            ((infile.linebuf^[hp1.fileinfo.line]>=0) or (InlineLevel>0)) then
+                           writer.AsmWriteLn(asminfo^.comment+'['+tostr(hp1.fileinfo.line)+'] '+
+                             fixline(infile.GetLineStr(hp1.fileinfo.line)));
+                         { set it to a negative value !
+                         to make that is has been read already !! PM }
+                         if (infile.linebuf^[hp1.fileinfo.line]>=0) then
+                           infile.linebuf^[hp1.fileinfo.line]:=-infile.linebuf^[hp1.fileinfo.line]-1;
+                       end;
+                   end;
+                  lastfileinfo:=hp1.fileinfo;
+                  lastinfile:=infile;
+                end;
+            end;
+
+           case hp.typ of
+
+             ait_comment :
+               Begin
+                 writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWritePChar(tai_comment(hp).str);
+                 writer.AsmLn;
+               End;
+
+             ait_regalloc :
+               begin
+                 if (cs_asm_regalloc in current_settings.globalswitches) then
+                   begin
+                     writer.AsmWrite(#9+asminfo^.comment+'Register ');
+                     repeat
+                       writer.AsmWrite(std_regname(Tai_regalloc(hp).reg));
+                       if (hp.next=nil) or
+                          (tai(hp.next).typ<>ait_regalloc) or
+                          (tai_regalloc(hp.next).ratype<>tai_regalloc(hp).ratype) then
+                         break;
+                       hp:=tai(hp.next);
+                       writer.AsmWrite(',');
+                     until false;
+                     writer.AsmWrite(' ');
+                     writer.AsmWriteLn(regallocstr[tai_regalloc(hp).ratype]);
+                   end;
+               end;
+
+             ait_tempalloc :
+               begin
+                 if (cs_asm_tempalloc in current_settings.globalswitches) then
+                   begin
+  {$ifdef EXTDEBUG}
+                     if assigned(tai_tempalloc(hp).problem) then
+                       writer.AsmWriteLn(asminfo^.comment+'Temp '+tostr(tai_tempalloc(hp).temppos)+','+
+                         tostr(tai_tempalloc(hp).tempsize)+' '+tai_tempalloc(hp).problem^)
+                     else
+  {$endif EXTDEBUG}
+                   end;
+               end;
+
+             ait_align :
+               begin
+
+               end;
+
+             ait_section :
+               begin
+
+               end;
+
+             ait_datablock :
+               begin
+//                 internalerror(2010122701);
+               end;
+
+             ait_const:
+               begin
+                 writer.AsmWriteln('constant');
+//                 internalerror(2010122702);
+               end;
+
+             ait_realconst :
+               begin
+                 internalerror(2010122703);
+               end;
+
+             ait_string :
+               begin
+                 pos:=0;
+                  for i:=1 to tai_string(hp).len do
+                   begin
+                     if pos=0 then
+                      begin
+                        writer.AsmWrite(#9'strconst: '#9'"');
+                        pos:=20;
+                      end;
+                     ch:=tai_string(hp).str[i-1];
+                     case ch of
+                        #0, {This can't be done by range, because a bug in FPC}
+                   #1..#31,
+                #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                       '"' : s:='\"';
+                       '\' : s:='\\';
+                     else
+                      s:=ch;
+                     end;
+                     writer.AsmWrite(s);
+                     inc(pos,length(s));
+                     if (pos>line_length) or (i=tai_string(hp).len) then
+                      begin
+                        writer.AsmWriteLn('"');
+                        pos:=0;
+                      end;
+                   end;
+               end;
+
+             ait_label :
+               begin
+                 // don't write any labels. Wasm don't support it
+                 // labels are only allowed with the respective block structures
+               end;
+
+             ait_symbol :
+               begin
+                  if (tai_symbol(hp).sym.typ = AT_FUNCTION) then
+                    begin
+                    end
+                  else
+                   begin
+                     writer.AsmWrite('data symbol: ');
+                     writer.AsmWriteln(tai_symbol(hp).sym.name);
+//                     internalerror(2010122706);
+                   end;
+               end;
+             ait_symbol_end :
+               begin
+               end;
+
+             ait_instruction :
+               begin
+                 WriteInstruction(hp);
+               end;
+
+             ait_force_line,
+             ait_function_name : ;
+
+             ait_cutobject :
+               begin
+               end;
+
+             ait_marker :
+               if tai_marker(hp).kind=mark_NoLineInfoStart then
+                 inc(InlineLevel)
+               else if tai_marker(hp).kind=mark_NoLineInfoEnd then
+                 dec(InlineLevel);
+
+             ait_directive :
+               begin
+                 { the CPU directive is probably not supported by the JVM assembler,
+                   so it's commented out }
+
+                 //todo:
+                 writer.AsmWrite(asminfo^.comment);
+
+                 if tai_directive(hp).directive=asd_cpu then
+                   writer.AsmWrite(asminfo^.comment);
+                 writer.AsmWrite('.'+directivestr[tai_directive(hp).directive]+' ');
+                 if tai_directive(hp).name<>'' then
+                   writer.AsmWrite(tai_directive(hp).name);
+                 writer.AsmLn;
+               end;
+
+             ait_local :
+               begin
+                 writer.AsmWrite(#9#9'(local ');
+                 if tai_local(hp).name <> '' then
+                   begin
+                     writer.AsmWrite(' ');
+                     writer.AsmWrite(tai_local(hp).name);
+                     writer.AsmWrite(' ');
+                   end;
+                 writer.AsmWrite( WasmBasicTypeStr[ tai_local(hp).bastyp ] );
+                 writer.AsmWrite(')');
+                 writer.AsmLn;
+               end;
+
+             else
+               internalerror(2010122707);
+           end;
+           hp:=tai(hp.next);
+         end;
+    end;
+
+    procedure TWabtTextAssembler.WriteAsmList;
+      var
+        hal : tasmlisttype;
+      begin
+        writer.MarkEmpty;
+        writer.AsmWriteLn('(module ');
+        writer.AsmWriteLn('(import "env" "memory" (memory 0)) ;;');
+        WriteImports;
+        WriteConstants(current_asmdata.asmlists[al_const]);
+        WriteConstants(current_asmdata.asmlists[al_typedconsts]);
+
+        //current_asmdata.CurrAsmList.labe
+
+        { print all global variables }
+        //current_asmdata.AsmSymbolDict
+
+        // for every unit __stack_top is a weak symbol
+        // __stack_top is strong only for libraries or programs.
+        if current_module.is_unit then
+          writer.AsmWriteLn(#9';;.weak');
+        writer.AsmWrite(#9'(global $__stack_top (mut i32) (i32.const ');
+        writer.AsmWrite(tostr(globals.stacksize));
+        writer.AsmWriteLn('))');
+
+        WriteSymtableVarSyms(current_module.globalsymtable);
+        WriteSymtableVarSyms(current_module.localsymtable);
+
+        //writer.AsmLn;
+        { print all global procedures/functions }
+        WriteSymtableProcdefs(current_module.globalsymtable);
+        WriteSymtableProcdefs(current_module.localsymtable);
+
+        if current_module.islibrary then begin
+          WriteExports(current_asmdata.asmlists[al_exports]);
+        end else
+          WriteUnitExports(current_module.globalsymtable);
+
+        //WriteSymtableStructDefs(current_module.globalsymtable);
+        //WriteSymtableStructDefs(current_module.localsymtable);
+        //writer.decorator.LinePrefix := '';
+        writer.AsmWriteLn(')');
+
+        writer.AsmLn;
+      end;
+
+    function TWabtTextAssembler.DoAssemble: boolean;
+    var
+      t : tcmdstr;
+      begin
+        Result:=inherited DoAssemble;
+        // the tool updates the symbol flags, so the linker
+        // is capable of producing an executable
+        if Result then
+          if FindExe('wasmtool',true,t) then begin
+            if current_module.is_unit then
+              // making "common" global variables a week reference
+              RequotedExecuteProcess(t,' --weak "$__stack_top" --symbolauto '+ObjFileName)
+            else
+              RequotedExecuteProcess(t,' --symbolauto '+ObjFileName)
+          end
+          else
+            Message1(exec_e_util_not_found,'wasmtool');
+      end;
+
+    constructor TWabtTextAssembler.CreateWithWriter(info: pasminfo;
+      wr: TExternalAssemblerOutputFile; freewriter, smart: boolean);
+      begin
+        inherited CreateWithWriter(info, wr, freewriter, smart);
+      end;
+
+    procedure TWabtTextAssembler.WriteSymtableProcdefs(st: TSymtable);
+      var
+        i   : longint;
+        def : tdef;
+      begin
+        if not assigned(st) then
+          exit;
+        for i:=0 to st.DefList.Count-1 do
+          begin
+            def:=tdef(st.DefList[i]);
+            case def.typ of
+              procdef :
+                begin
+                  { methods are also in the static/globalsymtable of the unit
+                    -> make sure they are only written for the objectdefs that
+                    own them }
+                  if (not(st.symtabletype in [staticsymtable,globalsymtable]) or
+                      (def.owner=st)) and
+                     not(df_generic in def.defoptions) and
+                     not (po_external in tprocdef(def).procoptions)
+                     then
+                    begin
+                      WriteProcDef(tprocdef(def));
+                      if assigned(tprocdef(def).localst) then
+                        WriteSymtableProcdefs(tprocdef(def).localst);
+                    end;
+                end;
+              else
+                ;
+            end;
+          end;
+      end;
+
+    procedure TWabtTextAssembler.WriteSymtableVarSyms(st: TSymtable);
+      var
+        i : integer;
+        sym : tsym;
+      begin
+        if not assigned(st) then
+          exit;
+
+        for i:=0 to st.SymList.Count-1 do
+         begin
+           sym:=tsym(st.SymList[i]);
+           case sym.typ of
+             staticvarsym:
+               begin
+                 //WriteFieldSym(tabstractvarsym(sym));
+                 //if (sym.typ=staticvarsym) and
+                 //   assigned(tstaticvarsym(sym).defaultconstsym) then
+                 //  WriteFieldSym(tabstractvarsym(tstaticvarsym(sym).defaultconstsym));
+                 WriteOutGlobalInt32(tcpustaticvarsym(sym).mangledname, dataofs);
+                 inc(dataofs, tcpustaticvarsym(sym).getsize);
+               end;
+             fieldvarsym:
+               begin
+                 writer.AsmWriteLn(';; field');
+               end;
+             constsym:
+               begin
+                 //if (sym.typ=staticvarsym) and
+                 //   assigned(tstaticvarsym(sym).defaultconstsym) then
+                 //  WriteFieldSym(tabstractvarsym(tstaticvarsym(sym).defaultconstsym));
+                 //{ multiple procedures can have constants with the same name }
+                 //if not assigned(sym.owner.defowner) or
+                 //   (tdef(sym.owner.defowner).typ<>procdef) then
+                 //  WriteConstSym(tconstsym(sym));
+                 writer.AsmWriteLn(';; constant');
+               end;
+             {procsym:
+               begin
+                 for j:=0 to tprocsym(sym).procdeflist.count-1 do
+                   if not(df_generic in tprocdef(tprocsym(sym).procdeflist[j]).defoptions) then
+                     WriteSymtableVarSyms(tprocdef(tprocsym(sym).procdeflist[j]).localst);
+               end;}
+             else
+               ;
+           end;
+         end;
+      end;
+
+    procedure TWabtTextAssembler.WriteTempAlloc(p: TAsmList);
+      var
+        hp: tai;
+        tmp: array of tai_tempalloc;
+        mx : integer;
+        i  : integer;
+      begin
+        if not assigned(p) then
+         exit;
+
+        mx := -1;
+        hp:=tai(p.first);
+        while assigned(hp) do
+         begin
+           //prefetch(pointer(hp.next)^);
+           if (hp.typ = ait_tempalloc) and
+             tai_tempalloc(hp).allocation and
+             (tai_tempalloc(hp).temppos >= mx) then
+               mx := tai_tempalloc(hp).temppos+1;
+
+           hp:=tai(hp.next);
+         end;
+
+        if (mx <= 0) then exit; // no temp allocations used
+
+        SetLength(tmp, mx);
+
+        hp:=tai(p.first);
+        while assigned(hp) do
+          begin
+            //prefetch(pointer(hp.next)^);
+
+            if (hp.typ = ait_tempalloc) and
+              (tai_tempalloc(hp).allocation) and
+              (tmp[ tai_tempalloc(hp).temppos ] = nil) then
+              begin
+                tmp[ tai_tempalloc(hp).temppos ] := tai_tempalloc(hp);
+                dec(mx);
+                if mx = 0 then break;
+              end;
+            hp:=tai(hp.next);
+          end;
+
+        for i:=0 to length(tmp)-1 do
+          begin
+            if tmp[i] = nil then continue;
+            writer.AsmWrite(#9'(local'#9);
+            if tmp[i].tempsize<=4 then writer.AsmWrite('i32')
+            else if tmp[i].tempsize = 8 then writer.AsmWrite('i64');
+            writer.AsmWrite(')');
+
+            writer.AsmWrite(#9+asminfo^.comment+'Temp '+tostr(tmp[i].temppos)+','+
+              tostr(tmp[i].tempsize)+' '+tempallocstr[tmp[i].allocation]);
+
+            writer.AsmLn;
+          end;
+
+      end;
+
+    procedure TWabtTextAssembler.WriteExports(p: TAsmList);
+    var
+      hp: tai;
+      x: tai_impexp;
+      cnt: integer;
+    begin
+      if not Assigned(p) then Exit;
+      hp:=tai(p.First);
+      if not Assigned(hp) then Exit;
+
+      cnt := 0;
+      while Assigned(hp) do begin
+        case hp.typ of
+          ait_importexport:
+            inc(cnt);
+          else
+            ;
+        end;
+        hp := tai_impexp(hp.Next);
+      end;
+
+      // writting out table, so wat2wasm can create reallocation symbols
+
+      writer.AsmWrite(#9'(table ');
+      writer.AsmWrite(tostr(cnt));
+      writer.AsmWrite(' anyfunc)');
+      writer.AsmWriteLn(#9'(elem 0 (i32.const 0) ');
+      hp:=tai(p.First);
+      while Assigned(hp) do begin
+        case hp.typ of
+          ait_importexport:
+          begin
+            x:=tai_impexp(hp);
+            writer.AsmWrite(#9#9);
+            writer.AsmWriteLn(GetWasmName(x.intname));
+          end;
+          else
+            ;
+        end;
+        hp := tai_impexp(hp.Next);
+      end;
+      writer.AsmWriteLn(#9') ');
+
+      // writing export sections
+      hp:=tai(p.First);
+      while Assigned(hp) do begin
+        case hp.typ of
+          ait_importexport:
+          begin
+            x:=tai_impexp(hp);
+            writer.AsmWrite(#9#9'(export "');
+            writer.AsmWrite(x.extname);
+            writer.AsmWrite('" (');
+            case x.symstype of
+              ie_Func: writer.AsmWrite('func');
+              else
+                ;
+            end;
+            writer.AsmWrite(' ');
+            writer.AsmWrite(GetWasmName(x.intname));
+            writer.AsmWrite('))');
+            writer.AsmLn;
+          end;
+          else
+            ;
+        end;
+        hp := tai_impexp(hp.Next);
+      end;
+    end;
+
+    procedure TWabtTextAssembler.WriteUnitExports(st: TSymtable);
+    var
+      i   : longint;
+      def : tdef;
+    begin
+      if not assigned(st) then
+        exit;
+
+      writer.AsmWrite(#9'(table 0 funcref)');
+      writer.AsmWriteLn(#9'(elem 0 (i32.const 0) ');
+      for i:=0 to st.DefList.Count-1 do
+        begin
+          def:=tdef(st.DefList[i]);
+          case def.typ of
+            procdef :
+              begin
+                { methods are also in the static/globalsymtable of the unit
+                  -> make sure they are only written for the objectdefs that
+                  own them }
+                  if
+                   not (po_external in tprocdef(def).procoptions)
+                   then
+                  begin
+                    writer.AsmWrite(#9#9'$');
+                    writer.AsmWriteLn(tprocdef(def).mangledname);
+                  end;
+              end;
+            else
+              ;
+          end;
+        end;
+      writer.AsmWriteLn(#9') ');
+    end;
+
+    procedure TWabtTextAssembler.WriteImports;
+      var
+        i    : integer;
+        proc : tprocdef;
+        sym  : tsym;
+        j    : integer;
+        psym : tprocsym;
+      begin
+        for i:=0 to current_module.deflist.Count-1 do begin
+          if tdef(current_module.deflist[i]).typ = procdef then begin
+            proc := tprocdef(current_module.deflist[i]);
+            if (po_external in proc.procoptions) and assigned(proc.import_dll) then begin
+              writer.AsmWrite(#9'(import "');
+              writer.AsmWrite(proc.import_dll^);
+              writer.AsmWrite('" "');
+              writer.AsmWrite(proc.import_name^);
+              writer.AsmWrite('" ');
+              WriteProcDef(proc);
+              writer.AsmWriteLn(')');
+            end;
+          end;
+        end;
+
+        // any symbol used from another unit must be fully declared in .wat
+        // (reference by symbol name only doesn't work in Wasm)
+        // the entire entry should declared (as imported) symbol.
+        // The wasm-import name (name of exernal module and name)
+        // is not important, as the linker would be using the symbol name
+        // while linking.
+        for i:=0 to current_module.unitimportsyms.Count-1 do begin
+          sym := tsym(current_module.unitimportsyms[i]);
+          if sym.typ = procsym then begin
+            psym := tprocsym(sym);
+            if psym.ProcdefList.Count>0 then
+              proc := tprocdef(psym.ProcdefList[0])
+            else
+              proc := nil;
+            if proc<>nil then begin
+              {writer.AsmWrite(#9'(import "_fpc_use" "');
+              writer.AsmWrite(proc.mangledname);
+              writer.AsmWrite('" ');}
+              WriteProcDef(proc, true);
+              //writer.AsmWrite(')');
+            end;
+          end;
+        end;
+      end;
+
+
+    procedure TWabtTextAssembler.WriteOutPChar(p: pchar; ofs, len: integer);
+        var
+          i : integer;
+          s : string;
+          ch : char;
+        begin
+          for i:=ofs to ofs+len-1 do begin
+               ch:=p[i];
+               case ch of
+                #0, {This can't be done by range, because a bug in FPC}
+                #1..#31,
+                #128..#255 : s:='\'+tostr(ord(ch) shr 6)+tostr((ord(ch) and 63) shr 3)+tostr(ord(ch) and 7);
+                '"' : s:='\"';
+                '\' : s:='\\';
+                else
+                  s:=ch;
+                end;
+                writer.AsmWrite(s);
+            end;
+        end;
+
+        procedure TWabtTextAssembler.WriteConstString(lbl: tai_label;
+            str: tai_string);
+          var
+            i : integer;
+            ch : char;
+            s : string;
+          begin
+            WriteOutGlobalInt32(lbl.labsym.Name, dataofs);
+            // (data (get_global $test) "00")
+            writer.AsmWrite(#9);
+            writer.AsmWrite('(data (i32.const ');
+            writer.AsmWrite(tostr(dataOfs));
+            writer.AsmWrite(') "');
+            // can be broken apart in multiple data() if needs to be
+            WriteOutPChar(str.str, 0, str.len);
+            writer.AsmWrite('"');
+            writer.AsmWriteLn(') ;; value of '+ lbl.labsym.Name);
+            inc(dataofs, str.len);
+          end;
+
+    procedure TWabtTextAssembler.WriteConstants(p: TAsmList);
+      var
+        i : integer;
+        hp : tai;
+        dt : tai;
+      begin
+        //WriteTree(p);
+        hp:=tai(p.First);
+        while Assigned(hp) do begin
+          if (hp.typ = ait_label) then begin
+            dt:=tai(hp.Next);
+            if Assigned(dt) then begin
+              case dt.typ of
+                ait_string:
+                begin
+                  WriteConstString(tai_label(hp), tai_string(dt));
+                  hp:=dt;
+                end;
+                else
+                  ;
+              end;
+            end;
+          end;
+          hp:=tai(hp.Next);
+        end;
+      end;
+
+
+{ TWatInstrWriter }
+
+  constructor TWatInstrWriter.create(_owner: TWabtTextAssembler);
+    begin
+      inherited create;
+      owner := _owner;
+    end;
+
+  procedure TWatInstrWriter.WriteInstruction(hp: tai);
+    begin
+
+    end;
+
+
+  const
+    as_wasm_wabt_info : tasminfo =
+       (
+         id     : as_wasm32_wabt;
+         idtxt  : 'WABT';
+         asmbin : 'wasa';
+         asmcmd : '-r --no-canonicalize-leb128s -o $OBJ $EXTRAOPT $ASM';
+         supported_targets : [system_wasm32_embedded,system_wasm32_wasi];
+         flags : [];
+         labelprefix : 'L';
+         labelmaxlen : -1;
+         comment : ';; ';
+         dollarsign : '$';
+       );
+
+initialization
+  RegisterAssembler(as_wasm_wabt_info, TWabtTextAssembler);
+
+end.

+ 18 - 0
compiler/wasm32/ccpuinnr.inc

@@ -0,0 +1,18 @@
+{
+
+    This file is part of the Free Pascal run time library.
+    Copyright (c) 2021 by the Free Pascal development team.
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+  in_wasm32_memory_size = in_cpu_first,
+  in_wasm32_memory_grow = in_cpu_first+1,
+  in_wasm32_unreachable = in_cpu_first+2
+

+ 129 - 0
compiler/wasm32/cgcpu.pas

@@ -0,0 +1,129 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    This unit implements the code generator for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       globtype,parabase,
+       cgbase,cgutils,cgobj,cghlcpu,
+       aasmbase,aasmtai,aasmdata,aasmcpu,
+       cpubase,cpuinfo,
+       node,symconst,SymType,symdef,
+       rgcpu;
+
+    type
+      TCgWasm=class(thlbasecgcpu)
+     public
+        procedure init_register_allocators;override;
+        procedure done_register_allocators;override;
+        function  getintregister(list:TAsmList;size:Tcgsize):Tregister;override;
+        function  getfpuregister(list:TAsmList;size:Tcgsize):Tregister;override;
+        function  getaddressregister(list:TAsmList):Tregister;override;
+        procedure do_register_allocation(list:TAsmList;headertai:tai);override;
+      end;
+
+    procedure create_codegen;
+
+implementation
+
+  uses
+    globals,verbose,systems,cutils,
+    paramgr,fmodule,
+    tgobj,
+    procinfo,cpupi;
+
+
+{****************************************************************************
+                              Assembler code
+****************************************************************************}
+
+    procedure TCgWasm.init_register_allocators;
+      begin
+        inherited init_register_allocators;
+{$ifndef cpu64bitaddr}
+        rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBD,
+          [RS_R0],first_int_imreg,[]);
+{$else not cpu64bitaddr}
+        rg[R_INTREGISTER]:=Trgcpu.create(R_INTREGISTER,R_SUBQ,
+          [RS_R0],first_int_imreg,[]);
+{$endif not cpu64bitaddr}
+        rg[R_FPUREGISTER]:=trgcpu.create(R_FPUREGISTER,R_SUBFS,
+          [RS_R0],first_fpu_imreg,[]);
+        rg[R_MMREGISTER]:=trgcpu.create(R_MMREGISTER,R_SUBNONE,
+          [RS_R0],first_mm_imreg,[]);
+      end;
+
+
+    procedure TCgWasm.done_register_allocators;
+      begin
+        rg[R_INTREGISTER].free;
+        rg[R_FPUREGISTER].free;
+        rg[R_MMREGISTER].free;
+        inherited done_register_allocators;
+      end;
+
+
+    function TCgWasm.getintregister(list:TAsmList;size:Tcgsize):Tregister;
+      begin
+        if not(size in [OS_64,OS_S64]) then
+          result:=rg[R_INTREGISTER].getregister(list,R_SUBD)
+        else
+          result:=rg[R_INTREGISTER].getregister(list,R_SUBQ);
+      end;
+
+
+    function TCgWasm.getfpuregister(list:TAsmList;size:Tcgsize):Tregister;
+      begin
+        if size=OS_F64 then
+          result:=rg[R_FPUREGISTER].getregister(list,R_SUBFD)
+        else
+          result:=rg[R_FPUREGISTER].getregister(list,R_SUBFS);
+      end;
+
+
+    function tcgwasm.getaddressregister(list:TAsmList):Tregister;
+      begin
+        { avoid problems in the compiler where int and addr registers are
+          mixed for now; we currently don't have to differentiate between the
+          two as far as the jvm backend is concerned }
+        result:=rg[R_INTREGISTER].getregister(list,R_SUBD)
+      end;
+
+
+    procedure tcgwasm.do_register_allocation(list:TAsmList;headertai:tai);
+      begin
+        { We only run the "register allocation" once for an arbitrary allocator,
+          which will perform the register->temp mapping for all register types.
+          This allows us to easily reuse temps. }
+        trgcpu(rg[R_INTREGISTER]).do_all_register_allocation(list,headertai);
+      end;
+
+
+    procedure create_codegen;
+      begin
+        cg:=tcgwasm.Create;
+      end;
+      
+end.

+ 417 - 0
compiler/wasm32/cpubase.pas

@@ -0,0 +1,417 @@
+{
+    Copyright (c) 2016-2017 by Karoly Balogh
+
+    Contains the base types for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+{ This Unit contains the base types for the Java Virtual Machine
+}
+unit cpubase;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,
+  aasmbase,cpuinfo,cgbase;
+
+
+{*****************************************************************************
+                                Assembler Opcodes
+*****************************************************************************}
+
+    type
+      TAsmOp=(A_None,
+      // control flow
+      a_block, a_loop, a_br, a_br_if, a_br_table, a_if, a_else, a_end_block,
+      a_end_loop, a_end_if, a_end_function, a_return, a_unreachable,
+      // basic
+      a_nop, a_drop, a_i32_const, a_i64_const, a_f32_const, a_f64_const,
+      a_local_get, a_local_set, a_local_tee, a_global_get, a_global_set,
+      a_select, a_call, a_call_indirect,
+      // integer
+      a_i32_add, a_i64_add, a_i32_sub, a_i64_sub, a_i32_mul, a_i64_mul,
+      a_i32_div_s, a_i64_div_s, a_i32_div_u, a_i64_div_u, a_i32_rem_s, a_i64_rem_s,
+      a_i32_rem_u, a_i64_rem_u, a_i32_and, a_i64_and, a_i32_or, a_i64_or,
+      a_i32_xor, a_i64_xor, a_i32_shl, a_i64_shl, a_i32_shr_s, a_i64_shr_s,
+      a_i32_shr_u, a_i64_shr_u, a_i32_rotl, a_i64_rotl, a_i32_rotr, a_i64_rotr,
+      a_i32_clz, a_i64_clz, a_i32_ctz, a_i64_ctz, a_i32_popcnt, a_i64_popcnt,
+      a_i32_eqz, a_i64_eqz,
+      // floating point
+      a_f32_add, a_f64_add, a_f32_sub, a_f64_sub, a_f32_mul, a_f64_mul,
+      a_f32_div, a_f64_div, a_f32_sqrt, a_f64_sqrt, a_f32_min, a_f64_min,
+      a_f32_max, a_f64_max, a_f32_ceil, a_f64_ceil, a_f32_floor, a_f64_floor,
+      a_f32_trunc, a_f64_trunc, a_f32_nearest, a_f64_nearest, a_f32_abs, a_f64_abs,
+      a_f32_neg, a_f64_neg, a_f32_copysign, a_f64_copysign,
+      // integer compare
+      a_i32_eq, a_i64_eq, a_i32_ne, a_i64_ne, a_i32_lt_s, a_i64_lt_s,
+      a_i32_lt_u, a_i64_lt_u, a_i32_le_s, a_i64_le_s, a_i32_le_u, a_i64_le_u,
+      a_i32_gt_s, a_i64_gt_s, a_i32_gt_u, a_i64_gt_u, a_i32_ge_s, a_i64_ge_s,
+      a_i32_ge_u, a_i64_ge_u,
+      // floating point compare
+      a_f32_eq, a_f64_eq, a_f32_ne, a_f64_ne, a_f32_lt, a_f64_lt,
+      a_f32_le, a_f64_le, a_f32_gt, a_f64_gt, a_f32_ge, a_f64_ge,
+      // conversion
+      a_i32_wrap_i64, a_i64_extend_i32_s, a_i64_extend_i32_u,
+      a_i32_extend8_s,a_i32_extend16_s,a_i64_extend8_s,a_i64_extend16_s,a_i64_extend32_s,
+      a_i32_trunc_f32_s, a_i32_trunc_f64_s, a_i64_trunc_f32_s, a_i64_trunc_f64_s,
+      a_i32_trunc_f32_u, a_i32_trunc_f64_u, a_i64_trunc_f32_u, a_i64_trunc_f64_u,
+      a_f32_demote_f64, a_f64_promote_f32,
+      a_f32_convert_i32_s, a_f32_convert_i64_s,a_f64_convert_i32_s,a_f64_convert_i64_s,
+      a_f32_convert_i32_u, a_f32_convert_i64_u,a_f64_convert_i32_u,a_f64_convert_i64_u,
+      a_i32_reinterpret_f32, a_i64_reinterpret_f64, a_f32_reinterpret_i32, a_f64_reinterpret_i64,
+      // load/store
+      a_i32_load, a_i64_load, a_f32_load, a_f64_load,
+      a_i32_store, a_i64_store, a_f32_store, a_f64_store,
+      a_i32_load8_s, a_i32_load16_s, a_i64_load8_s, a_i64_load16_s, a_i64_load32_s,
+      a_i32_load8_u, a_i32_load16_u, a_i64_load8_u, a_i64_load16_u, a_i64_load32_u,
+      a_i32_store8, a_i32_store16, a_i64_store8, a_i64_store16, a_i64_store32,
+      // additional memory
+      a_memory_grow, a_memory_size
+      );
+
+      TWasmBasicType = (wbt_i32, wbt_i64, wbt_f32, wbt_f64);
+      TWasmResultType = array of TWasmBasicType;
+
+      { TWasmFuncType }
+
+      TWasmFuncType = class
+        params: TWasmResultType;
+        results: TWasmResultType;
+        constructor Create(aparams, aresults: TWasmResultType);
+        procedure add_param(param: TWasmBasicType);
+        procedure add_result(res: TWasmBasicType);
+      end;
+
+      {# This should define the array of instructions as string }
+      op2strtable=array[tasmop] of string[31];
+
+    Const
+      {# First value of opcode enumeration }
+      firstop = low(tasmop);
+      {# Last value of opcode enumeration  }
+      lastop  = high(tasmop);
+
+      AsmOp_Store = [
+         a_i32_store, a_i32_store16, a_i32_store8
+        ,a_i64_store, a_i64_store16, a_i64_store8, a_i64_store32
+        ,a_f32_store, a_f64_store
+      ];
+
+      AsmOp_Load = [
+         a_i32_load,
+         a_i32_load8_s,  a_i32_load8_u,
+         a_i32_load16_s, a_i32_load16_u,
+         a_i64_load,
+         a_i64_load8_s,  a_i64_load8_u,
+         a_i64_load16_s, a_i64_load16_u,
+         a_i64_load32_s, a_i64_load32_u,
+         a_f32_load, a_f64_load
+      ];
+
+      AsmOp_LoadStore = AsmOp_Load + AsmOp_Store;
+
+
+{*****************************************************************************
+                                  Registers
+*****************************************************************************}
+
+    type
+      { Number of registers used for indexing in tables }
+      tregisterindex=0..{$i rwasmnor.inc}-1; // no registers in wasm
+      totherregisterset = set of tregisterindex;
+
+    const
+      { Available Superregisters }
+      // there's no registers in wasm
+      {$i rwasmsup.inc}
+
+      { No Subregisters }
+      R_SUBWHOLE = R_SUBNONE;
+
+      { Available Registers }
+      // there's no registers in wasm
+      {$i rwasmcon.inc}
+
+      { aliases }
+      { used as base register in references for parameters passed to
+        subroutines: these are passed on the evaluation stack, but this way we
+        can use the offset field to indicate the order, which is used by ncal
+        to sort the parameters }
+      NR_EVAL_STACK_BASE = NR_R0;
+      RS_EVAL_STACK_BASE = RS_R0;
+      { used as base register in references to indicate that it's a local }
+      NR_LOCAL_STACK_POINTER_REG = NR_R1;
+      RS_LOCAL_STACK_POINTER_REG = RS_R1;
+      { fake register, representing the local frame pointer. Used for accessing
+        address-taken local variables on the linear stack: (localframeptr+offset). }
+      NR_LOCAL_FRAME_POINTER_REG = NR_R3;
+      RS_LOCAL_FRAME_POINTER_REG = RS_R3;
+
+      maxvarregs = 1;
+      maxfpuvarregs = 1;
+
+      { Integer Super registers first and last }
+      first_int_imreg = 4;
+
+      { Float Super register first and last }
+      first_fpu_imreg     = 4;
+
+      { MM Super register first and last }
+      first_mm_imreg     = 4;
+
+      regnumber_table : array[tregisterindex] of tregister = (
+        {$i rwasmnum.inc}
+      );
+
+     EVALSTACKLOCS = [LOC_REGISTER,LOC_CREGISTER,LOC_FPUREGISTER,LOC_CFPUREGISTER,
+       LOC_MMREGISTER,LOC_CMMREGISTER,LOC_SUBSETREG,LOC_CSUBSETREG];
+
+
+{*****************************************************************************
+                                Conditions
+*****************************************************************************}
+
+   type
+     // not used by wasm target
+     TAsmCond=(C_None);
+
+{*****************************************************************************
+                                 Constants
+*****************************************************************************}
+
+    const
+      max_operands = 2;
+
+
+{*****************************************************************************
+                          Default generic sizes
+*****************************************************************************}
+
+{$ifdef cpu64bitaddr}
+      {# Defines the default address size for a processor,
+        -- fake for JVM, only influences default width of
+           arithmetic calculations }
+      OS_ADDR = OS_64;
+      {# the natural int size for a processor,
+         has to match osuinttype/ossinttype as initialized in psystem }
+      OS_INT = OS_64;
+      OS_SINT = OS_S64;
+{$else}
+      {# Defines the default address size for a processor,
+        -- fake for wasm, only influences default width of
+           arithmetic calculations }
+      OS_ADDR = OS_32;
+      {# the natural int size for a processor,
+         has to match osuinttype/ossinttype as initialized in psystem }
+      OS_INT = OS_32;
+      OS_SINT = OS_S32;
+{$endif}
+      {# the maximum float size for a processor,           }
+      OS_FLOAT = OS_F64;
+      {# the size of a vector register for a processor     }
+      OS_VECTOR = OS_M128;
+
+{*****************************************************************************
+                          Generic Register names
+*****************************************************************************}
+
+      { dummies, not used for Wasm }
+
+      {# Stack pointer register }
+      { used as base register in references to indicate that it's a local }
+      NR_STACK_POINTER_REG = NR_R1;
+      RS_STACK_POINTER_REG = RS_R1;
+      {# Frame pointer register }
+      NR_FRAME_POINTER_REG = NR_LOCAL_FRAME_POINTER_REG;
+      RS_FRAME_POINTER_REG = RS_LOCAL_FRAME_POINTER_REG;
+
+      { WebAssembly results are returned on the evaluation stack, not via a register }
+
+      { Results are returned in this register (32-bit values) }
+      NR_FUNCTION_RETURN_REG = NR_NO;
+      RS_FUNCTION_RETURN_REG = RS_NO;
+      { Low part of 64bit return value }
+      NR_FUNCTION_RETURN64_LOW_REG = NR_NO;
+      RS_FUNCTION_RETURN64_LOW_REG = RS_NO;
+      { High part of 64bit return value }
+      NR_FUNCTION_RETURN64_HIGH_REG = NR_NO;
+      RS_FUNCTION_RETURN64_HIGH_REG = RS_NO;
+      { The value returned from a function is available in this register }
+      NR_FUNCTION_RESULT_REG = NR_FUNCTION_RETURN_REG;
+      RS_FUNCTION_RESULT_REG = RS_FUNCTION_RETURN_REG;
+      { The lowh part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_LOW_REG = NR_FUNCTION_RETURN64_LOW_REG;
+      RS_FUNCTION_RESULT64_LOW_REG = RS_FUNCTION_RETURN64_LOW_REG;
+      { The high part of 64bit value returned from a function }
+      NR_FUNCTION_RESULT64_HIGH_REG = NR_FUNCTION_RETURN64_HIGH_REG;
+      RS_FUNCTION_RESULT64_HIGH_REG = RS_FUNCTION_RETURN64_HIGH_REG;
+
+      NR_FPU_RESULT_REG = NR_NO;
+      NR_MM_RESULT_REG = NR_NO;
+
+
+{*****************************************************************************
+                       GCC /ABI linking information
+*****************************************************************************}
+
+      { dummies, not used for Wasm }
+
+      {# Required parameter alignment when calling a routine
+      }
+      std_param_align = 1;
+
+
+{*****************************************************************************
+                            CPU Dependent Constants
+*****************************************************************************}
+
+      maxfpuregs = 0;
+
+      { Global variable, that acts as the stack pointer in linear memory
+        (also called the "linear stack"). This stack is used for address-taken
+        local variables. This separate stack is needed, because the WASM
+        implementation's runtime call stack (which includes return addresses and
+        function parameters) is not visible in linear memory. }
+      STACK_POINTER_SYM = '__stack_pointer';
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+    function reg_cgsize(const reg: tregister) : tcgsize;
+
+    function std_regnum_search(const s:string):Tregister;
+    function std_regname(r:Tregister):string;
+    function findreg_by_number(r:Tregister):tregisterindex;
+
+    function dwarf_reg(r:tregister):byte;
+    function dwarf_reg_no_error(r:tregister):shortint;
+    function eh_return_data_regno(nr: longint): longint;
+
+    { since we don't use tasmconds, don't call this routine
+      (it will internalerror). We need it anyway to get aoptobj
+      to compile (but it won't execute it).
+    }
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+
+implementation
+
+uses
+  verbose,
+  rgbase;
+
+{*****************************************************************************
+                                  Helpers
+*****************************************************************************}
+
+    const
+      std_regname_table : array[tregisterindex] of string[15] = (
+        {$i rwasmstd.inc}
+      );
+
+      regnumber_index : array[tregisterindex] of tregisterindex = (
+        {$i rwasmrni.inc}
+      );
+
+      std_regname_index : array[tregisterindex] of tregisterindex = (
+        {$i rwasmsri.inc}
+      );
+
+    function reg_cgsize(const reg: tregister): tcgsize;
+      begin
+        result:=OS_NO;
+      end;
+
+
+    function cgsize2subreg(regtype: tregistertype; s:Tcgsize):Tsubregister;
+      begin
+        cgsize2subreg:=R_SUBNONE;
+      end;
+
+
+    function std_regnum_search(const s:string):Tregister;
+      begin
+        result:=NR_NO;
+      end;
+
+
+    function findreg_by_number(r:Tregister):tregisterindex;
+      begin
+        result:=findreg_by_number_table(r,regnumber_index);
+      end;
+
+    function std_regname(r:Tregister):string;
+      var
+        p : tregisterindex;
+      begin
+        p:=findreg_by_number_table(r,regnumber_index);
+        if p<>0 then
+          result:=std_regname_table[p]
+        else
+          result:=generic_regname(r);
+      end;
+
+    function dwarf_reg(r:tregister):byte;
+      begin
+        result:=0;
+        internalerror(200603251);
+      end;
+
+    function dwarf_reg_no_error(r:tregister):shortint;
+      begin
+        result:=-1;
+      end;
+
+    function eh_return_data_regno(nr: longint): longint;
+      begin
+        result:=-1;
+      end;
+
+    function inverse_cond(const c: TAsmCond): Tasmcond; {$ifdef USEINLINE}inline;{$endif USEINLINE}
+      begin
+        result:=C_None;
+        internalerror(2015082701);
+      end;
+
+{*****************************************************************************
+                                  TWasmFuncType
+*****************************************************************************}
+
+    constructor TWasmFuncType.Create(aparams, aresults: TWasmResultType);
+      begin
+        inherited Create;
+        params:=aparams;
+        results:=aresults;
+      end;
+
+    procedure TWasmFuncType.add_param(param: TWasmBasicType);
+      begin
+        SetLength(params,Length(params)+1);
+        params[High(params)]:=param;
+      end;
+
+    procedure TWasmFuncType.add_result(res: TWasmBasicType);
+      begin
+        SetLength(results,Length(results)+1);
+        results[High(results)]:=res;
+      end;
+
+end.

+ 103 - 0
compiler/wasm32/cpuinfo.pas

@@ -0,0 +1,103 @@
+{
+    Copyright (c) 2010 by Free Pascal and Lazarus foundation
+
+    Basic Processor information for the WebAssembly
+
+    See the file COPYING.FPC, included in this distribution,
+    for details about the copyright.
+
+    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.
+
+ **********************************************************************}
+
+Unit cpuinfo;
+
+{$i fpcdefs.inc}
+
+Interface
+
+  uses
+    globtype;
+
+Type
+   bestreal = double;
+{$if FPC_FULLVERSION>20700}
+   bestrealrec = TDoubleRec;
+{$endif FPC_FULLVERSION>20700}
+   ts32real = single;
+   ts64real = double;
+   ts80real = extended;
+   ts128real = extended;
+   ts64comp = comp;
+
+   pbestreal=^bestreal;
+
+   { possible supported processors for this target }
+   tcputype =
+      (cpu_none,
+       { wasm32, same as cpu_none }
+       cpu_wasm32
+      );
+
+   tfputype =
+     (fpu_none,
+      fpu_standard
+     );
+
+   tcontrollertype =
+     (ct_none
+     );
+
+   tcontrollerdatatype = record
+      controllertypestr, controllerunitstr: string[20];
+      cputype: tcputype; fputype: tfputype;
+      flashbase, flashsize, srambase, sramsize, eeprombase, eepromsize, bootbase, bootsize: dword;
+   end;
+
+
+Const
+   { Is there support for dealing with multiple microcontrollers available }
+   { for this platform? }
+   ControllerSupport = false;
+
+   { We know that there are fields after sramsize
+     but we don't care about this warning }
+   {$PUSH}
+    {$WARN 3177 OFF}
+   embedded_controllers : array [tcontrollertype] of tcontrollerdatatype =
+   (
+      (controllertypestr:''; controllerunitstr:''; cputype:cpu_none; fputype:fpu_none; flashbase:0; flashsize:0; srambase:0; sramsize:0));
+   {$POP}
+
+   { calling conventions supported by the code generator }
+   supported_calling_conventions : tproccalloptions = [
+     pocall_internproc
+   ];
+
+   cputypestr : array[tcputype] of string[9] = ('',
+     'WASM32'
+   );
+
+   fputypestr : array[tfputype] of string[8] = (
+     'NONE',
+     'STANDARD'
+   );
+
+   { Supported optimizations, only used for information }
+   supported_optimizerswitches = genericlevel1optimizerswitches+
+                                 genericlevel2optimizerswitches+
+                                 genericlevel3optimizerswitches-
+                                 { no need to write info about those }
+                                 [cs_opt_level1,cs_opt_level2,cs_opt_level3]+
+                                 [cs_opt_loopunroll,cs_opt_nodecse];
+
+   level1optimizerswitches = genericlevel1optimizerswitches;
+   level2optimizerswitches = genericlevel2optimizerswitches + level1optimizerswitches + [cs_opt_nodecse];
+   level3optimizerswitches = genericlevel3optimizerswitches + level2optimizerswitches + [{,cs_opt_loopunroll}];
+   level4optimizerswitches = genericlevel4optimizerswitches + level3optimizerswitches + [];
+
+Implementation
+
+end.

+ 47 - 0
compiler/wasm32/cpunode.pas

@@ -0,0 +1,47 @@
+{******************************************************************************
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    Includes the WebAssembly code generator
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ *****************************************************************************}
+unit cpunode;
+
+{$I fpcdefs.inc}
+
+interface
+{ This unit is used to define the specific CPU implementations. All needed
+actions are included in the INITALIZATION part of these units. This explains
+the behaviour of such a unit having just a USES clause! }
+
+implementation
+
+  uses
+    ncgbas,ncgflw,ncgcnv,ncgld,ncgmem,ncgcon,ncgset,
+    ncgadd, ncgcal,ncgmat,ncginl,
+    
+    nwasmadd,nwasmcal,nwasmmat,nwasmflw,nwasmcon,nwasmcnv,nwasmset,nwasminl,
+    (* todo: WASM
+    njvmcnv,njvmcon,njvminl,njvmmem,njvmld,
+    njvmset,njvmvmt
+    { these are not really nodes }
+    ,rgcpu,tgcpu,njvmutil,njvmtcon,
+    *)
+    { symtable }
+    symcpu;
+    { no aasmdef, the WebAssembly uses the base TAsmData class (set in init code of aasmcpu) }
+
+end.

+ 306 - 0
compiler/wasm32/cpupara.pas

@@ -0,0 +1,306 @@
+{
+    Copyright (c) 2019 by Dmtiry Boyarintsev
+
+    Calling conventions for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *****************************************************************************}
+unit cpupara;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      globtype,
+      cclasses,
+      aasmtai,aasmdata,
+      cpubase,cpuinfo,
+      symconst,symbase,symsym,symtype,symdef,paramgr,parabase,cgbase,cgutils;
+
+    type
+
+      { tcpuparamanager }
+
+      tcpuparamanager=class(TParaManager)
+        function  get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;override;
+        function  keep_para_array_range(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean; override;
+        function  push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;override;
+        function  push_size(varspez: tvarspez; def: tdef; calloption: tproccalloption): longint;override;
+        function  create_paraloc_info(p : TAbstractProcDef; side: tcallercallee):longint;override;
+        function  create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;override;
+        function  get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;override;
+        { true if the location in paraloc can be reused as localloc }
+        function param_use_paraloc(const cgpara: tcgpara): boolean; override;
+        function is_stack_paraloc(paraloc: pcgparalocation): boolean;override;
+      private
+        procedure create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee; paras: tparalist;
+                                             var parasize:longint);
+      end;
+
+implementation
+
+    uses
+      cutils,verbose,systems,
+      defutil,wasmdef,
+      aasmcpu,
+      hlcgobj;
+
+
+    function tcpuparamanager.get_saved_registers_int(calloption: tproccalloption): tcpuregisterarray;
+      const
+        { dummy, not used for WebAssembly }
+        saved_regs: {$ifndef VER3_0}tcpuregisterarray{$else}array [0..0] of tsuperregister{$endif} = (RS_NO);
+      begin
+        result:=saved_regs;
+      end;
+
+
+    function tcpuparamanager.keep_para_array_range(varspez: tvarspez; def: tdef; calloption: tproccalloption): boolean;
+      begin
+        { even though these don't need a high parameter (see push_high_param),
+          we do have to keep the original parameter's array length because it's
+          used by the compiler (to determine the size of the array to construct
+          to pass to an array of const parameter)  }
+        if not is_array_of_const(def) then
+          result:=inherited
+        else
+          result:=true;
+      end;
+
+
+    { true if a parameter is too large to copy and only the address is pushed }
+    function tcpuparamanager.push_addr_param(varspez:tvarspez;def : tdef;calloption : tproccalloption) : boolean;
+      begin
+        result:=false;
+        { var,out,constref always require address }
+        if varspez in [vs_var,vs_out,vs_constref] then
+          begin
+            result:=true;
+            exit;
+          end;
+        { Only vs_const, vs_value here }
+        case def.typ of
+          variantdef,
+          formaldef :
+            result:=true;
+          recorddef :
+            begin
+              { Delphi stdcall passes records on the stack for call by value }
+              result:=(varspez=vs_const) or (def.size=0);
+            end;
+          arraydef :
+            begin
+              result:=(tarraydef(def).highrange>=tarraydef(def).lowrange) or
+                 is_open_array(def) or
+                 is_array_of_const(def) or
+                 is_array_constructor(def);
+            end;
+          objectdef :
+            result:=is_object(def);
+          stringdef :
+            result:= (tstringdef(def).stringtype in [st_shortstring,st_longstring]);
+          procvardef :
+            result:=not(calloption in cdecl_pocalls) and not tprocvardef(def).is_addressonly;
+          setdef :
+            result:=not is_smallset(def);
+          else
+            ;
+        end;
+
+      end;
+
+
+    function tcpuparamanager.push_size(varspez: tvarspez; def: tdef; calloption: tproccalloption): longint;
+      begin
+        { all aggregate types are emulated using indirect pointer types }
+        result:=inherited;
+      end;
+
+
+    function tcpuparamanager.get_funcretloc(p : tabstractprocdef; side: tcallercallee; forcetempdef: tdef): tcgpara;
+      var
+        paraloc : pcgparalocation;
+        retcgsize  : tcgsize;
+      begin
+        result.init;
+        result.alignment:=get_para_align(p.proccalloption);
+        if not assigned(forcetempdef) then
+          result.def:=p.returndef
+        else
+          begin
+            result.def:=forcetempdef;
+            result.temporary:=true;
+          end;
+        result.def:=get_para_push_size(result.def);
+        { void has no location }
+        if is_void(result.def) then
+          begin
+            paraloc:=result.add_location;
+            result.size:=OS_NO;
+            result.intsize:=0;
+            paraloc^.size:=OS_NO;
+            paraloc^.def:=voidtype;
+            paraloc^.loc:=LOC_VOID;
+            exit;
+          end;
+        { Constructors return self instead of a boolean }
+        if (p.proctypeoption=potype_constructor) then
+          begin
+            retcgsize:=OS_INT;
+            result.intsize:=sizeof(pint);
+          end
+        //todo: wasm should have the similar
+        {else if jvmimplicitpointertype(result.def) then
+          begin
+            retcgsize:=OS_ADDR;
+            result.def:=cpointerdef.getreusable_no_free(result.def);
+          end}
+        else
+          begin
+            retcgsize:=def_cgsize(result.def);
+            result.intsize:=result.def.size;
+          end;
+        result.size:=retcgsize;
+
+        paraloc:=result.add_location;
+        { all values are returned on the evaluation stack }
+        paraloc^.loc:=LOC_REFERENCE;
+        paraloc^.reference.index:=NR_EVAL_STACK_BASE;
+        paraloc^.reference.offset:=0;
+        paraloc^.size:=result.size;
+        paraloc^.def:=result.def;
+      end;
+
+    function tcpuparamanager.param_use_paraloc(const cgpara: tcgpara): boolean;
+      begin
+        { all parameters are copied to the linear stack, so that their address
+          can be taken }
+        result:=false;
+      end;
+
+    function tcpuparamanager.is_stack_paraloc(paraloc: pcgparalocation): boolean;
+      begin
+        { all parameters are passed on the evaluation stack }
+        result:=true;
+      end;
+
+
+    function tcpuparamanager.create_varargs_paraloc_info(p : tabstractprocdef; side: tcallercallee; varargspara:tvarargsparalist):longint;
+      var
+        parasize : longint;
+      begin
+        parasize:=0;
+        { calculate the registers for the normal parameters }
+        create_paraloc_info_intern(p,side,p.paras,parasize);
+        { append the varargs }
+        if assigned(varargspara) then
+          begin
+            if side=callerside then
+              create_paraloc_info_intern(p,side,varargspara,parasize)
+            else
+              internalerror(2019021924);
+          end;
+        create_funcretloc_info(p,side);
+        result:=parasize;
+      end;
+
+
+    procedure tcpuparamanager.create_paraloc_info_intern(p : tabstractprocdef; side: tcallercallee;paras:tparalist;
+                                                           var parasize:longint);
+      var
+        paraloc      : pcgparalocation;
+        i            : integer;
+        hp           : tparavarsym;
+        paracgsize   : tcgsize;
+        paraofs      : longint;
+        paradef      : tdef;
+      begin
+        paraofs:=0;
+        for i:=0 to paras.count-1 do
+          begin
+            hp:=tparavarsym(paras[i]);
+            if push_copyout_param(hp.varspez,hp.vardef,p.proccalloption) then
+              begin
+                { passed via array reference (instead of creating a new array
+                  type for every single parameter, use java_jlobject) }
+                paracgsize:=OS_ADDR;
+                paradef:=ptruinttype;
+              end
+            else if push_addr_param(hp.varspez, hp.vardef,p.proccalloption) then
+              begin
+                paracgsize:=OS_ADDR;
+                paradef:=cpointerdef.getreusable_no_free(hp.vardef);
+              end
+            else
+              begin
+                paracgsize:=def_cgsize(hp.vardef);
+                if paracgsize=OS_NO then
+                  paracgsize:=OS_ADDR;
+                paradef:=hp.vardef;
+              end;
+            paradef:=get_para_push_size(paradef);
+            hp.paraloc[side].reset;
+            hp.paraloc[side].size:=paracgsize;
+            hp.paraloc[side].def:=paradef;
+            hp.paraloc[side].alignment:=std_param_align;
+            hp.paraloc[side].intsize:=tcgsize2size[paracgsize];
+            paraloc:=hp.paraloc[side].add_location;
+            { All parameters are passed on the evaluation stack, pushed from
+              left to right (including self, if applicable). At the callee side,
+              they're available as local variables 0..n-1  }
+            paraloc^.loc:=LOC_REFERENCE;
+            paraloc^.reference.offset:=paraofs;
+            paraloc^.size:=paracgsize;
+            paraloc^.def:=paradef;
+            case side of
+              callerside:
+                begin
+                  paraloc^.loc:=LOC_REFERENCE;
+                  { we use a fake loc_reference to indicate the stack location;
+                    the offset (set above) will be used by ncal to order the
+                    parameters so they will be pushed in the right order }
+                  paraloc^.reference.index:=NR_EVAL_STACK_BASE;
+                end;
+              calleeside:
+                begin
+                  paraloc^.loc:=LOC_REFERENCE;
+                  paraloc^.reference.index:=NR_STACK_POINTER_REG;
+                end;
+              else
+                ;
+            end;
+            inc(paraofs);
+          end;
+        parasize:=paraofs;
+      end;
+
+
+    function tcpuparamanager.create_paraloc_info(p : tabstractprocdef; side: tcallercallee):longint;
+      var
+        parasize : longint;
+      begin
+        parasize:=0;
+        create_paraloc_info_intern(p,side,p.paras,parasize);
+        { Create Function result paraloc }
+        create_funcretloc_info(p,side);
+        { We need to return the size allocated on the stack }
+        result:=parasize;
+      end;
+
+
+initialization
+  ParaManager:=tcpuparamanager.create;
+end.

+ 178 - 0
compiler/wasm32/cpupi.pas

@@ -0,0 +1,178 @@
+{
+    Copyright (c) 2002-2010 by Florian Klaempfl and Jonas Maebe
+
+    This unit contains the CPU specific part of tprocinfo
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cpupi;
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    cutils,globtype,
+    procinfo,cpuinfo, symtype,aasmbase,
+    psub, cclasses;
+
+  type
+
+    { tcpuprocinfo }
+
+    tcpuprocinfo=class(tcgprocinfo)
+    public
+      procedure setup_eh; override;
+      procedure postprocess_code; override;
+      procedure set_first_temp_offset;override;
+    end;
+
+implementation
+
+    uses
+      systems,globals,cpubase,tgcpu,aasmdata,aasmcpu,aasmtai,cgexcept,
+      tgobj,paramgr,symconst,symcpu;
+
+{*****************************************************************************
+                     twasmexceptionstatehandler
+*****************************************************************************}
+
+    type
+      twasmexceptionstatehandler = class(tcgexceptionstatehandler)
+        class procedure new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate); override;
+        class procedure free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean); override;
+        class procedure handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate); override;
+      end;
+
+    class procedure twasmexceptionstatehandler.new_exception(list:TAsmList;const t:texceptiontemps; const exceptframekind: texceptframekind; out exceptstate: texceptionstate);
+      begin
+        list.Concat(tai_comment.Create(strpnew('TODO: new_exception')));
+      end;
+
+    class procedure twasmexceptionstatehandler.free_exception(list: TAsmList; const t: texceptiontemps; const s: texceptionstate; a: aint; endexceptlabel: tasmlabel; onlyfree:boolean);
+      begin
+        list.Concat(tai_comment.Create(strpnew('TODO: free_exception')));
+      end;
+
+    class procedure twasmexceptionstatehandler.handle_nested_exception(list:TAsmList;var t:texceptiontemps;var entrystate: texceptionstate);
+      begin
+        list.Concat(tai_comment.Create(strpnew('TODO: handle_nested_exception')));
+      end;
+
+{*****************************************************************************
+                           tcpuprocinfo
+*****************************************************************************}
+
+    procedure tcpuprocinfo.setup_eh;
+      begin
+        cexceptionstatehandler:=twasmexceptionstatehandler;
+      end;
+
+    procedure tcpuprocinfo.postprocess_code;
+
+      function findfirst_tai_functype(asmlist: TAsmList): tai_functype;
+        var
+          hp: tai;
+        begin
+          result:=nil;
+          if not assigned(asmlist) then
+            exit;
+          hp:=tai(asmlist.first);
+          while assigned(hp) do
+            begin
+              if hp.typ=ait_functype then
+                begin
+                  result:=tai_functype(hp);
+                  exit;
+                end;
+              hp:=tai(hp.Next);
+            end;
+        end;
+
+      procedure replace_local_frame_pointer(asmlist: TAsmList);
+        var
+          hp: tai;
+          instr: taicpu;
+          l: Integer;
+        begin
+          if not assigned(asmlist) then
+            exit;
+          hp:=tai(asmlist.first);
+          while assigned(hp) do
+            begin
+              if hp.typ=ait_instruction then
+                begin
+                  instr:=taicpu(hp);
+                  for l:=0 to instr.ops-1 do
+                    if (instr.oper[l]^.typ=top_reg) and (instr.oper[l]^.reg=NR_LOCAL_FRAME_POINTER_REG) then
+                      instr.loadref(l,tcpuprocdef(current_procinfo.procdef).frame_pointer_ref);
+                end;
+              hp:=tai(hp.Next);
+            end;
+        end;
+
+      var
+       templist : TAsmList;
+       l : TWasmLocal;
+       first: Boolean;
+       local: tai_local;
+      begin
+        templist:=TAsmList.create;
+        local:=nil;
+        first:=true;
+        l:=ttgwasm(tg).localvars.first;
+        while Assigned(l) do
+          begin
+            local:=tai_local.create(l.typ);
+            local.first:=first;
+            first:=false;
+            templist.Concat(local);
+            l:=l.nextseq;
+          end;
+        if assigned(local) then
+          local.last:=true;
+        aktproccode.insertListAfter(findfirst_tai_functype(aktproccode),templist);
+        templist.Free;
+
+        replace_local_frame_pointer(aktproccode);
+
+        inherited postprocess_code;
+      end;
+
+    procedure tcpuprocinfo.set_first_temp_offset;
+      var
+        sz : integer;
+        i  : integer;
+        sym: tsym;
+      begin
+        {
+          Stackframe layout:
+          sp:
+            <incoming parameters>
+            sp+first_temp_offset:
+            <locals>
+            <temp>
+        }
+        procdef.init_paraloc_info(calleeside);
+        sz := procdef.calleeargareasize;
+        tg.setfirsttemp(sz);
+      end;
+
+
+initialization
+  cprocinfo:=tcpuprocinfo;
+end.

+ 69 - 0
compiler/wasm32/cputarg.pas

@@ -0,0 +1,69 @@
+{
+    Copyright (c)  by Dmitry Boyarintsev
+
+    Includes the WebAssembly dependent target units
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit cputarg;
+
+{$i fpcdefs.inc}
+
+interface
+
+
+implementation
+
+    uses
+      systems { prevent a syntax error when nothing is included }
+
+{$ifndef NOOPT}
+//      ,aoptcpu
+{$endif NOOPT}
+
+{**************************************
+             Targets
+**************************************}
+      ,t_embed
+      ,t_wasi
+
+{**************************************
+             Assemblers
+**************************************}
+
+      ,agwat
+      ,agbinaryen
+      ,agllvmmc
+
+{**************************************
+        Assembler Readers
+**************************************}
+
+{**************************************
+             Debuginfo
+**************************************}
+
+  {$ifndef NoCFIDwarf}
+      //,cfidwarf
+  {$endif NoCFIDwarf}
+  {$ifndef NoDbgDwarf}
+      ,dbgdwarf
+  {$endif NoDbgDwarf}
+
+      ;
+
+end.

+ 1882 - 0
compiler/wasm32/hlcgcpu.pas

@@ -0,0 +1,1882 @@
+{
+    Copyright (c) 1998-2010 by Florian Klaempfl and Jonas Maebe
+    Member of the Free Pascal development team
+
+    This unit implements the WebAssembly high level code generator
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit hlcgcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,
+  aasmbase,aasmdata,
+  symbase,symconst,symtype,symdef,symsym,
+  node,
+  cpubase, hlcgobj, cgbase, cgutils, parabase, wasmdef;
+
+  type
+
+    { thlcgwasm }
+
+    thlcgwasm = class(thlcgobj)
+     private
+      fevalstackheight,
+      fmaxevalstackheight: longint;
+     public
+      br_blocks: integer;
+      loopContBr: integer; // the value is different depending of the condition test
+                           // if it's in the beggning the jump should be done to the loop (1)
+                           // if the condition at the end, the jump should done to the end of block (0)
+      loopBreakBr: integer;
+      exitBr: integer;
+      fntypelookup : TWasmProcTypeLookup;
+
+      constructor create;
+      destructor Destroy; override;
+
+      procedure incblock;
+      procedure decblock;
+
+      procedure incstack(list : TAsmList;slots: longint);
+      procedure decstack(list : TAsmList;slots: longint);
+
+      procedure a_load_const_cgpara(list : TAsmList;tosize : tdef;a : tcgint;const cgpara : TCGPara);override;
+
+      function a_call_name(list : TAsmList;pd : tprocdef;const s : TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;override;
+      function a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara; override;
+
+      { move instructions - a_load_FROM_TO }
+      procedure a_load_const_reg(list : TAsmList;tosize : tdef;a : tcgint;register : tregister);override;
+      procedure a_load_const_ref(list : TAsmList;tosize : tdef;a : tcgint;const ref : treference);override;
+      procedure a_load_reg_ref(list : TAsmList;fromsize, tosize : tdef;register : tregister;const ref : treference);override;
+      procedure a_load_reg_reg(list : TAsmList;fromsize, tosize : tdef;reg1,reg2 : tregister);override;
+      procedure a_load_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;register : tregister);override;
+      procedure a_load_ref_ref(list : TAsmList;fromsize, tosize : tdef;const sref : treference;const dref : treference);override;
+      procedure a_loadaddr_ref_reg(list : TAsmList;fromsize, tosize : tdef;const ref : treference;r : tregister);override;
+
+      { basic arithmetic operations }
+      procedure a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister); override;
+      procedure a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister); override;
+      procedure a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference); override;
+
+      procedure a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister); override;
+      procedure a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister); override;
+      procedure a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister); override;
+      procedure a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
+      procedure a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister;setflags : boolean;var ovloc : tlocation); override;
+
+      procedure a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel); override;
+      procedure a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel); override;
+      procedure a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel); override;
+      procedure a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel); override;
+      procedure a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel); override;
+
+      procedure a_jmp_always(list : TAsmList;l: tasmlabel); override;
+
+      procedure a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference); override;
+      procedure a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister); override;
+      procedure a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference); override;
+      procedure a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister); override;
+
+      procedure g_concatcopy(list : TAsmList;size: tdef; const source,dest : treference); override;
+
+      procedure g_proc_entry(list : TAsmList;localsize : longint;nostackframe:boolean); override;
+      procedure g_proc_exit(list : TAsmList;parasize:longint;nostackframe:boolean); override;
+
+      procedure g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef); override;
+      procedure g_overflowCheck_loc(List:TAsmList;const Loc:TLocation;def:TDef;var ovloc : tlocation); override;
+
+      procedure maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean); override;
+
+      procedure gen_entry_code(list: TAsmList); override;
+      procedure gen_exit_code(list: TAsmList); override;
+
+      { unimplemented/unnecessary routines }
+      procedure a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister); override;
+      procedure a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle); override;
+      procedure a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle); override;
+      procedure a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle); override;
+      procedure a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle); override;
+      procedure a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle); override;
+      procedure a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle); override;
+      procedure a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle); override;
+      procedure g_stackpointer_alloc(list: TAsmList; size: longint); override;
+      procedure g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint); override;
+      procedure g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint); override;
+      procedure g_local_unwind(list: TAsmList; l: TAsmLabel); override;
+
+      { Wasm-specific routines }
+
+      procedure g_procdef(list:TAsmList;pd: tprocdef);
+
+      procedure a_load_stack_reg(list : TAsmList;size: tdef;reg: tregister);
+      { extra_slots are the slots that are used by the reference, and that
+        will be removed by the store operation }
+      procedure a_load_stack_ref(list : TAsmList;size: tdef;const ref: treference;extra_slots: longint);
+      procedure a_load_reg_stack(list : TAsmList;size: tdef;reg: tregister);
+      { extra_slots are the slots that are used by the reference, and that
+        will be removed by the load operation }
+      procedure a_load_ref_stack(list : TAsmList;size: tdef;const ref: treference;extra_slots: longint);
+      procedure a_load_const_stack(list : TAsmList;size: tdef;a :tcgint; typ: TRegisterType);
+      procedure a_loadaddr_ref_stack(list : TAsmList;fromsize, tosize : tdef;const ref : treference);
+
+      procedure a_load_stack_loc(list : TAsmList;size: tdef;const loc: tlocation);
+      procedure a_load_loc_stack(list : TAsmList;size: tdef;const loc: tlocation);
+
+      procedure a_loadfpu_const_stack(list : TAsmList;size: tdef;a :double);
+
+      procedure a_op_stack(list : TAsmList;op: topcg; size: tdef);
+      procedure a_op_const_stack(list : TAsmList;op: topcg; size: tdef;a : tcgint);
+      procedure a_op_reg_stack(list : TAsmList;op: topcg; size: tdef;reg: tregister);
+      procedure a_op_ref_stack(list : TAsmList;op: topcg; size: tdef;const ref: treference);
+      procedure a_op_loc_stack(list : TAsmList;op: topcg; size: tdef;const loc: tlocation);
+
+      procedure a_cmp_const_loc_stack(list: TAsmList; size: tdef;cmp_op: topcmp; a: tcgint; const loc: tlocation);
+      procedure a_cmp_const_ref_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference);
+      procedure a_cmp_const_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister);
+      procedure a_cmp_ref_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister);
+      procedure a_cmp_reg_ref_stack(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference);
+      procedure a_cmp_reg_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister);
+      procedure a_cmp_subsetreg_reg_stack(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sreg: tsubsetregister; reg: tregister);
+      procedure a_cmp_subsetref_reg_stack(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sref: tsubsetreference; reg: tregister);
+
+      procedure a_cmp_loc_reg_stack(list : TAsmList;size : tdef;cmp_op : topcmp; const loc: tlocation; reg : tregister);
+      procedure a_cmp_reg_loc_stack(list : TAsmList;size : tdef;cmp_op : topcmp; reg: tregister; const loc: tlocation);
+      procedure a_cmp_ref_loc_stack(list: TAsmList; size: tdef;cmp_op: topcmp; const ref: treference; const loc: tlocation);
+
+      procedure a_cmp_const_loc_br(list: TAsmList; size: tdef;cmp_op: topcmp; a: tcgint; const loc: tlocation; br: Integer);
+      procedure a_cmp_const_ref_br(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; br: Integer);
+      procedure a_cmp_const_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; br: Integer);
+      procedure a_cmp_ref_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; br: Integer);
+      procedure a_cmp_reg_ref_br(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; br: Integer);
+      procedure a_cmp_reg_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; br: Integer);
+      procedure a_cmp_subsetreg_reg_br(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sreg: tsubsetregister; reg: tregister; br: Integer);
+      procedure a_cmp_subsetref_reg_br(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sref: tsubsetreference; reg: tregister; br: Integer);
+
+      procedure a_cmp_loc_reg_br(list : TAsmList;size : tdef;cmp_op : topcmp; const loc: tlocation; reg : tregister; br: Integer);
+      procedure a_cmp_reg_loc_br(list : TAsmList;size : tdef;cmp_op : topcmp; reg: tregister; const loc: tlocation; br: Integer);
+      procedure a_cmp_ref_loc_br(list: TAsmList; size: tdef;cmp_op: topcmp; const ref: treference; const loc: tlocation; br: Integer);
+
+      procedure g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation); override;
+
+      procedure a_cmp_stack_stack(list : TAsmlist; size: tdef; cmp_op: topcmp);
+      { truncate/sign extend after performing operations on values < 32 bit
+        that may have overflowed outside the range }
+      procedure maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
+
+      { performs sign/zero extension as required }
+      procedure resize_stack_int_val(list: TAsmList;fromsize,tosize: tdef; formemstore: boolean);
+
+      { 8/16 bit unsigned parameters and return values must be sign-extended on
+        the producer side, because the JVM does not support unsigned variants;
+        then they have to be zero-extended again on the consumer side }
+      procedure maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
+
+      { adjust the stack height after a call based on the specified number of
+        slots used for parameters and the provided resultdef }
+      procedure g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef);
+
+      { because WebAssembly has no spec for any sort of debug info, and the
+        only linker that we support (LLVM's wasm-ld) does not support creating
+        map files in its stable version, and crashes when attempting to create
+        a map file in its development version from git, we have no way to
+        identify which procedure a crash occurred in. So, to identify the
+        procedure, we call this procedure on proc entry, which generates a few
+        useless loads of random numbers on the stack, that are immediately
+        discarded, so they are essentially equivalent to a nop. This allows
+        finding the procedure in the FPC output assembly, produced with -al by
+        searching for these random numbers, as taken from the disassembly of the
+        final binary. }
+      procedure g_fingerprint(list: TAsmList);
+
+      property maxevalstackheight: longint read fmaxevalstackheight;
+
+     protected
+      procedure gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara); override;
+
+      function g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara; override;
+
+     public
+      { in case of an array, the array base address and index have to be
+        put on the evaluation stack before the stored value; similarly, for
+        fields the self pointer has to be loaded first. Also checks whether
+        the reference is valid. If dup is true, the necessary values are stored
+        twice. Returns how many stack slots have been consumed, disregarding
+        the "dup". }
+      function prepare_stack_for_ref(list: TAsmList; var ref: treference; dup: boolean): longint;
+     protected
+      { return the load/store opcode to load/store from/to ref; if the result
+        has to be and'ed after a load to get the final value, that constant
+        is returned in finishandval (otherwise that value is set to -1) }
+      function loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
+      procedure resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
+    end;
+
+implementation
+
+  uses
+    verbose,cutils,globals,fmodule,constexp,
+    defutil,
+    aasmtai,aasmcpu,
+    symtable,symcpu,
+    procinfo,cpuinfo,cgcpu,tgobj,tgcpu,paramgr;
+
+  const
+    TOpCG2IAsmOp : array[topcg] of TAsmOp=(
+      A_None,      {OP_NONE}
+      A_None,      {OP_MOVE, replaced operation with direct load }
+      a_i32_add,   {OP_ADD,  simple addition          }
+      a_i32_and,   {OP_AND,  simple logical and       }
+      a_i32_div_u, {OP_DIV,  simple unsigned division }
+      a_i32_div_s, {OP_IDIV, simple signed division   }
+      a_i32_mul,   {OP_IMUL, simple signed multiply   }
+      a_i32_mul,   {OP_MUL,  simple unsigned multiply }
+      A_None,      {OP_NEG,  simple negate            } // neg = xor + 1
+      A_None,      {OP_NOT,  simple logical not       } // not = xor - 1
+      a_i32_or,    {OP_OR,   simple logical or        }
+      a_i32_shr_s, {OP_SAR,  arithmetic shift-right   }
+      a_i32_shl,   {OP_SHL,  logical shift left       }
+      a_i32_shr_u, {OP_SHR,  logical shift right      }
+      a_i32_sub,   {OP_SUB,  simple subtraction       }
+      a_i32_xor,   {OP_XOR,  simple exclusive or      }
+      a_i32_rotl,  {OP_ROL,  rotate left              }
+      a_i32_rotr   {OP_ROR   rotate right             }
+    );
+    TOpCG2LAsmOp : array[topcg] of TAsmOp=(
+      A_None,      {OP_NONE}
+      a_i64_load,  {OP_MOVE, replaced operation with direct load }
+      a_i64_add,   {OP_ADD,  simple addition          }
+      a_i64_and,   {OP_AND,  simple logical and       }
+      a_i64_div_u, {OP_DIV,  simple unsigned division }
+      a_i64_div_s, {OP_IDIV, simple signed division   }
+      a_i64_mul,   {OP_IMUL, simple signed multiply   }
+      a_i64_mul,   {OP_MUL,  simple unsigned multiply }
+      A_None,      {OP_NEG,  simple negate            } // neg = xor + 1
+      A_None,      {OP_NOT,  simple logical not       } // not = xor - 1
+      a_i64_or,    {OP_OR,   simple logical or        }
+      a_i64_shr_s, {OP_SAR,  arithmetic shift-right   }
+      a_i64_shl,   {OP_SHL,  logical shift left       }
+      a_i64_shr_u, {OP_SHR,  logical shift right      }
+      a_i64_sub,   {OP_SUB,  simple subtraction       }
+      a_i64_xor,   {OP_XOR,  simple exclusive or      }
+      a_i64_rotl,  {OP_ROL,  rotate left              }
+      a_i64_rotr   {OP_ROR   rotate right             }
+    );
+
+  constructor thlcgwasm.create;
+    begin
+      fevalstackheight:=0;
+      fmaxevalstackheight:=0;
+      fntypelookup:=TWasmProcTypeLookup.Create;
+    end;
+
+  destructor thlcgwasm.Destroy;
+    begin
+      fntypelookup.Free;
+      inherited Destroy;
+    end;
+
+  procedure thlcgwasm.incblock;
+    begin
+      inc(br_blocks);
+    end;
+
+  procedure thlcgwasm.decblock;
+    begin
+      dec(br_blocks);
+      if br_blocks<0 then
+        Internalerror(2019091807); // out of block
+    end;
+
+  procedure thlcgwasm.incstack(list: TAsmList; slots: longint);
+    begin
+      if slots=0 then
+        exit;
+      inc(fevalstackheight,slots);
+      if (fevalstackheight>fmaxevalstackheight) then
+        fmaxevalstackheight:=fevalstackheight;
+      if cs_asm_regalloc in current_settings.globalswitches then
+        list.concat(tai_comment.Create(strpnew('    allocated '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
+    end;
+
+  procedure thlcgwasm.decstack(list: TAsmList;slots: longint);
+    begin
+      if slots=0 then
+        exit;
+      dec(fevalstackheight,slots);
+      if (fevalstackheight<0) and
+         not(cs_no_regalloc in current_settings.globalswitches) then
+        internalerror(2010120501);
+      if cs_asm_regalloc in current_settings.globalswitches then
+        list.concat(tai_comment.Create(strpnew('    freed '+tostr(slots)+', stack height = '+tostr(fevalstackheight))));
+    end;
+
+  procedure thlcgwasm.a_load_const_cgpara(list: TAsmList; tosize: tdef; a: tcgint; const cgpara: TCGPara);
+    begin
+      tosize:=get_para_push_size(tosize);
+      if tosize=s8inttype then
+        a:=shortint(a)
+      else if tosize=s16inttype then
+        a:=smallint(a);
+      inherited a_load_const_cgpara(list, tosize, a, cgpara);
+    end;
+
+  function thlcgwasm.a_call_name(list: TAsmList; pd: tprocdef; const s: TSymStr; const paras: array of pcgpara; forceresdef: tdef; weak: boolean): tcgpara;
+    begin
+      list.concat(taicpu.op_sym(a_call,current_asmdata.RefAsmSymbol(s,AT_FUNCTION)));
+      result:=get_call_result_cgpara(pd,forceresdef);
+    end;
+
+
+  function thlcgwasm.a_call_reg(list: TAsmList; pd: tabstractprocdef; reg: tregister; const paras: array of pcgpara): tcgpara;
+    begin
+      a_load_reg_stack(list, ptrsinttype, reg);
+      current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_call_indirect,tcpuprocdef(pd).create_functype));
+      decstack(list,1);
+      result:=hlcg.get_call_result_cgpara(pd, nil);
+    end;
+
+
+  procedure thlcgwasm.a_load_const_stack(list : TAsmList;size : tdef;a : tcgint; typ: TRegisterType);
+    begin
+      case typ of
+        R_INTREGISTER,
+        R_ADDRESSREGISTER:
+          begin
+            case def_cgsize(size) of
+              OS_8,OS_16,OS_32,
+              OS_S8,OS_S16,OS_S32:
+                begin
+                  { convert cardinals to longints }
+                  list.concat(taicpu.op_const(a_i32_const, a));
+                end;
+              OS_64,OS_S64:
+                begin
+                  list.concat(taicpu.op_const(a_i64_const, a));
+                end;
+              else
+                internalerror(2010110702);
+            end;
+          end;
+        else
+          internalerror(2010110703);
+      end;
+      incstack(list,1);
+    end;
+
+  procedure thlcgwasm.a_loadaddr_ref_stack(list : TAsmList;fromsize, tosize : tdef;const ref : treference);
+    var
+      tmpref: treference;
+    begin
+      { you can't take the address of references, that are on the local stack }
+      if (ref.base=NR_EVAL_STACK_BASE) or (ref.index=NR_EVAL_STACK_BASE) or
+         (ref.base=NR_LOCAL_STACK_POINTER_REG) or (ref.index=NR_LOCAL_STACK_POINTER_REG) then
+        internalerror(2021010101);
+
+      tmpref:=ref;
+      tmpref.base:=NR_NO;
+      tmpref.index:=NR_NO;
+      list.Concat(taicpu.op_ref(a_i32_const, tmpref));
+      incstack(list, 1);
+      if ref.base<>NR_NO then
+        begin
+          list.Concat(taicpu.op_reg(a_local_get,ref.base));
+          incstack(list, 1);
+          list.Concat(taicpu.op_none(a_i32_add));
+          decstack(list, 1);
+        end;
+      if ref.index<>NR_NO then
+        begin
+          list.Concat(taicpu.op_reg(a_local_get,ref.index));
+          incstack(list, 1);
+          if ref.scalefactor>1 then
+            begin
+              list.Concat(taicpu.op_const(a_i32_const,ref.scalefactor));
+              incstack(list, 1);
+              list.Concat(taicpu.op_none(a_i32_mul));
+              decstack(list, 1);
+            end;
+          list.Concat(taicpu.op_none(a_i32_add));
+          decstack(list, 1);
+        end;
+    end;
+
+  procedure thlcgwasm.a_load_stack_loc(list: TAsmList; size: tdef; const loc: tlocation);
+    var
+      tmpref: treference;
+    begin
+      case loc.loc of
+        LOC_REGISTER,LOC_CREGISTER,
+        LOC_FPUREGISTER,LOC_CFPUREGISTER:
+          a_load_stack_reg(list,size,loc.register);
+        LOC_REFERENCE:
+          begin
+            tmpref:=loc.reference;
+            a_load_stack_ref(list,size,loc.reference,prepare_stack_for_ref(list,tmpref,false));
+          end;
+        else
+          internalerror(2011020501);
+      end;
+    end;
+
+  procedure thlcgwasm.a_load_loc_stack(list: TAsmList;size: tdef;const loc: tlocation);
+    var
+      tmpref: treference;
+      extra_slots: LongInt;
+    begin
+      case loc.loc of
+        LOC_REGISTER,LOC_CREGISTER,
+        LOC_FPUREGISTER,LOC_CFPUREGISTER:
+          a_load_reg_stack(list,size,loc.register);
+        LOC_REFERENCE,LOC_CREFERENCE:
+          begin
+            tmpref:=loc.reference;
+            extra_slots:=prepare_stack_for_ref(list,tmpref,false);
+            a_load_ref_stack(list,size,tmpref,extra_slots);
+          end;
+        LOC_CONSTANT:
+          a_load_const_stack(list,size,loc.value,def2regtyp(size));
+        else
+          internalerror(2011010401);
+      end;
+    end;
+
+  procedure thlcgwasm.a_loadfpu_const_stack(list: TAsmList; size: tdef; a: double);
+    begin
+      case tfloatdef(size).floattype of
+        s32real:
+          begin
+            list.concat(taicpu.op_single(a_f32_const, a));
+            incstack(list,1);
+          end;
+        s64real:
+          begin
+            list.concat(taicpu.op_double(a_f64_const,a));
+            incstack(list,1);
+          end
+        else
+          internalerror(2011010501);
+      end;
+    end;
+
+  procedure thlcgwasm.a_op_stack(list: TAsmList; op: topcg; size: tdef);
+    begin
+      case def_cgsize(size) of
+        OS_8,OS_S8,
+        OS_16,OS_S16,
+        OS_32,OS_S32:
+          begin
+            { boolean not: =0? for boolean }
+            { todo: should we also do this for cbool? }
+            if (op=OP_NOT) and is_pasbool(size) then
+              list.concat(taicpu.op_none(a_i32_eqz))
+            else
+              begin
+                if op=OP_NOT then
+                  begin
+                    { not = xor -1 for integer }
+                    a_load_const_stack(list,s32inttype,high(cardinal),R_INTREGISTER);
+                    op:=OP_XOR;
+                  end
+                else if op=OP_NEG then
+                  begin
+                    { neg = *(-1) }
+                    a_load_const_stack(list,s32inttype,-1,R_INTREGISTER);
+                    op:=OP_MUL;
+                  end;
+                if TOpCG2IAsmOp[op]=A_None then
+                  internalerror(2010120532);
+                list.concat(taicpu.op_none(TOpCG2IAsmOp[op]));
+                decstack(list,1);
+              end;
+            maybe_adjust_op_result(list,op,size);
+          end;
+        OS_64,OS_S64:
+          begin
+            { unsigned 64 bit division must be done via a helper }
+            if op=OP_DIV then
+              internalerror(2010120530);
+            { boolean not: =0? for boolean }
+            { todo: should we also do this for cbool? }
+            if (op=OP_NOT) and is_pasbool(size) then
+              list.concat(taicpu.op_none(a_i64_eqz))
+            else
+              begin
+                if op=OP_NOT then
+                  begin
+                    { not = xor -1 for integer }
+                    a_load_const_stack(list,s64inttype,-1,R_INTREGISTER);
+                    op:=OP_XOR;
+                  end
+                else if op=OP_NEG then
+                  begin
+                    { neg = *(-1) }
+                    a_load_const_stack(list,s64inttype,-1,R_INTREGISTER);
+                    op:=OP_MUL;
+                  end;
+                if TOpCG2LAsmOp[op]=A_None then
+                  internalerror(2010120533);
+                list.concat(taicpu.op_none(TOpCG2LAsmOp[op]));
+                decstack(list,1);
+              end;
+          end;
+        else
+          internalerror(2010120531);
+      end;
+    end;
+
+  procedure thlcgwasm.a_op_const_stack(list: TAsmList;op: topcg;size: tdef;a: tcgint);
+    begin
+      case op of
+        OP_NEG,OP_NOT:
+          internalerror(2011010801);
+        else
+          a_load_const_stack(list,size,a,R_INTREGISTER);
+      end;
+      a_op_stack(list,op,size);
+    end;
+
+  procedure thlcgwasm.a_op_reg_stack(list: TAsmList; op: topcg; size: tdef; reg: tregister);
+    begin
+      a_load_reg_stack(list,size,reg);
+      a_op_stack(list,op,size);
+    end;
+
+  procedure thlcgwasm.a_op_ref_stack(list: TAsmList; op: topcg; size: tdef; const ref: treference);
+    var
+      tmpref: treference;
+    begin
+      { ref must not be the stack top, because that may indicate an error
+        (it means that we will perform an operation of the stack top onto
+         itself, so that means the two values have been loaded manually prior
+         to calling this routine, instead of letting this routine load one of
+         them; if something like that is needed, call a_op_stack() directly) }
+      if ref.base=NR_EVAL_STACK_BASE then
+        internalerror(2010121102);
+      tmpref:=ref;
+      a_load_ref_stack(list,size,tmpref,prepare_stack_for_ref(list,tmpref,false));
+      a_op_stack(list,op,size);
+    end;
+
+  procedure thlcgwasm.a_op_loc_stack(list: TAsmList; op: topcg; size: tdef; const loc: tlocation);
+    begin
+      case loc.loc of
+        LOC_REGISTER,LOC_CREGISTER:
+          a_op_reg_stack(list,op,size,loc.register);
+        LOC_REFERENCE,LOC_CREFERENCE:
+          a_op_ref_stack(list,op,size,loc.reference);
+        LOC_CONSTANT:
+          a_op_const_stack(list,op,size,loc.value);
+        else
+          internalerror(2011011415)
+      end;
+    end;
+
+  procedure thlcgwasm.a_cmp_const_loc_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const loc: tlocation);
+    var
+      tmpreg: tregister;
+    begin
+      case loc.loc of
+        LOC_REGISTER,LOC_CREGISTER:
+          a_cmp_const_reg_stack(list,size,cmp_op,a,loc.register);
+        LOC_REFERENCE,LOC_CREFERENCE:
+          a_cmp_const_ref_stack(list,size,cmp_op,a,loc.reference);
+        LOC_SUBSETREG, LOC_CSUBSETREG:
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_subsetreg_reg(list,size,size,loc.sreg,tmpreg);
+            a_cmp_const_reg_stack(list,size,cmp_op,a,tmpreg);
+          end;
+        LOC_SUBSETREF, LOC_CSUBSETREF:
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_subsetref_reg(list,size,size,loc.sref,tmpreg);
+            a_cmp_const_reg_stack(list,size,cmp_op,a,tmpreg);
+          end;
+        else
+          internalerror(2010120430);
+      end;
+    end;
+
+  procedure thlcgwasm.a_cmp_const_ref_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference);
+    var
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      if tmpref.base<>NR_EVAL_STACK_BASE then
+        a_load_ref_stack(list,size,tmpref,prepare_stack_for_ref(list,tmpref,false));
+      a_load_const_stack(list,size,a,def2regtyp(size));
+      a_cmp_stack_stack(list,size,cmp_op);
+    end;
+
+  procedure thlcgwasm.a_cmp_const_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister);
+    begin
+      a_load_reg_stack(list,size,reg);
+      a_load_const_stack(list,size,a,def2regtyp(size));
+      a_cmp_stack_stack(list,size,cmp_op);
+    end;
+
+  procedure thlcgwasm.a_cmp_ref_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister);
+    var
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      a_load_reg_stack(list,size,reg);
+      if tmpref.base<>NR_EVAL_STACK_BASE then
+        a_load_ref_stack(list,size,tmpref,prepare_stack_for_ref(list,tmpref,false))
+      else
+        cmp_op:=swap_opcmp(cmp_op);
+      a_cmp_stack_stack(list,size,cmp_op);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_ref_stack(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference);
+    var
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      if tmpref.base<>NR_EVAL_STACK_BASE then
+        a_load_ref_stack(list,size,ref,prepare_stack_for_ref(list,tmpref,false));
+      a_load_reg_stack(list,size,reg);
+      a_cmp_stack_stack(list,size,cmp_op);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister);
+    begin
+      a_load_reg_stack(list,size,reg2);
+      a_load_reg_stack(list,size,reg1);
+      a_cmp_stack_stack(list,size,cmp_op);
+    end;
+
+  procedure thlcgwasm.a_cmp_subsetreg_reg_stack(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sreg: tsubsetregister; reg: tregister);
+    var
+      tmpreg: tregister;
+    begin
+      tmpreg:=getintregister(list,cmpsize);
+      a_load_subsetreg_reg(list,fromsubsetsize,cmpsize,sreg,tmpreg);
+      a_cmp_reg_reg_stack(list,cmpsize,cmp_op,tmpreg,reg);
+    end;
+
+  procedure thlcgwasm.a_cmp_subsetref_reg_stack(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sref: tsubsetreference; reg: tregister);
+    var
+      tmpreg: tregister;
+    begin
+      tmpreg:=getintregister(list,cmpsize);
+      a_load_subsetref_reg(list,fromsubsetsize,cmpsize,sref,tmpreg);
+      a_cmp_reg_reg_stack(list,cmpsize,cmp_op,tmpreg,reg);
+    end;
+
+  procedure thlcgwasm.a_cmp_loc_reg_stack(list: TAsmList; size: tdef; cmp_op: topcmp; const loc: tlocation; reg: tregister);
+    begin
+      case loc.loc of
+        LOC_REGISTER,
+        LOC_CREGISTER:
+          a_cmp_reg_reg_stack(list,size,cmp_op,loc.register,reg);
+        LOC_REFERENCE,
+        LOC_CREFERENCE :
+          a_cmp_ref_reg_stack(list,size,cmp_op,loc.reference,reg);
+        LOC_CONSTANT:
+          a_cmp_const_reg_stack(list,size,cmp_op,loc.value,reg);
+        LOC_SUBSETREG,
+        LOC_CSUBSETREG:
+          a_cmp_subsetreg_reg_stack(list,size,size,cmp_op,loc.sreg,reg);
+        LOC_SUBSETREF,
+        LOC_CSUBSETREF:
+          a_cmp_subsetref_reg_stack(list,size,size,cmp_op,loc.sref,reg);
+        else
+          internalerror(2010120431);
+      end;
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_loc_stack(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const loc: tlocation);
+    begin
+      a_cmp_loc_reg_stack(list,size,swap_opcmp(cmp_op),loc,reg);
+    end;
+
+  procedure thlcgwasm.a_cmp_ref_loc_stack(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; const loc: tlocation);
+    var
+      tmpreg: tregister;
+    begin
+      case loc.loc of
+        LOC_REGISTER,LOC_CREGISTER:
+          a_cmp_ref_reg_stack(list,size,cmp_op,ref,loc.register);
+        LOC_REFERENCE,LOC_CREFERENCE:
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_ref_reg(list,size,size,loc.reference,tmpreg);
+            a_cmp_ref_reg_stack(list,size,cmp_op,ref,tmpreg);
+          end;
+        LOC_CONSTANT:
+          begin
+            a_cmp_const_ref_stack(list,size,swap_opcmp(cmp_op),loc.value,ref);
+          end;
+        LOC_SUBSETREG, LOC_CSUBSETREG:
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_ref_reg(list,size,size,loc.reference,tmpreg);
+            a_cmp_subsetreg_reg_stack(list,size,size,swap_opcmp(cmp_op),loc.sreg,tmpreg);
+          end;
+        LOC_SUBSETREF, LOC_CSUBSETREF:
+          begin
+            tmpreg:=getintregister(list,size);
+            a_load_ref_reg(list,size,size,loc.reference,tmpreg);
+            a_cmp_subsetref_reg_stack(list,size,size,swap_opcmp(cmp_op),loc.sref,tmpreg);
+          end;
+        else
+          internalerror(2010120432);
+      end;
+    end;
+
+  procedure thlcgwasm.a_cmp_const_loc_br(list: TAsmList; size: tdef;cmp_op: topcmp; a: tcgint; const loc: tlocation; br: Integer);
+    begin
+      a_cmp_const_loc_stack(list,size,cmp_op,a,loc);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_const_ref_br(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; br: Integer);
+    begin
+      a_cmp_const_ref_stack(list,size,cmp_op,a,ref);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_const_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; br: Integer);
+    begin
+      a_cmp_const_reg_stack(list,size,cmp_op,a,reg);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_ref_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; br: Integer);
+    begin
+      a_cmp_ref_reg_stack(list,size,cmp_op,ref,reg);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_ref_br(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; br: Integer);
+    begin
+      a_cmp_reg_ref_stack(list,size,cmp_op,reg,ref);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_reg_br(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; br: Integer);
+    begin
+      a_cmp_reg_reg_stack(list,size,cmp_op,reg1,reg2);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_subsetreg_reg_br(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sreg: tsubsetregister; reg: tregister; br: Integer);
+    begin
+      a_cmp_subsetreg_reg_stack(list,fromsubsetsize,cmpsize,cmp_op,sreg,reg);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_subsetref_reg_br(list: TAsmList; fromsubsetsize, cmpsize: tdef; cmp_op: topcmp; const sref: tsubsetreference; reg: tregister; br: Integer);
+    begin
+      a_cmp_subsetref_reg_stack(list,fromsubsetsize,cmpsize,cmp_op,sref,reg);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_loc_reg_br(list : TAsmList;size : tdef;cmp_op : topcmp; const loc: tlocation; reg : tregister; br: Integer);
+    begin
+      a_cmp_loc_reg_stack(list,size,cmp_op,loc,reg);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_loc_br(list : TAsmList;size : tdef;cmp_op : topcmp; reg: tregister; const loc: tlocation; br: Integer);
+    begin
+      a_cmp_reg_loc_stack(list,size,cmp_op,reg,loc);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.a_cmp_ref_loc_br(list: TAsmList; size: tdef;cmp_op: topcmp; const ref: treference; const loc: tlocation; br: Integer);
+    begin
+      a_cmp_ref_loc_stack(list,size,cmp_op,ref,loc);
+      current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,br));
+      thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+    end;
+
+  procedure thlcgwasm.g_reference_loc(list: TAsmList; def: tdef; const fromloc: tlocation; out toloc: tlocation);
+    begin
+      case fromloc.loc of
+        LOC_CREFERENCE,
+        LOC_REFERENCE:
+          begin
+            toloc:=fromloc;
+            if (fromloc.reference.base<>NR_NO) and
+               (fromloc.reference.base<>current_procinfo.framepointer) and
+               (fromloc.reference.base<>NR_STACK_POINTER_REG) then
+              g_allocload_reg_reg(list,voidpointertype,fromloc.reference.base,toloc.reference.base,R_ADDRESSREGISTER);
+          end;
+        else
+          inherited;
+      end;
+    end;
+
+    procedure thlcgwasm.a_cmp_stack_stack(list: TAsmlist; size: tdef; cmp_op: topcmp);
+      const
+        opcmp32: array[topcmp] of tasmop = (
+          A_None,     { OC_NONE, }
+          a_i32_eq,   { OC_EQ,   equality comparison              }
+          a_i32_gt_s, { OC_GT,   greater than (signed)            }
+          a_i32_lt_s, { OC_LT,   less than (signed)               }
+          a_i32_ge_s, { OC_GTE,  greater or equal than (signed)   }
+          a_i32_le_s, { OC_LTE,  less or equal than (signed)      }
+          a_i32_ne,   { OC_NE,   not equal                        }
+          a_i32_le_u, { OC_BE,   less or equal than (unsigned)    }
+          a_i32_lt_u, { OC_B,    less than (unsigned)             }
+          a_i32_ge_u, { OC_AE,   greater or equal than (unsigned) }
+          a_i32_gt_u  { OC_A     greater than (unsigned)          }
+        );
+      const
+        opcmp64: array[TOpCmp] of TAsmOp = (A_None,
+           a_i64_eq,               // OC_EQ
+           a_i64_gt_s, a_i64_lt_s, // OC_GT, OC_LT
+           a_i64_ge_s, a_i64_le_s, // OC_GTE, OC_LTE
+           a_i64_ne,               // OC_NE
+           a_i64_le_u, a_i64_lt_u, // OC_BE, OC_B
+           a_i64_ge_u, a_i64_gt_u  // OC_AE, OC_A
+        );
+
+      var
+        cgsize: tcgsize;
+      begin
+        case def2regtyp(size) of
+          R_INTREGISTER,
+          R_ADDRESSREGISTER:
+            begin
+              cgsize:=def_cgsize(size);
+              case cgsize of
+                OS_S8,OS_8,
+                OS_16,OS_S16,
+                OS_S32,OS_32:
+                  begin
+                    list.concat(taicpu.op_none(opcmp32[cmp_op]));
+                    decstack(list,1);
+                  end;
+                OS_64,OS_S64:
+                  begin
+                    list.concat(taicpu.op_none(opcmp64[cmp_op]));
+                    decstack(list,1);
+                  end;
+                else
+                  internalerror(2010120538);
+              end;
+            end;
+          else
+            internalerror(2010120538);
+        end;
+      end;
+
+    procedure thlcgwasm.maybe_adjust_op_result(list: TAsmList; op: TOpCg; size: tdef);
+      const
+        overflowops = [OP_MUL,OP_SHL,OP_ADD,OP_SUB,OP_NOT,OP_NEG];
+      begin
+        if (op in overflowops) and
+           (def_cgsize(size) in [OS_8,OS_S8,OS_16,OS_S16]) then
+          resize_stack_int_val(list,s32inttype,size,false);
+      end;
+
+  procedure thlcgwasm.gen_load_uninitialized_function_result(list: TAsmList; pd: tprocdef; resdef: tdef; const resloc: tcgpara);
+    begin
+      { nothing to do for ret_in_param results }
+      if paramanager.ret_in_param(pd.returndef,pd) then
+        exit;
+      { constructors don't return anything in Java }
+      if pd.proctypeoption=potype_constructor then
+        exit;
+      { must return a value of the correct type on the evaluation stack }
+      case def2regtyp(resdef) of
+        R_INTREGISTER,
+        R_ADDRESSREGISTER:
+          a_load_const_cgpara(list,resdef,0,resloc);
+        R_FPUREGISTER:
+          case tfloatdef(resdef).floattype of
+            s32real:
+              begin
+                list.concat(taicpu.op_single(a_f32_const, 0));
+                incstack(list,1);
+              end;
+            s64real:
+              begin
+                list.concat(taicpu.op_double(a_f64_const, 0));
+                incstack(list,1);
+              end;
+            else
+              internalerror(2011010302);
+          end
+        else
+          internalerror(2011010301);
+      end;
+    end;
+
+
+  function thlcgwasm.g_call_system_proc_intern(list: TAsmList; pd: tprocdef; const paras: array of pcgpara; forceresdef: tdef): tcgpara;
+    begin
+      result:=inherited;
+      pd.init_paraloc_info(callerside);
+      g_adjust_stack_after_call(list,pd);
+    end;
+
+
+  function thlcgwasm.prepare_stack_for_ref(list: TAsmList; var ref: treference; dup: boolean): longint;
+    begin
+      result:=0;
+      { fake location that indicates the value is already on the stack? }
+      if (ref.base=NR_EVAL_STACK_BASE) or (ref.base=NR_LOCAL_STACK_POINTER_REG) then
+        exit;
+
+      if (ref.base=NR_NO) and (ref.index<>NR_NO) and (ref.scalefactor<=1) then
+        begin
+          ref.base:=ref.index;
+          ref.index:=NR_NO;
+        end;
+
+      // setting up memory offset
+      if assigned(ref.symbol) and (ref.base=NR_NO) and (ref.index=NR_NO) then
+        begin
+          list.Concat(taicpu.op_const(a_i32_const,ref.offset));
+          incstack(list,1);
+          if dup then
+            begin
+              list.Concat(taicpu.op_const(a_i32_const,ref.offset));
+              incstack(list,1);
+            end;
+          ref.offset:=0;
+          result:=1;
+        end
+      else if ref.index <> NR_NO then // array access
+        begin
+          // it's just faster to sum two of those together
+          list.Concat(taicpu.op_reg(a_local_get, ref.base));
+          incstack(list,1);
+          list.Concat(taicpu.op_reg(a_local_get, ref.index));
+          incstack(list,1);
+          list.Concat(taicpu.op_none(a_i32_add));
+          decstack(list,1);
+          if ref.offset<0 then
+            begin
+              list.Concat(taicpu.op_const(a_i32_const,-ref.offset));
+              incstack(list,1);
+              list.Concat(taicpu.op_none(a_i32_sub));
+              decstack(list,1);
+            end;
+          if dup then
+            begin
+              list.Concat(taicpu.op_reg(a_local_get, ref.base));
+              incstack(list,1);
+              list.Concat(taicpu.op_reg(a_local_get, ref.index));
+              incstack(list,1);
+              list.Concat(taicpu.op_none(a_i32_add));
+              decstack(list,1);
+              if ref.offset<0 then
+                begin
+                  list.Concat(taicpu.op_const(a_i32_const,-ref.offset));
+                  incstack(list,1);
+                  list.Concat(taicpu.op_none(a_i32_sub));
+                  decstack(list,1);
+                end;
+            end;
+          ref.base:=NR_NO;
+          ref.index:=NR_NO;
+          if ref.offset<0 then
+            ref.offset:=0;
+          result:=1;
+        end
+      else if (ref.base<>NR_NO) then
+        begin
+          if (ref.base<>NR_STACK_POINTER_REG) then
+            begin
+              { regular field -> load self on the stack }
+              a_load_reg_stack(list,voidpointertype,ref.base);
+              if ref.offset<0 then
+                begin
+                  list.Concat(taicpu.op_const(a_i32_const,-ref.offset));
+                  incstack(list,1);
+                  list.Concat(taicpu.op_none(a_i32_sub));
+                  decstack(list,1);
+                end;
+              if dup then
+                begin
+                  a_load_reg_stack(list,voidpointertype,ref.base);
+                  if ref.offset<0 then
+                    begin
+                      list.Concat(taicpu.op_const(a_i32_const,-ref.offset));
+                      incstack(list,1);
+                      list.Concat(taicpu.op_none(a_i32_sub));
+                      decstack(list,1);
+                    end;
+                end;
+              if ref.offset<0 then
+                ref.offset:=0;
+              ref.base:=NR_NO;
+              result:=1;
+            end
+          else // if (ref.base = NR_FRAME_POINTER_REG) then
+            begin
+              internalerror(2021012202);
+              //list.Concat(taicpu.op_sym(a_local_get, current_asmdata.RefAsmSymbol(FRAME_POINTER_SYM,AT_ADDR) ));
+              //incstack(list,1);
+            end;
+        end
+      else
+        begin
+          { static field -> nothing to do here, except for validity check }
+          {if not assigned(ref.symbol) or
+             (ref.offset<>0) then
+          begin
+            internalerror(2010120525);
+          end;}
+        end;
+    end;
+
+  procedure thlcgwasm.a_load_const_reg(list: TAsmList; tosize: tdef; a: tcgint; register: tregister);
+    begin
+      a_load_const_stack(list,tosize,a,def2regtyp(tosize));
+      a_load_stack_reg(list,tosize,register);
+    end;
+
+  procedure thlcgwasm.a_load_const_ref(list: TAsmList; tosize: tdef; a: tcgint; const ref: treference);
+    var
+      extra_slots: longint;
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      extra_slots:=prepare_stack_for_ref(list,tmpref,false);
+      a_load_const_stack(list,tosize,a,def2regtyp(tosize));
+      a_load_stack_ref(list,tosize,tmpref,extra_slots);
+    end;
+
+  procedure thlcgwasm.a_load_reg_ref(list: TAsmList; fromsize, tosize: tdef; register: tregister; const ref: treference);
+    var
+      extra_slots: longint;
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      extra_slots:=prepare_stack_for_ref(list,tmpref,false);
+      a_load_reg_stack(list,fromsize,register);
+      if def2regtyp(fromsize)=R_INTREGISTER then
+        resize_stack_int_val(list,fromsize,tosize,assigned(tmpref.symbol));
+      a_load_stack_ref(list,tosize,tmpref,extra_slots);
+    end;
+
+  procedure thlcgwasm.a_load_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
+    begin
+      a_load_reg_stack(list,fromsize,reg1);
+      if def2regtyp(fromsize)=R_INTREGISTER then
+        resize_stack_int_val(list,fromsize,tosize,false);
+      a_load_stack_reg(list,tosize,reg2);
+    end;
+
+  procedure thlcgwasm.a_load_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; register: tregister);
+    var
+      extra_slots: longint;
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      extra_slots:=prepare_stack_for_ref(list,tmpref,false);
+      a_load_ref_stack(list,fromsize,tmpref,extra_slots);
+
+      if def2regtyp(fromsize)=R_INTREGISTER then
+        resize_stack_int_val(list,fromsize,tosize,false);
+      a_load_stack_reg(list,tosize,register);
+    end;
+
+  procedure thlcgwasm.a_load_ref_ref(list: TAsmList; fromsize, tosize: tdef; const sref: treference; const dref: treference);
+    var
+      extra_sslots,
+      extra_dslots: longint;
+      tmpsref, tmpdref: treference;
+      tmpreg: tregister;
+    begin
+      if sref.base<>NR_EVAL_STACK_BASE then
+        begin
+          tmpsref:=sref;
+          tmpdref:=dref;
+          { make sure the destination reference is on top, since in the end the
+            order has to be "destref, value" -> first create "destref, sourceref" }
+          extra_dslots:=prepare_stack_for_ref(list,tmpdref,false);
+          extra_sslots:=prepare_stack_for_ref(list,tmpsref,false);
+          a_load_ref_stack(list,fromsize,tmpsref,extra_sslots);
+          if def2regtyp(fromsize)=R_INTREGISTER then
+            resize_stack_int_val(list,fromsize,tosize,assigned(tmpdref.symbol));
+          a_load_stack_ref(list,tosize,tmpdref,extra_dslots);
+        end
+      else
+        begin
+          { verify if we have the same reference }
+          if references_equal(sref,dref) then
+            exit;
+          tmpreg:=getregisterfordef(list,tosize);
+          a_load_ref_reg(list,fromsize,tosize,sref,tmpreg);
+          a_load_reg_ref(list,tosize,tosize,tmpreg,dref);
+        end;
+    end;
+
+  procedure thlcgwasm.a_loadaddr_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; r: tregister);
+    begin
+      a_loadaddr_ref_stack(list,fromsize,tosize,ref);
+      a_load_stack_reg(list, tosize, r);
+    end;
+
+  procedure thlcgwasm.a_op_const_reg(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; reg: TRegister);
+    begin
+      a_op_const_reg_reg(list,op,size,a,reg,reg);
+    end;
+
+  procedure thlcgwasm.a_op_const_reg_reg(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister);
+    begin
+      a_load_reg_stack(list,size,src);
+      a_op_const_stack(list,op,size,a);
+      a_load_stack_reg(list,size,dst);
+    end;
+
+  procedure thlcgwasm.a_op_const_ref(list: TAsmList; Op: TOpCG; size: tdef; a: tcgint; const ref: TReference);
+    var
+      extra_slots: longint;
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      extra_slots:=prepare_stack_for_ref(list,tmpref,true);
+      { TODO, here or in peepholeopt: use iinc when possible }
+      a_load_ref_stack(list,size,tmpref,extra_slots);
+      a_op_const_stack(list,op,size,a);
+      { for android verifier }
+      if (def2regtyp(size)=R_INTREGISTER) and
+         (assigned(tmpref.symbol)) then
+        resize_stack_int_val(list,size,size,true);
+      a_load_stack_ref(list,size,tmpref,extra_slots);
+    end;
+
+  procedure thlcgwasm.a_op_ref_reg(list: TAsmList; Op: TOpCG; size: tdef; const ref: TReference; reg: TRegister);
+    begin
+      if not(op in [OP_NOT,OP_NEG]) then
+        a_load_reg_stack(list,size,reg);
+      a_op_ref_stack(list,op,size,ref);
+      a_load_stack_reg(list,size,reg);
+    end;
+
+  procedure thlcgwasm.a_op_reg_reg_reg(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister);
+    begin
+      if not(op in [OP_NOT,OP_NEG]) then
+        a_load_reg_stack(list,size,src2);
+      a_op_reg_stack(list,op,size,src1);
+      a_load_stack_reg(list,size,dst);
+    end;
+
+  procedure thlcgwasm.a_op_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; reg1, reg2: TRegister);
+    begin
+      a_op_reg_reg_reg(list,op,size,reg1,reg2,reg2);
+    end;
+
+  procedure thlcgwasm.a_op_const_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; a: tcgint; src, dst: tregister; setflags: boolean; var ovloc: tlocation);
+    var
+      tmpreg: tregister;
+    begin
+      if not setflags then
+        begin
+          inherited;
+          exit;
+        end;
+      tmpreg:=getintregister(list,size);
+      a_load_const_reg(list,size,a,tmpreg);
+      a_op_reg_reg_reg_checkoverflow(list,op,size,tmpreg,src,dst,true,ovloc);
+    end;
+
+  procedure thlcgwasm.a_op_reg_reg_reg_checkoverflow(list: TAsmList; op: TOpCg; size: tdef; src1, src2, dst: tregister; setflags: boolean; var ovloc: tlocation);
+    var
+      orgsrc1, orgsrc2: tregister;
+      docheck: boolean;
+      lab: tasmlabel;
+    begin
+      if not setflags then
+        begin
+          inherited;
+          exit;
+        end;
+      { anything else cannot overflow }
+      docheck:=size.size in [4,8];
+      if docheck then
+        begin
+          orgsrc1:=src1;
+          orgsrc2:=src2;
+          if src1=dst then
+            begin
+              orgsrc1:=getintregister(list,size);
+              a_load_reg_reg(list,size,size,src1,orgsrc1);
+            end;
+          if src2=dst then
+            begin
+              orgsrc2:=getintregister(list,size);
+              a_load_reg_reg(list,size,size,src2,orgsrc2);
+            end;
+        end;
+      a_op_reg_reg_reg(list,op,size,src1,src2,dst);
+      if docheck then
+        begin
+          { * signed overflow for addition iff
+             - src1 and src2 are negative and result is positive (excep in case of
+               subtraction, then sign of src1 has to be inverted)
+             - src1 and src2 are positive and result is negative
+              -> Simplified boolean equivalent (in terms of sign bits):
+                 not(src1 xor src2) and (src1 xor dst)
+
+             for subtraction, multiplication: invert src1 sign bit
+             for division: handle separately (div by zero, low(inttype) div -1),
+               not supported by this code
+
+            * unsigned overflow iff carry out, aka dst < src1 or dst < src2
+          }
+          location_reset(ovloc,LOC_REGISTER,OS_S32);
+          { not pasbool8, because then we'd still have to convert the integer to
+            a boolean via branches for Dalvik}
+          ovloc.register:=getintregister(list,s32inttype);
+          if not ((size.typ=pointerdef) or
+                 ((size.typ=orddef) and
+                  (torddef(size).ordtype in [u64bit,u16bit,u32bit,u8bit,uchar,
+                                             pasbool1,pasbool8,pasbool16,pasbool32,pasbool64]))) then
+            begin
+              a_load_reg_stack(list,size,src1);
+              if op in [OP_SUB,OP_IMUL] then
+                a_op_stack(list,OP_NOT,size);
+              a_op_reg_stack(list,OP_XOR,size,src2);
+              a_op_stack(list,OP_NOT,size);
+              a_load_reg_stack(list,size,src1);
+              a_op_reg_stack(list,OP_XOR,size,dst);
+              a_op_stack(list,OP_AND,size);
+              a_op_const_stack(list,OP_SHR,size,(size.size*8)-1);
+              if size.size=8 then
+                begin
+                  //todo: any operands needed?
+                  list.concat(taicpu.op_none(a_i32_wrap_i64));
+                end;
+            end
+          else
+            begin
+              a_load_const_stack(list,s32inttype,0,R_INTREGISTER);
+              current_asmdata.getjumplabel(lab);
+              { can be optimized by removing duplicate xor'ing to convert dst from
+                signed to unsigned quadrant }
+              a_cmp_reg_reg_label(list,size,OC_B,dst,src1,lab);
+              a_cmp_reg_reg_label(list,size,OC_B,dst,src2,lab);
+              a_op_const_stack(list,OP_XOR,s32inttype,1);
+              a_label(list,lab);
+            end;
+          a_load_stack_reg(list,s32inttype,ovloc.register);
+        end
+      else
+        ovloc.loc:=LOC_VOID;
+    end;
+
+  procedure thlcgwasm.a_cmp_const_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; const ref: treference; l: tasmlabel);
+    begin
+      internalerror(2021011802);
+    end;
+
+  procedure thlcgwasm.a_cmp_const_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; a: tcgint; reg: tregister; l: tasmlabel);
+    begin
+      internalerror(2021011802);
+    end;
+
+  procedure thlcgwasm.a_cmp_ref_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; const ref: treference; reg: tregister; l: tasmlabel);
+    begin
+      internalerror(2021011802);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_ref_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg: tregister; const ref: treference; l: tasmlabel);
+    begin
+      internalerror(2021011802);
+    end;
+
+  procedure thlcgwasm.a_cmp_reg_reg_label(list: TAsmList; size: tdef; cmp_op: topcmp; reg1, reg2: tregister; l: tasmlabel);
+    begin
+      internalerror(2021011802);
+    end;
+
+  procedure thlcgwasm.a_jmp_always(list: TAsmList; l: tasmlabel);
+    begin
+      if l=current_procinfo.CurrBreakLabel then
+        list.concat(taicpu.op_const(a_br,br_blocks-loopBreakBr))
+      else if l=current_procinfo.CurrContinueLabel then
+        list.concat(taicpu.op_const(a_br,br_blocks-loopContBr))
+      else if l=current_procinfo.CurrExitLabel then
+        list.concat(taicpu.op_const(a_br,br_blocks-exitBr))
+      else
+        Internalerror(2019091806); // unexpected jump
+    end;
+
+  procedure thlcgwasm.a_loadfpu_ref_ref(list: TAsmList; fromsize, tosize: tdef; const ref1, ref2: treference);
+    var
+      dstack_slots: longint;
+      tmpref1, tmpref2: treference;
+    begin
+      tmpref1:=ref1;
+      tmpref2:=ref2;
+      dstack_slots:=prepare_stack_for_ref(list,tmpref2,false);
+      a_load_ref_stack(list,fromsize,tmpref1,prepare_stack_for_ref(list,tmpref1,false));
+      resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
+      a_load_stack_ref(list,tosize,tmpref2,dstack_slots);
+    end;
+
+  procedure thlcgwasm.a_loadfpu_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister);
+    var
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      a_load_ref_stack(list,fromsize,tmpref,prepare_stack_for_ref(list,tmpref,false));
+      resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
+      a_load_stack_reg(list,tosize,reg);
+    end;
+
+  procedure thlcgwasm.a_loadfpu_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference);
+    var
+      dstack_slots: longint;
+      tmpref: treference;
+    begin
+      tmpref:=ref;
+      dstack_slots:=prepare_stack_for_ref(list,tmpref,false);
+      a_load_reg_stack(list,fromsize,reg);
+      resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
+      a_load_stack_ref(list,tosize,tmpref,dstack_slots);
+    end;
+
+  procedure thlcgwasm.a_loadfpu_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister);
+    begin
+      a_load_reg_stack(list,fromsize,reg1);
+      resizestackfpuval(list,def_cgsize(fromsize),def_cgsize(tosize));
+      a_load_stack_reg(list,tosize,reg2);
+    end;
+
+  procedure thlcgwasm.g_concatcopy(list: TAsmList; size: tdef; const source, dest: treference);
+    var
+      pd: tprocdef;
+      cgpara1,cgpara2,cgpara3 : TCGPara;
+    begin
+      if (source.base=NR_EVAL_STACK_BASE) or (source.base=NR_LOCAL_STACK_POINTER_REG) or
+         (source.index=NR_EVAL_STACK_BASE) or (source.index=NR_LOCAL_STACK_POINTER_REG) or
+         (dest.base=NR_EVAL_STACK_BASE) or (dest.base=NR_LOCAL_STACK_POINTER_REG) or
+         (dest.index=NR_EVAL_STACK_BASE) or (dest.index=NR_LOCAL_STACK_POINTER_REG) or
+         (size.size in [1,2,4,8]) then
+        inherited
+      else
+        begin
+          pd:=search_system_proc('MOVE');
+          cgpara1.init;
+          cgpara2.init;
+          cgpara3.init;
+          paramanager.getcgtempparaloc(list,pd,1,cgpara1);
+          paramanager.getcgtempparaloc(list,pd,2,cgpara2);
+          paramanager.getcgtempparaloc(list,pd,3,cgpara3);
+          if pd.is_pushleftright then
+            begin
+              { load source }
+              a_loadaddr_ref_cgpara(list,voidtype,source,cgpara1);
+              { load destination }
+              a_loadaddr_ref_cgpara(list,voidtype,dest,cgpara2);
+              { load size }
+              a_load_const_cgpara(list,sizesinttype,size.size,cgpara3);
+            end
+          else
+            begin
+              { load size }
+              a_load_const_cgpara(list,sizesinttype,size.size,cgpara3);
+              { load destination }
+              a_loadaddr_ref_cgpara(list,voidtype,dest,cgpara2);
+              { load source }
+              a_loadaddr_ref_cgpara(list,voidtype,source,cgpara1);
+            end;
+          paramanager.freecgpara(list,cgpara3);
+          paramanager.freecgpara(list,cgpara2);
+          paramanager.freecgpara(list,cgpara1);
+          g_call_system_proc(list,pd,[@cgpara1,@cgpara2,@cgpara3],nil).resetiftemp;
+          cgpara3.done;
+          cgpara2.done;
+          cgpara1.done;
+        end;
+    end;
+
+  procedure thlcgwasm.g_proc_entry(list: TAsmList; localsize: longint; nostackframe: boolean);
+    var
+      pd: tcpuprocdef;
+    begin
+      pd:=tcpuprocdef(current_procinfo.procdef);
+      g_procdef(list,pd);
+
+      ttgwasm(tg).allocframepointer(list,pd.frame_pointer_ref);
+      ttgwasm(tg).allocbasepointer(list,pd.base_pointer_ref);
+
+      g_fingerprint(list);
+
+      list.Concat(taicpu.op_sym(a_global_get,current_asmdata.RefAsmSymbol(STACK_POINTER_SYM,AT_LABEL)));
+      incstack(list,1);
+      list.Concat(taicpu.op_ref(a_local_set,pd.base_pointer_ref));
+      decstack(list,1);
+
+      if (localsize>0) then begin
+        list.Concat(taicpu.op_ref(a_local_get,pd.base_pointer_ref));
+        incstack(list,1);
+        list.concat(taicpu.op_const(a_i32_const, localsize ));
+        incstack(list,1);
+        list.concat(taicpu.op_none(a_i32_sub));
+        decstack(list,1);
+        list.Concat(taicpu.op_ref(a_local_set,pd.frame_pointer_ref));
+        decstack(list,1);
+        list.Concat(taicpu.op_ref(a_local_get,pd.frame_pointer_ref));
+        incstack(list,1);
+        list.Concat(taicpu.op_sym(a_global_set,current_asmdata.RefAsmSymbol(STACK_POINTER_SYM,AT_LABEL)));
+        decstack(list,1);
+      end;
+    end;
+
+  procedure thlcgwasm.g_proc_exit(list: TAsmList; parasize: longint; nostackframe: boolean);
+    var
+      pd: tcpuprocdef;
+    begin
+      pd:=tcpuprocdef(current_procinfo.procdef);
+      list.Concat(taicpu.op_ref(a_local_get,pd.base_pointer_ref));
+      incstack(list,1);
+      list.Concat(taicpu.op_sym(a_global_set,current_asmdata.RefAsmSymbol(STACK_POINTER_SYM,AT_LABEL)));
+      decstack(list,1);
+
+      list.concat(taicpu.op_none(a_return));
+      list.concat(taicpu.op_none(a_end_function));
+    end;
+
+  procedure thlcgwasm.g_overflowcheck(list: TAsmList; const Loc: tlocation; def: tdef);
+    begin
+      { not possible, need the original operands }
+      internalerror(2012102101);
+    end;
+
+  procedure thlcgwasm.g_overflowCheck_loc(List: TAsmList; const Loc: TLocation; def: TDef; var ovloc: tlocation);
+    var
+      hl : tasmlabel;
+    begin
+      if not(cs_check_overflow in current_settings.localswitches) then
+        exit;
+      current_asmdata.getjumplabel(hl);
+      a_cmp_const_loc_label(list,s32inttype,OC_EQ,0,ovloc,hl);
+      g_call_system_proc(list,'fpc_overflow',[],nil);
+      a_label(list,hl);
+    end;
+
+  procedure thlcgwasm.maybe_change_load_node_reg(list: TAsmList; var n: tnode; reload: boolean);
+    begin
+      { don't do anything, all registers become stack locations anyway }
+    end;
+
+  procedure thlcgwasm.gen_entry_code(list: TAsmList);
+    begin
+      inherited;
+      list.concat(taicpu.op_none(a_block));
+      incblock;
+      exitBr:=br_blocks;
+    end;
+
+  procedure thlcgwasm.gen_exit_code(list: TAsmList);
+    begin
+      list.concat(taicpu.op_none(a_end_block));
+      decblock;
+      if fevalstackheight<>0 then
+        list.concat(tai_comment.Create(strpnew('!!! values remaining on stack at end of block !!!')));
+      inherited;
+    end;
+
+  procedure thlcgwasm.a_bit_scan_reg_reg(list: TAsmList; reverse: boolean; srcsize, dstsize: tdef; src, dst: tregister);
+    begin
+      internalerror(2012090201);
+    end;
+
+  procedure thlcgwasm.a_loadmm_loc_reg(list: TAsmList; fromsize, tosize: tdef; const loc: tlocation; const reg: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012090202);
+    end;
+
+  procedure thlcgwasm.a_loadmm_reg_reg(list: TAsmList; fromsize, tosize: tdef; reg1, reg2: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060130);
+    end;
+
+  procedure thlcgwasm.a_loadmm_ref_reg(list: TAsmList; fromsize, tosize: tdef; const ref: treference; reg: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060131);
+    end;
+
+  procedure thlcgwasm.a_loadmm_reg_ref(list: TAsmList; fromsize, tosize: tdef; reg: tregister; const ref: treference; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060132);
+    end;
+
+  procedure thlcgwasm.a_opmm_reg_reg(list: TAsmList; Op: TOpCG; size: tdef; src, dst: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060133);
+    end;
+
+  procedure thlcgwasm.a_loadmm_intreg_reg(list: TAsmList; fromsize, tosize: tdef; intreg, mmreg: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060134);
+    end;
+
+  procedure thlcgwasm.a_loadmm_reg_intreg(list: TAsmList; fromsize, tosize: tdef; mmreg, intreg: tregister; shuffle: pmmshuffle);
+    begin
+      internalerror(2012060135);
+    end;
+
+  procedure thlcgwasm.g_stackpointer_alloc(list: TAsmList; size: longint);
+    begin
+      internalerror(2012090203);
+    end;
+
+  procedure thlcgwasm.g_intf_wrapper(list: TAsmList; procdef: tprocdef; const labelname: string; ioffset: longint);
+    begin
+      internalerror(2012090204);
+    end;
+
+  procedure thlcgwasm.g_adjust_self_value(list: TAsmList; procdef: tprocdef; ioffset: aint);
+    begin
+      internalerror(2012090205);
+    end;
+
+  procedure thlcgwasm.g_local_unwind(list: TAsmList; l: TAsmLabel);
+    begin
+      internalerror(2012090206);
+    end;
+
+  procedure thlcgwasm.g_procdef(list: TAsmList; pd: tprocdef);
+    begin
+      list.Concat(tai_functype.create(pd.mangledname,tcpuprocdef(pd).create_functype));
+    end;
+
+  procedure thlcgwasm.a_load_stack_reg(list: TAsmList; size: tdef; reg: tregister);
+    begin
+      list.concat(taicpu.op_reg(a_local_set,reg));
+      decstack(list,1);
+    end;
+
+  procedure thlcgwasm.a_load_stack_ref(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
+    var
+      opc: tasmop;
+      finishandval: tcgint;
+    begin
+      { fake location that indicates the value has to remain on the stack }
+      if ref.base=NR_EVAL_STACK_BASE then
+        exit;
+      opc:=loadstoreopcref(size,false,ref,finishandval);
+
+      list.concat(taicpu.op_ref(opc,ref));
+      { avoid problems with getting the size of an open array etc }
+      if wasmAlwayInMem(size) then
+        size:=ptruinttype;
+      decstack(list,1+extra_slots);
+    end;
+
+  procedure thlcgwasm.a_load_reg_stack(list: TAsmList; size: tdef; reg: tregister);
+    begin
+      list.concat(taicpu.op_reg(a_local_get,reg));
+      incstack(list,1);
+    end;
+
+  procedure thlcgwasm.a_load_ref_stack(list: TAsmList; size: tdef; const ref: treference; extra_slots: longint);
+    var
+      opc: tasmop;
+      finishandval: tcgint;
+    begin
+      { fake location that indicates the value is already on the stack? }
+      if (ref.base=NR_EVAL_STACK_BASE) then
+        exit;
+      opc:=loadstoreopcref(size,true,ref,finishandval);
+
+      list.concat(taicpu.op_ref(opc,ref));
+
+      { avoid problems with getting the size of an open array etc }
+      if wasmAlwayInMem(size) then
+        size:=ptruinttype;
+      incstack(list,1-extra_slots);
+      if finishandval<>-1 then
+        a_op_const_stack(list,OP_AND,size,finishandval);
+
+      // there's no cast check in Wasm
+      //if ref.checkcast then
+      //  gen_typecheck(list,a_checkcast,size);
+    end;
+
+  function thlcgwasm.loadstoreopcref(def: tdef; isload: boolean; const ref: treference; out finishandval: tcgint): tasmop;
+    const
+                          {iisload} {issigned}
+      getputmem8   : array [boolean, boolean] of TAsmOp = ((a_i32_store8, a_i32_store8),   (a_i32_load8_u, a_i32_load8_s));
+      getputmem16  : array [boolean, boolean] of TAsmOp = ((a_i32_store16, a_i32_store16), (a_i32_load16_u ,a_i32_load16_s));
+      getputmem32  : array [boolean, boolean] of TAsmOp = ((a_i32_store, a_i32_store),     (a_i32_load, a_i32_load));
+      getputmem64  : array [boolean, boolean] of TAsmOp = ((a_i64_store,  a_i64_store),    (a_i64_load, a_i64_load));
+      getputmemf32 : array [boolean] of TAsmOp = (a_f32_store, a_f32_load);
+      getputmemf64 : array [boolean] of TAsmOp = (a_f64_store, a_f64_load);
+    begin
+      if (ref.base<>NR_LOCAL_STACK_POINTER_REG) or assigned(ref.symbol) then
+        begin
+          { -> either a global (static) field, or a regular field. If a regular
+            field, then ref.base contains the self pointer, otherwise
+            ref.base=NR_NO. In both cases, the symbol contains all other
+            information (combined field name and type descriptor) }
+          case def.size of
+            1: result := getputmem8[isload, is_signed(def)];
+            2: result := getputmem16[isload, is_signed(def)];
+            4:
+              if is_single(def) then
+                result := getputmemf32[isload]
+              else
+                result := getputmem32[isload, is_signed(def)];
+            8: if is_double(def) then
+                 result := getputmemf64[isload]
+               else
+                result := getputmem64[isload, is_signed(def)];
+          else
+            Internalerror(2019091501);
+          end;
+
+          //result:=getputopc[isload,ref.base=NR_NO];
+          finishandval:=-1;
+          { erase sign extension for byte/smallint loads }
+          if (def2regtyp(def)=R_INTREGISTER) and
+             not is_signed(def) and
+             (def.typ=orddef) and
+             not is_widechar(def) then
+            case def.size of
+              1: if (torddef(def).high>127) then
+                   finishandval:=255;
+              2: if (torddef(def).high>32767) then
+                   finishandval:=65535;
+            end;
+        end
+      else
+        begin
+          finishandval:=-1;
+          if isload then
+            result := a_local_get
+          else
+            result := a_local_set;
+        end;
+    end;
+
+  procedure thlcgwasm.resize_stack_int_val(list: TAsmList; fromsize, tosize: tdef; formemstore: boolean);
+    var
+      fromcgsize, tocgsize: tcgsize;
+    begin
+      { When storing to an array, field or global variable, make sure the
+        static type verification can determine that the stored value fits
+        within the boundaries of the declared type (to appease the Dalvik VM).
+        Local variables either get their type upgraded in the debug info,
+        or have no type information at all }
+      if formemstore and
+         (tosize.typ=orddef) then
+        if (torddef(tosize).ordtype in [u8bit,uchar]) then
+          tosize:=s8inttype
+        else if torddef(tosize).ordtype=u16bit then
+          tosize:=s16inttype;
+
+      fromcgsize:=def_cgsize(fromsize);
+      tocgsize:=def_cgsize(tosize);
+      if fromcgsize in [OS_S64,OS_64] then
+        begin
+          if not(tocgsize in [OS_S64,OS_64]) then
+            begin
+              { truncate }
+              list.concat(taicpu.op_none(a_i32_wrap_i64));
+              case tocgsize of
+                OS_8:
+                  a_op_const_stack(list,OP_AND,s32inttype,255);
+                OS_S8:
+                  list.concat(taicpu.op_none(a_i32_extend8_s));
+                OS_16:
+                  a_op_const_stack(list,OP_AND,s32inttype,65535);
+                OS_S16:
+                  list.concat(taicpu.op_none(a_i32_extend16_s));
+                OS_32,OS_S32:
+                  ;
+                else
+                  internalerror(2021012201);
+              end;
+            end;
+        end
+      else if tocgsize in [OS_S64,OS_64] then
+        begin
+          { extend }
+          case fromcgsize of
+            OS_8:
+              begin
+                a_op_const_stack(list,OP_AND,s32inttype,255);
+                list.concat(taicpu.op_none(a_i64_extend_i32_u));
+              end;
+            OS_S8:
+              begin
+                list.concat(taicpu.op_none(a_i64_extend_i32_u));
+                list.concat(taicpu.op_none(a_i64_extend8_s));
+              end;
+            OS_16:
+              begin
+                a_op_const_stack(list,OP_AND,s32inttype,65535);
+                list.concat(taicpu.op_none(a_i64_extend_i32_u));
+              end;
+            OS_S16:
+              begin
+                list.concat(taicpu.op_none(a_i64_extend_i32_u));
+                list.concat(taicpu.op_none(a_i64_extend16_s));
+              end;
+            OS_32:
+              list.concat(taicpu.op_none(a_i64_extend_i32_u));
+            OS_S32:
+              list.concat(taicpu.op_none(a_i64_extend_i32_s));
+            OS_64,OS_S64:
+              ;
+            else
+              internalerror(2021010301);
+          end;
+        end
+      else
+        begin
+          if tcgsize2size[fromcgsize]<tcgsize2size[tocgsize] then
+            begin
+              { extend }
+              case fromcgsize of
+                OS_8:
+                  a_op_const_stack(list,OP_AND,s32inttype,255);
+                OS_S8:
+                  list.concat(taicpu.op_none(a_i32_extend8_s));
+                OS_16:
+                  a_op_const_stack(list,OP_AND,s32inttype,65535);
+                OS_S16:
+                  list.concat(taicpu.op_none(a_i32_extend16_s));
+                OS_32,OS_S32:
+                  ;
+                else
+                  internalerror(2021010302);
+              end;
+            end
+          else if tcgsize2size[fromcgsize]>=tcgsize2size[tocgsize] then
+            begin
+              { truncate }
+              case tocgsize of
+                OS_8:
+                  a_op_const_stack(list,OP_AND,s32inttype,255);
+                OS_S8:
+                  list.concat(taicpu.op_none(a_i32_extend8_s));
+                OS_16:
+                  a_op_const_stack(list,OP_AND,s32inttype,65535);
+                OS_S16:
+                  list.concat(taicpu.op_none(a_i32_extend16_s));
+                OS_32,OS_S32:
+                  ;
+                else
+                  internalerror(2021010302);
+              end;
+            end;
+        end;
+    end;
+
+    procedure thlcgwasm.maybe_resize_stack_para_val(list: TAsmList; retdef: tdef; callside: boolean);
+      var
+        convsize: tdef;
+      begin
+        if (retdef.typ=orddef) then
+          begin
+            if (torddef(retdef).ordtype in [u8bit,u16bit,uchar]) and
+               (torddef(retdef).high>=(1 shl (retdef.size*8-1))) then
+              begin
+                convsize:=nil;
+                if callside then
+                  if torddef(retdef).ordtype in [u8bit,uchar] then
+                    convsize:=s8inttype
+                  else
+                    convsize:=s16inttype
+                else if torddef(retdef).ordtype in [u8bit,uchar] then
+                    convsize:=u8inttype
+                  else
+                    convsize:=u16inttype;
+                if assigned(convsize) then
+                  resize_stack_int_val(list,s32inttype,convsize,false);
+              end;
+          end;
+      end;
+
+
+  procedure thlcgwasm.g_adjust_stack_after_call(list: TAsmList; pd: tabstractprocdef);
+    var
+      totalremovesize: longint;
+      realresdef: tdef;
+      ft: TWasmFuncType;
+    begin
+      ft:=tcpuprocdef(pd).create_functype;
+      totalremovesize:=Length(ft.params)-Length(ft.results);
+      if (Length(ft.results)=0) and (po_discardresult in pd.procoptions) then
+        dec(totalremovesize);
+      { remove parameters from internal evaluation stack counter (in case of
+        e.g. no parameters and a result, it can also increase) }
+      if totalremovesize>0 then
+        decstack(list,totalremovesize)
+      else if totalremovesize<0 then
+        incstack(list,-totalremovesize);
+      ft.free;
+    end;
+
+
+  procedure thlcgwasm.g_fingerprint(list: TAsmList);
+    begin
+      list.concat(taicpu.op_const(a_i64_const,Random(high(int64))));
+      list.concat(taicpu.op_const(a_i64_const,Random(high(int64))));
+      list.concat(taicpu.op_const(a_i64_const,Random(high(int64))));
+      list.concat(taicpu.op_const(a_i64_const,Random(high(int64))));
+      list.concat(taicpu.op_none(a_drop));
+      list.concat(taicpu.op_none(a_drop));
+      list.concat(taicpu.op_none(a_drop));
+      list.concat(taicpu.op_none(a_drop));
+    end;
+
+
+  procedure thlcgwasm.resizestackfpuval(list: TAsmList; fromsize, tosize: tcgsize);
+    begin
+      if (fromsize=OS_F32) and
+         (tosize=OS_F64) then
+        begin
+          list.concat(taicpu.op_none(a_f64_promote_f32));
+        end
+      else if (fromsize=OS_F64) and
+              (tosize=OS_F32) then
+        begin
+          list.concat(taicpu.op_none(a_f32_demote_f64));
+        end;
+    end;
+
+  procedure create_hlcodegen_cpu;
+    begin
+      hlcg:=thlcgwasm.create;
+      create_codegen;
+    end;
+
+initialization
+  chlcgobj:=thlcgwasm;
+  create_hlcodegen:=@create_hlcodegen_cpu;
+end.

+ 101 - 0
compiler/wasm32/itcpugas.pas

@@ -0,0 +1,101 @@
+{
+    Copyright (c) 1998-2012 by Florian Klaempfl and others
+
+    This unit contains the WebAssembly GAS instruction tables
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpugas;
+
+{$i fpcdefs.inc}
+
+interface
+
+  uses
+    cpubase,cgbase,
+    itcpuwasm;
+
+
+  const
+    { Standard opcode string table (for each tasmop enumeration). The
+      opcode strings should conform to the names as defined by the
+      processor manufacturer.
+    }
+    gas_op2str : op2strtable = (
+      '<none>',
+      // control flow
+      'block', 'loop', 'br', 'br_if', 'br_table', 'if', 'else', 'end_block',
+      'end_loop', 'end_if', 'end_function', 'return', 'unreachable',
+      // basic
+      'nop', 'drop', 'i32.const', 'i64.const', 'f32.const', 'f64.const',
+      'local.get', 'local.set', 'local.tee', 'global.get', 'global.set',
+      'select', 'call', 'call_indirect',
+      // integer
+      'i32.add', 'i64.add', 'i32.sub', 'i64.sub', 'i32.mul', 'i64.mul',
+      'i32.div_s', 'i64.div_s', 'i32.div_u', 'i64.div_u', 'i32.rem_s', 'i64.rem_s',
+      'i32.rem_u', 'i64.rem_u', 'i32.and', 'i64.and', 'i32.or', 'i64.or',
+      'i32.xor', 'i64.xor', 'i32.shl', 'i64.shl', 'i32.shr_s', 'i64.shr_s',
+      'i32.shr_u', 'i64.shr_u', 'i32.rotl', 'i64.rotl', 'i32.rotr', 'i64.rotr',
+      'i32.clz', 'i64.clz', 'i32.ctz', 'i64.ctz', 'i32.popcnt', 'i64.popcnt',
+      'i32.eqz', 'i64.eqz',
+      // floating point
+      'f32.add', 'f64.add', 'f32.sub', 'f64.sub', 'f32.mul', 'f64.mul',
+      'f32.div', 'f64.div', 'f32.sqrt', 'f64.sqrt', 'f32.min', 'f64.min',
+      'f32.max', 'f64.max', 'f32.ceil', 'f64.ceil', 'f32.floor', 'f64.floor',
+      'f32.trunc', 'f64.trunc', 'f32.nearest', 'f64.nearest', 'f32.abs', 'f64.abs',
+      'f32.neg', 'f64.neg', 'f32.copysign', 'f64.copysign',
+      // integer compare
+      'i32.eq', 'i64.eq', 'i32.ne', 'i64.ne', 'i32.lt_s', 'i64.lt_s',
+      'i32.lt_u', 'i64.lt_u', 'i32.le_s', 'i64.le_s', 'i32.le_u', 'i64.le_u',
+      'i32.gt_s', 'i64.gt_s', 'i32.gt_u', 'i64.gt_u', 'i32.ge_s', 'i64.ge_s',
+      'i32.ge_u', 'i64.ge_u',
+      // floating point compare
+      'f32.eq', 'f64.eq', 'f32.ne', 'f64.ne', 'f32.lt', 'f64.lt',
+      'f32.le', 'f64.le', 'f32.gt', 'f64.gt', 'f32.ge', 'f64.gt',
+      // conversion
+      'i32.wrap_i64', 'i64.extend_i32_s', 'i64.extend_i32_u',
+      'i32.extend8_s','i32.extend16_s','i64.extend8_s','i64.extend16_s','i64.extend32_s',
+      'i32.trunc_f32_s', 'i32.trunc_f64_s', 'i64.trunc_f32_s', 'i64.trunc_f64_s',
+      'i32.trunc_f32_u', 'i32.trunc_f64_u', 'i64.trunc_f32_u', 'i64.trunc_f64_u',
+      'f32.demote_f64', 'f64.promote_f32',
+      'f32.convert_i32_s', 'f32.convert_i64_s', 'f64.convert_i32_s', 'f64.convert_i64_s',
+      'f32.convert_i32_u', 'f32.convert_i64_u', 'f64.convert_i32_u', 'f64.convert_i64_u',
+      'i32.reinterpret_f32', 'i64.reinterpret_f64', 'f32.reinterpret_i32', 'f64.reinterpret_i64',
+      // load/store
+      'i32.load', 'i64.load', 'f32.load', 'f64.load',
+      'i32.store', 'i64.store', 'f32.store', 'f64.store',
+      'i32.load8_s', 'i32.load16_s', 'i64.load8_s', 'i64.load16_s', 'i64.load32_s',
+      'i32.load8_u', 'i32.load16_u', 'i64.load8_u', 'i64.load16_u', 'i64.load32_u',
+      'i32.store8', 'i32.store16', 'i64.store8', 'i64.store16', 'i64.store32',
+      // additional memory
+      'memory.grow 0', 'memory.size 0'
+    );
+
+    gas_wasm_basic_type_str : array [TWasmBasicType] of string = ('i32','i64','f32','f64');
+
+    function gas_regname(r:Tregister):string;
+
+
+implementation
+
+
+    function gas_regname(r:Tregister):string;
+      begin
+        result:=generic_regname(r);
+      end;
+
+end.

+ 36 - 0
compiler/wasm32/itcpuwasm.pas

@@ -0,0 +1,36 @@
+{
+    Copyright (c) 2016 by Karoly Balogh
+
+    This unit contains the WebAssembly instruction tables
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit itcpuwasm;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cpubase,cgbase;
+
+    const
+      wasm_op2str : op2strtable = ({$i strinst.inc});
+
+implementation
+
+end.

+ 355 - 0
compiler/wasm32/nwasmadd.pas

@@ -0,0 +1,355 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev based on JVM by Jonas Maebe
+
+    Code generation for add nodes on the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmadd;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       cgbase,
+       node,ncgadd,cpubase, globals, pass_2;
+
+    type
+
+       { twasmaddnode }
+
+       twasmaddnode = class(tcgaddnode)
+       protected
+          procedure second_generic_compare(unsigned: boolean);
+
+          procedure pass_left_right;override;
+          procedure second_addfloat;override;
+          procedure second_cmpfloat;override;
+          procedure second_cmpboolean;override;
+          procedure second_cmp64bit;override;
+          procedure second_add64bit; override;
+          procedure second_cmpordinal;override;
+
+          // special treatement for short-boolean expressions
+          // using IF block, instead of direct labels
+          procedure second_addboolean; override;
+       public
+          function pass_1: tnode;override;
+       end;
+
+  implementation
+
+    uses
+      systems,
+      cutils,verbose,constexp,globtype,compinnr,
+      symconst,symtable,symdef,symcpu,
+      paramgr,procinfo,pass_1,
+      aasmbase,aasmtai,aasmdata,aasmcpu,defutil,
+      hlcgobj,hlcgcpu,cgutils,
+      cpupara,
+      nbas,ncon,nset,nadd,ncal,ncnv,ninl,nld,nmat,nmem,
+      //njvmcon,
+      cgobj, symtype, tgobj;
+
+{*****************************************************************************
+                               twasmaddnode
+*****************************************************************************}
+
+    function twasmaddnode.pass_1: tnode;
+      begin
+        result:=inherited;
+        if (result=nil) and (expectloc in [LOC_JUMP,LOC_FLAGS]) then
+          expectloc:=LOC_REGISTER;
+      end;
+
+    procedure twasmaddnode.pass_left_right;
+      begin
+        //if not((nodetype in [orn,andn]) and
+        //       is_boolean(left.resultdef)) then
+        //  swapleftright;
+        inherited pass_left_right;
+      end;
+
+    procedure twasmaddnode.second_addfloat;
+      var
+        op : TAsmOp;
+        commutative : boolean;
+      begin
+        pass_left_right;
+
+        location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
+
+        commutative:=false;
+        case nodetype of
+          addn :
+            begin
+              if location.size=OS_F64 then
+                op:=a_f64_add
+              else
+                op:=a_f32_add;
+              commutative:=true;
+            end;
+          muln :
+            begin
+              if location.size=OS_F64 then
+                op:=a_f64_mul
+              else
+                op:=a_f32_mul;
+              commutative:=true;
+            end;
+          subn :
+            begin
+              if location.size=OS_F64 then
+                op:=a_f64_sub
+              else
+                op:=a_f32_sub;
+            end;
+          slashn :
+            begin
+              if location.size=OS_F64 then
+                op:=a_f64_div
+              else
+                op:=a_f32_div;
+            end;
+          else
+            internalerror(2011010402);
+        end;
+
+        { swap the operands to make it easier for the optimizer to optimize
+          the operand stack slot reloading (non-commutative operations must
+          always be in the correct order though) }
+        if (commutative and
+            (left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) and
+            (right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER])) or
+           (not commutative and
+            (nf_swapped in flags)) then
+          swapleftright;
+
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+        { could be optimized in the future by keeping the results on the stack,
+          if we add code to swap the operands when necessary (a_swap for
+          singles, store/load/load for doubles since there is no swap for
+          2-slot elements -- also adjust expectloc in that case! }
+        thlcgwasm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+    procedure twasmaddnode.second_cmpfloat;
+      var
+        op : TAsmOp;
+        commutative : boolean;
+        cmpResultType : tdef;
+      begin
+        cmpResultType := s32inttype;
+        pass_left_right;
+
+        commutative:=false;
+        case nodetype of
+          ltn :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_lt
+              else
+                op:=a_f32_lt;
+            end;
+          lten :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_le
+              else
+                op:=a_f32_le;
+            end;
+          gtn :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_gt
+              else
+                op:=a_f32_gt;
+            end;
+          gten :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_ge
+              else
+                op:=a_f32_ge;
+            end;
+          equaln :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_eq
+              else
+                op:=a_f32_eq;
+              commutative:=true;
+            end;
+          unequaln :
+            begin
+              if left.location.size=OS_F64 then
+                op:=a_f64_ne
+              else
+                op:=a_f32_ne;
+              commutative:=true;
+            end;
+
+          else
+            internalerror(2011010402);
+        end;
+
+        { swap the operands to make it easier for the optimizer to optimize
+          the operand stack slot reloading (non-commutative operations must
+          always be in the correct order though) }
+        if (commutative and
+            (left.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER]) and
+            (right.location.loc in [LOC_FPUREGISTER,LOC_CFPUREGISTER])) or
+           (not commutative and
+            (nf_swapped in flags)) then
+          swapleftright;
+
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+        { could be optimized in the future by keeping the results on the stack,
+          if we add code to swap the operands when necessary (a_swap for
+          singles, store/load/load for doubles since there is no swap for
+          2-slot elements -- also adjust expectloc in that case! }
+          set_result_location_reg;
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+
+    procedure twasmaddnode.second_cmpboolean;
+      begin
+        second_generic_compare(true);
+      end;
+
+
+    procedure twasmaddnode.second_cmp64bit;
+      begin
+        second_generic_compare(not is_signed(left.resultdef));
+      end;
+
+
+    procedure twasmaddnode.second_add64bit;
+      begin
+        second_opordinal;
+      end;
+
+
+    procedure twasmaddnode.second_cmpordinal;
+      begin
+        second_generic_compare(not is_signed(left.resultdef));
+      end;
+
+    procedure twasmaddnode.second_addboolean;
+      begin
+        if (nodetype in [orn,andn]) and
+           (not(cs_full_boolean_eval in current_settings.localswitches) or
+            (nf_short_bool in flags)) then
+        begin
+          secondpass(left);
+          thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+
+          current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i32])));
+          thlcgwasm(hlcg).incblock;
+          thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+          case nodetype of
+              andn :
+                begin
+                   // inside of IF (the condition evaluated as true)
+                   // for "and" must evaluate the right section
+                   secondpass(right);
+                   thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+
+                   current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_else) );
+                   thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+                   // inside of ELSE (the condition evaluated as false)
+                   // for "and" must end evaluation immediately
+                   current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, 0) );
+                   thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+                end;
+              orn :
+                begin
+                   // inside of IF (the condition evaluated as true)
+                   // for "or" must end evalaution immediately - satified!
+                   current_asmdata.CurrAsmList.Concat( taicpu.op_const(a_i32_const, 1) );
+                   thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+
+                   current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_else) );
+                   thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+                   // inside of ELSE (the condition evaluated as false)
+                   // for "or" must evaluate the right part
+                   secondpass(right);
+                   // inside of ELSE (the condition evaluated as false)
+                   // for "and" must end evaluation immediately
+                   thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+                end;
+              else
+                Internalerror(2019091902);
+              end;
+          current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_end_if) );
+          thlcgwasm(hlcg).decblock;
+          set_result_location_reg;
+          thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+        end else
+          inherited;
+      end;
+
+    procedure twasmaddnode.second_generic_compare(unsigned: boolean);
+      var
+        truelabel,
+        falselabel: tasmlabel;
+        cmpop: TOpCmp;
+      begin
+        truelabel:=nil;
+        falselabel:=nil;
+        pass_left_right;
+        { swap the operands to make it easier for the optimizer to optimize
+          the operand stack slot reloading in case both are in a register }
+        if (left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) and
+           (right.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          swapleftright;
+        cmpop:=cmpnode2topcmp(unsigned);
+        if (nf_swapped in flags) then
+          cmpop:=swap_opcmp(cmpop);
+
+        if left.location.loc in [LOC_REGISTER,LOC_CREGISTER] then
+          thlcgwasm(hlcg).a_cmp_loc_reg_stack(current_asmdata.CurrAsmList,left.resultdef,cmpop,right.location,left.location.register)
+        else case right.location.loc of
+          LOC_REGISTER,LOC_CREGISTER:
+            thlcgwasm(hlcg).a_cmp_reg_loc_stack(current_asmdata.CurrAsmList,left.resultdef,cmpop,right.location.register,left.location);
+          LOC_REFERENCE,LOC_CREFERENCE:
+            thlcgwasm(hlcg).a_cmp_ref_loc_stack(current_asmdata.CurrAsmList,left.resultdef,cmpop,right.location.reference,left.location);
+          LOC_CONSTANT:
+            thlcgwasm(hlcg).a_cmp_const_loc_stack(current_asmdata.CurrAsmList,left.resultdef,cmpop,right.location.value,left.location);
+          else
+            internalerror(2011010413);
+        end;
+        set_result_location_reg;
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+begin
+  caddnode:=twasmaddnode;
+end.

+ 80 - 0
compiler/wasm32/nwasmcal.pas

@@ -0,0 +1,80 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    WebAssembly-specific code for call nodes
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmcal;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      cgbase,
+      symtype,symdef,cgutils,parabase,
+      node,ncal,ncgcal,hlcgobj,aasmcpu,cpubase, wasmdef;
+
+    type
+       { twasmcallparanode }
+
+       twasmcallparanode = class(tcgcallparanode)
+       end;
+
+       { twasmcallnode }
+
+       twasmcallnode = class(tcgcallnode)
+       protected
+         procedure extra_post_call_code; override;
+         procedure do_release_unused_return_value; override;
+         procedure set_result_location(realresdef: tstoreddef); override;
+       end;
+
+
+implementation
+
+    uses
+      globtype, aasmdata, defutil, tgobj, hlcgcpu, symconst;
+
+      { twasmcallnode }
+
+    procedure twasmcallnode.extra_post_call_code;
+      begin
+        thlcgwasm(hlcg).g_adjust_stack_after_call(current_asmdata.CurrAsmList,procdefinition);
+      end;
+
+    procedure twasmcallnode.do_release_unused_return_value;
+      begin
+        if is_void(resultdef) and not (po_discardresult in procdefinition.procoptions) then
+          exit;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_drop));
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+      end;
+
+    procedure twasmcallnode.set_result_location(realresdef: tstoreddef);
+      begin
+        // default implementation is placing the return value on LOC_REGISTER.
+        // WebAssembly always returns the value on stack.
+        location_reset_ref(location,LOC_REFERENCE,def_cgsize(realresdef),1,[]);
+        tg.gethltemp(current_asmdata.CurrAsmList,realresdef,retloc.intsize,tt_normal,location.reference);
+      end;
+
+begin
+  ccallnode:=twasmcallnode;
+  ccallparanode:=twasmcallparanode;
+end.

+ 172 - 0
compiler/wasm32/nwasmcnv.pas

@@ -0,0 +1,172 @@
+{
+    Copyright (c) 1998-2020 by Florian Klaempfl and Nikolay Nikolov
+
+    Generate WebAssembly code for type converting nodes
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+unit nwasmcnv;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,ncnv,ncgcnv;
+
+    type
+
+       { twasmtypeconvnode }
+
+       twasmtypeconvnode = class(tcgtypeconvnode)
+       protected
+         function first_int_to_real: tnode; override;
+         procedure second_int_to_real;override;
+         procedure second_int_to_bool;override;
+         procedure second_ansistring_to_pchar;override;
+       end;
+
+implementation
+
+   uses
+      verbose,globals,globtype,aasmdata,
+      defutil,fmodule,cpubase,
+      cgbase,cgutils,pass_1,pass_2,
+      aasmbase,aasmcpu,
+      symdef,
+      hlcgobj,hlcgcpu;
+
+
+{ twasmtypeconvnode }
+
+    function twasmtypeconvnode.first_int_to_real: tnode;
+      begin
+        first_int_to_real:=nil;
+        if left.resultdef.size<4 then
+          begin
+            inserttypeconv(left,s32inttype);
+            firstpass(left);
+          end;
+        expectloc:=LOC_FPUREGISTER;
+      end;
+
+
+    procedure twasmtypeconvnode.second_int_to_real;
+      var
+        op: TAsmOp;
+      begin
+        secondpass(left);
+        if codegenerror then
+          exit;
+
+        case tfloatdef(resultdef).floattype of
+          s32real:
+            begin
+              if is_64bitint(left.resultdef) or
+                is_currency(left.resultdef) then
+                begin
+                  if is_signed(left.resultdef) then
+                    op:=a_f32_convert_i64_s
+                  else
+                    op:=a_f32_convert_i64_u;
+                end
+              else
+                { other integers are supposed to be 32 bit }
+                begin
+                  if is_signed(left.resultdef) then
+                    op:=a_f32_convert_i32_s
+                  else
+                    op:=a_f32_convert_i32_u;
+                end;
+            end;
+          s64real:
+            begin
+              if is_64bitint(left.resultdef) or
+                is_currency(left.resultdef) then
+                begin
+                  if is_signed(left.resultdef) then
+                    op:=a_f64_convert_i64_s
+                  else
+                    op:=a_f64_convert_i64_u;
+                end
+              else
+                { other integers are supposed to be 32 bit }
+                begin
+                  if is_signed(left.resultdef) then
+                    op:=a_f64_convert_i32_s
+                  else
+                    op:=a_f64_convert_i32_u;
+                end;
+            end;
+          else
+            internalerror(2021010501);
+        end;
+
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(op));
+        location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+        location.register := hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+
+    procedure twasmtypeconvnode.second_int_to_bool;
+      begin
+        secondpass(left);
+        if codegenerror then
+          exit;
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,left.resultdef,0,R_INTREGISTER);
+        thlcgwasm(hlcg).a_cmp_stack_stack(current_asmdata.CurrAsmList,left.resultdef,OC_NE);
+        thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,left.resultdef,resultdef,false);
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register := hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+
+    procedure twasmtypeconvnode.second_ansistring_to_pchar;
+      var
+        hr : treference;
+      begin
+        thlcgwasm(hlcg).a_cmp_const_loc_stack(current_asmdata.CurrAsmList,left.resultdef,OC_NE,0,left.location);
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i32])));
+        thlcgwasm(hlcg).incblock;
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_else));
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+        { FPC_EMPTYCHAR is a widechar -> 2 bytes }
+        reference_reset(hr,2,[]);
+        hr.symbol:=current_asmdata.RefAsmSymbol('FPC_EMPTYCHAR',AT_DATA);
+        current_module.add_extern_asmsym('FPC_EMPTYCHAR',AB_EXTERNAL,AT_DATA);
+        thlcgwasm(hlcg).a_loadaddr_ref_stack(current_asmdata.CurrAsmList,cwidechartype,resultdef,hr);
+
+        current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_end_if) );
+        thlcgwasm(hlcg).decblock;
+
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+begin
+  ctypeconvnode:=twasmtypeconvnode;
+end.

+ 494 - 0
compiler/wasm32/nwasmcon.pas

@@ -0,0 +1,494 @@
+{
+    Copyright (c) 1998-2011 by Florian Klaempfl and Jonas Maebe
+
+    Generate assembler for constant nodes for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmcon;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+       globtype,aasmbase,
+       symtype,
+       node,ncal,ncon,ncgcon;
+
+    type
+      (*
+       tjvmordconstnode = class(tcgordconstnode)
+          { normally, we convert the enum constant into a load of the
+            appropriate enum class field in pass_1. In some cases (array index),
+            we want to keep it as an enum constant however }
+          enumconstok: boolean;
+          function pass_1: tnode; override;
+          function docompare(p: tnode): boolean; override;
+          function dogetcopy: tnode; override;
+       end;
+         *)
+
+       twasmrealconstnode = class(tcgrealconstnode)
+          procedure pass_generate_code;override;
+       end;
+
+       (*tjvmstringconstnode = class(tstringconstnode)
+          function pass_1: tnode; override;
+          procedure pass_generate_code;override;
+          class function emptydynstrnil: boolean; override;
+       end;
+       *)
+       (*
+       tjvmsetconsttype = (
+         { create symbol for the set constant; the symbol will be initialized
+           in the class constructor/unit init code (default) }
+         sct_constsymbol,
+         { normally, we convert the set constant into a constructor/factory
+           method to create a set instance. In some cases (simple "in"
+           expressions, adding an element to an empty set, ...) we want to
+           keep the set constant instead }
+         sct_notransform,
+         { actually construct a JUBitSet/JUEnumSet that contains the set value
+           (for initializing the sets contstants) }
+         sct_construct
+         );
+       tjvmsetconstnode = class(tcgsetconstnode)
+          setconsttype: tjvmsetconsttype;
+          function pass_1: tnode; override;
+          procedure pass_generate_code; override;
+          constructor create(s : pconstset;def:tdef);override;
+          function docompare(p: tnode): boolean; override;
+          function dogetcopy: tnode; override;
+         protected
+          function emitvarsetconst: tasmsymbol; override;
+          { in case the set has only a single run of consecutive elements,
+            this function will return its starting index and length }
+          function find_single_elements_run(from: longint; out start, len: longint): boolean;
+          function buildbitset: tnode;
+          function buildenumset(const eledef: tdef): tnode;
+          function buildsetfromstring(const helpername: string; otherparas: tcallparanode): tnode;
+       end;
+       *)
+
+implementation
+
+    uses
+      globals,cutils,widestr,verbose,constexp,fmodule,
+      symdef,symsym,symcpu,symtable,symconst,
+      aasmdata,aasmcpu,defutil,
+      nutils,ncnv,nld,nmem,pass_1,
+      cgbase,hlcgobj,hlcgcpu,cgutils,cpubase
+      ;
+
+
+{*****************************************************************************
+                           TJVMORDCONSTNODE
+*****************************************************************************}
+              (*
+    function tjvmordconstnode.pass_1: tnode;
+      var
+        basedef: tcpuenumdef;
+        sym: tenumsym;
+        classfield: tsym;
+      begin
+        if (resultdef.typ<>enumdef) or
+           enumconstok then
+          begin
+            result:=inherited pass_1;
+            exit;
+          end;
+        { convert into JVM class instance }
+        { a) find the enumsym corresponding to the value (may not exist in case
+             of an explicit typecast of an integer -> error) }
+        sym:=nil;
+        sym:=tenumsym(tenumdef(resultdef).int2enumsym(int64(value)));
+        if not assigned(sym) then
+          begin
+            Message(parser_e_range_check_error);
+            result:=nil;
+            exit;
+          end;
+        { b) find the corresponding class field }
+        basedef:=tcpuenumdef(tenumdef(resultdef).getbasedef);
+        classfield:=search_struct_member(basedef.classdef,sym.name);
+
+        { c) create loadnode of the field }
+        result:=nil;
+        if not handle_staticfield_access(classfield,result) then
+          internalerror(2011062606);
+      end;
+
+
+    function tjvmordconstnode.docompare(p: tnode): boolean;
+      begin
+        result:=inherited docompare(p);
+        if result then
+          result:=(enumconstok=tjvmordconstnode(p).enumconstok);
+      end;
+
+
+    function tjvmordconstnode.dogetcopy: tnode;
+      begin
+        result:=inherited dogetcopy;
+        tjvmordconstnode(result).enumconstok:=enumconstok;
+      end;
+   *)
+
+{*****************************************************************************
+                           TWASMREALCONSTNODE
+*****************************************************************************}
+
+    procedure twasmrealconstnode.pass_generate_code;
+      begin
+        location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_loadfpu_const_stack(current_asmdata.CurrAsmList,resultdef,value_real);
+        thlcgwasm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+
+    { tcgstringconstnode }
+  (*
+    function tjvmstringconstnode.pass_1: tnode;
+      var
+        strclass: tobjectdef;
+        pw: pcompilerwidestring;
+        paras: tcallparanode;
+        wasansi: boolean;
+      begin
+        { all Java strings are utf-16. However, there is no way to
+          declare a constant array of bytes (or any other type), those
+          have to be constructed by declaring a final field and then
+          initialising them in the class constructor element per
+          element. We therefore put the straight ASCII values into
+          the UTF-16 string, and then at run time extract those and
+          store them in an Ansistring/AnsiChar array }
+        result:=inherited pass_1;
+        if assigned(result) or
+           (cst_type in [cst_unicodestring,cst_widestring]) then
+          exit;
+        { convert the constant into a widestring representation without any
+          code page conversion }
+        initwidestring(pw);
+        ascii2unicode(value_str,len,current_settings.sourcecodepage,pw,false);
+        ansistringdispose(value_str,len);
+        pcompilerwidestring(value_str):=pw;
+        { and now add a node to convert the data into ansistring format at
+          run time }
+        wasansi:=false;
+        case cst_type of
+          cst_ansistring:
+            begin
+              if len=0 then
+                begin
+                  { we have to use nil rather than an empty string, because an
+                    empty string has a code page and this messes up the code
+                    page selection logic in the RTL }
+                  exit;
+                end;
+              strclass:=tobjectdef(search_system_type('ANSISTRINGCLASS').typedef);
+              wasansi:=true;
+            end;
+          cst_shortstring:
+            strclass:=tobjectdef(search_system_type('SHORTSTRINGCLASS').typedef);
+          cst_conststring:
+            { used for array of char }
+            strclass:=tobjectdef(search_system_type('ANSICHARARRAYCLASS').typedef);
+          else
+           internalerror(2011052401);
+        end;
+        cst_type:=cst_unicodestring;
+        paras:=ccallparanode.create(self.getcopy,nil);
+        if wasansi then
+          paras:=ccallparanode.create(
+            genintconstnode(tstringdef(resultdef).encoding),paras);
+        { since self will be freed, have to make a copy }
+        result:=ccallnode.createinternmethodres(
+          cloadvmtaddrnode.create(ctypenode.create(strclass)),
+          'CREATEFROMLITERALSTRINGBYTES',paras,resultdef);
+      end;
+
+
+    procedure tjvmstringconstnode.pass_generate_code;
+      begin
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getaddressregister(current_asmdata.CurrAsmList,resultdef);
+        case cst_type of
+          cst_ansistring:
+            begin
+              if len<>0 then
+                internalerror(2012052604);
+              hlcg.a_load_const_reg(current_asmdata.CurrAsmList,resultdef,0,location.register);
+              { done }
+              exit;
+            end;
+          cst_shortstring,
+          cst_conststring:
+            internalerror(2012052601);
+          cst_unicodestring,
+          cst_widestring:
+            current_asmdata.CurrAsmList.concat(taicpu.op_wstring(a_ldc,pcompilerwidestring(value_str)));
+          else
+            internalerror(2012052602);
+        end;
+        thlcgjvm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+        thlcgjvm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+    class function tjvmstringconstnode.emptydynstrnil: boolean;
+      begin
+        result:=false;
+      end;
+
+
+    {*****************************************************************************
+                               TJVMSETCONSTNODE
+    *****************************************************************************}
+
+    function tjvmsetconstnode.buildsetfromstring(const helpername: string; otherparas: tcallparanode): tnode;
+      var
+        pw: pcompilerwidestring;
+        wc: tcompilerwidechar;
+        i, j, bit, nulls: longint;
+      begin
+        initwidestring(pw);
+        nulls:=0;
+        for i:=0 to 15 do
+          begin
+            wc:=0;
+            for bit:=0 to 15 do
+              if (i*16+bit) in value_set^ then
+                wc:=wc or (1 shl (15-bit));
+            { don't add trailing zeroes }
+            if wc=0 then
+              inc(nulls)
+            else
+              begin
+                for j:=1 to nulls do
+                  concatwidestringchar(pw,0);
+                nulls:=0;
+                concatwidestringchar(pw,wc);
+              end;
+          end;
+        result:=ccallnode.createintern(helpername,
+          ccallparanode.create(cstringconstnode.createunistr(pw),otherparas));
+        donewidestring(pw);
+      end;
+
+
+    function tjvmsetconstnode.buildbitset: tnode;
+      var
+        mp: tnode;
+      begin
+        if value_set^=[] then
+          begin
+            mp:=cloadvmtaddrnode.create(ctypenode.create(java_jubitset));
+            result:=ccallnode.createinternmethod(mp,'CREATE',nil);
+            exit;
+          end;
+        result:=buildsetfromstring('fpc_bitset_from_string',nil);
+      end;
+
+
+    function tjvmsetconstnode.buildenumset(const eledef: tdef): tnode;
+      var
+        stopnode: tnode;
+        startnode: tnode;
+        mp: tnode;
+        len: longint;
+        start: longint;
+        enumele: tnode;
+        paras: tcallparanode;
+        hassinglerun: boolean;
+      begin
+        hassinglerun:=find_single_elements_run(0, start, len);
+        if hassinglerun then
+          begin
+            mp:=cloadvmtaddrnode.create(ctypenode.create(java_juenumset));
+            if len=0 then
+              begin
+                enumele:=cloadvmtaddrnode.create(ctypenode.create(tcpuenumdef(tenumdef(eledef).getbasedef).classdef));
+                inserttypeconv_explicit(enumele,search_system_type('JLCLASS').typedef);
+                paras:=ccallparanode.create(enumele,nil);
+                result:=ccallnode.createinternmethod(mp,'NONEOF',paras)
+              end
+            else
+              begin
+                startnode:=cordconstnode.create(start,eledef,false);
+                { immediately firstpass so the enum gets translated into a JLEnum
+                  instance }
+                firstpass(startnode);
+                if len=1 then
+                  result:=ccallnode.createinternmethod(mp,'OF',ccallparanode.create(startnode,nil))
+                else
+                  begin
+                    stopnode:=cordconstnode.create(start+len-1,eledef,false);
+                    firstpass(stopnode);
+                    result:=ccallnode.createinternmethod(mp,'RANGE',ccallparanode.create(stopnode,ccallparanode.create(startnode,nil)));
+                  end
+              end
+          end
+        else
+          begin
+            enumele:=cordconstnode.create(tenumsym(tenumdef(eledef).symtable.symlist[0]).value,eledef,false);
+            firstpass(enumele);
+            paras:=ccallparanode.create(enumele,nil);
+            result:=buildsetfromstring('fpc_enumset_from_string',paras);
+          end;
+      end;
+
+
+    function tjvmsetconstnode.pass_1: tnode;
+      var
+        eledef: tdef;
+      begin
+        { we want set constants to be global, so we can reuse them. However,
+          if the set's elementdef is local, we can't do that since a global
+          symbol cannot have a local definition (the compiler will crash when
+          loading the ppu file afterwards) }
+        if tsetdef(resultdef).elementdef.owner.symtabletype=localsymtable then
+          setconsttype:=sct_construct;
+        result:=nil;
+        case setconsttype of
+          //sct_constsymbol:
+          //  begin
+          //    { normally a codegen pass routine, but we have to insert a typed
+          //      const in case the set constant does not exist yet, and that
+          //      should happen in pass_1 (especially since it involves creating
+          //      new nodes, which may even have to be tacked on to this code in
+          //      case it's the unit initialization code) }
+          //    handlevarsetconst;
+          //    { no smallsets }
+          //    expectloc:=LOC_CREFERENCE;
+          //  end;
+          sct_notransform:
+            begin
+              result:=inherited pass_1;
+              { no smallsets }
+              expectloc:=LOC_CREFERENCE;
+            end;
+          sct_constsymbol,
+          sct_construct:
+            begin
+              eledef:=tsetdef(resultdef).elementdef;
+              { empty sets don't have an element type, so we don't know whether we
+                have to constructor a bitset or enumset (and of which type) }
+              if not assigned(eledef) then
+                internalerror(2011070202);
+              if eledef.typ=enumdef then
+                begin
+                  result:=buildenumset(eledef);
+                end
+              else
+                begin
+                  result:=buildbitset;
+                end;
+              inserttypeconv_explicit(result,cpointerdef.getreusable(resultdef));
+              result:=cderefnode.create(result);
+            end;
+        end;
+      end;
+
+
+    procedure tjvmsetconstnode.pass_generate_code;
+      begin
+        case setconsttype of
+          sct_constsymbol:
+            begin
+              { all sets are varsets for the JVM target, no setbase differences }
+              handlevarsetconst;
+            end;
+          else
+            { must be handled in pass_1 or otherwise transformed }
+            internalerror(2011070201)
+        end;
+      end;
+
+    constructor tjvmsetconstnode.create(s: pconstset; def: tdef);
+      begin
+        inherited create(s, def);
+        setconsttype:=sct_constsymbol;
+      end;
+
+
+    function tjvmsetconstnode.docompare(p: tnode): boolean;
+      begin
+        result:=
+          inherited docompare(p) and
+          (setconsttype=tjvmsetconstnode(p).setconsttype);
+      end;
+
+
+    function tjvmsetconstnode.dogetcopy: tnode;
+      begin
+        result:=inherited dogetcopy;
+        tjvmsetconstnode(result).setconsttype:=setconsttype;
+      end;
+
+
+    function tjvmsetconstnode.emitvarsetconst: tasmsymbol;
+      var
+        csym: tconstsym;
+        ssym: tstaticvarsym;
+        ps: pnormalset;
+      begin
+        { add a read-only typed constant }
+        new(ps);
+        ps^:=value_set^;
+        csym:=cconstsym.create_ptr('_$setconst'+tostr(current_module.symlist.count),constset,ps,resultdef);
+        csym.visibility:=vis_private;
+        include(csym.symoptions,sp_internal);
+        current_module.localsymtable.insert(csym);
+        { generate assignment of the constant to the typed constant symbol }
+        ssym:=jvm_add_typed_const_initializer(csym);
+        result:=current_asmdata.RefAsmSymbol(ssym.mangledname,AT_DATA);
+      end;
+
+
+    function tjvmsetconstnode.find_single_elements_run(from: longint; out start, len: longint): boolean;
+      var
+        i: longint;
+      begin
+        i:=from;
+        result:=true;
+        { find first element in set }
+        while (i<=255) and
+              not(i in value_set^) do
+          inc(i);
+        start:=i;
+        { go to end of the run }
+        while (i<=255) and
+              (i in value_set^) do
+          inc(i);
+        len:=i-start;
+        { rest must be unset }
+        while (i<=255) and
+              not(i in value_set^) do
+          inc(i);
+        if i<>256 then
+          result:=false;
+      end;
+
+    *)
+
+begin
+   //cordconstnode:=tjvmordconstnode;
+   crealconstnode:=twasmrealconstnode;
+   //cstringconstnode:=tjvmstringconstnode;
+   //csetconstnode:=tjvmsetconstnode;
+end.

+ 263 - 0
compiler/wasm32/nwasmflw.pas

@@ -0,0 +1,263 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    Generate assembler for nodes that influence the flow for the JVM
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmflw;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      aasmbase,node,nflw,ncgflw, cutils;
+
+    type
+
+      { twasmifnode }
+
+      { Wasm doesn't have any jump(+offset) operations
+        It only provide structured blockes to handle jumps
+        (It's possible to jump-out-of-block at any time)
+        "If" is also implemented as a block, identical to high-level language. }
+      twasmifnode = class(tcgifnode)
+      public
+        procedure pass_generate_code;override;
+      end;
+
+      { twasmwhilerepeatnode }
+
+      twasmwhilerepeatnode = class(tcgwhilerepeatnode)
+      public
+        procedure pass_generate_code_condition;
+        procedure pass_generate_code;override;
+      end;
+
+      { twasmtryexceptnode }
+
+      twasmtryexceptnode = class(tcgtryexceptnode)
+      public
+        procedure pass_generate_code;override;
+      end;
+
+      { twasmtryfinallynode }
+
+      twasmtryfinallynode = class(tcgtryfinallynode)
+      public
+        procedure pass_generate_code;override;
+      end;
+
+implementation
+
+    uses
+      verbose,globals,systems,globtype,constexp,
+      symconst,symdef,symsym,aasmtai,aasmdata,aasmcpu,defutil,defcmp,
+      procinfo,cgbase,pass_1,pass_2,parabase,
+      cpubase,cpuinfo,
+      nbas,nld,ncon,ncnv,
+      tgobj,paramgr,
+      cgutils,hlcgobj,hlcgcpu;
+
+{*****************************************************************************
+                           twasmwhilerepeatnode
+*****************************************************************************}
+
+    procedure twasmwhilerepeatnode.pass_generate_code_condition;
+      begin
+        secondpass(left);
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+
+        // reversing the condition
+        if not (lnf_checknegate in loopflags) then
+          current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i32_eqz));
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br_if,1) );
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+      end;
+
+
+    procedure twasmwhilerepeatnode.pass_generate_code;
+      var
+         lcont,lbreak,lloop,
+         oldclabel,oldblabel : tasmlabel;
+         truelabel,falselabel : tasmlabel;
+         oldflowcontrol : tflowcontrol;
+         oldloopcontbroffset: Integer;
+         oldloopbreakbroffset: Integer;
+      begin
+        location_reset(location,LOC_VOID,OS_NO);
+
+        current_asmdata.getjumplabel(lloop);
+        current_asmdata.getjumplabel(lcont);
+        current_asmdata.getjumplabel(lbreak);
+
+        oldflowcontrol:=flowcontrol;
+
+        oldloopcontbroffset:=thlcgwasm(hlcg).loopContBr;
+        oldloopbreakbroffset:=thlcgwasm(hlcg).loopBreakBr;
+        oldclabel:=current_procinfo.CurrContinueLabel;
+        oldblabel:=current_procinfo.CurrBreakLabel;
+
+        include(flowcontrol,fc_inflowcontrol);
+        exclude(flowcontrol,fc_unwind_loop);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
+        thlcgwasm(hlcg).incblock;
+        thlcgwasm(hlcg).loopBreakBr:=thlcgwasm(hlcg).br_blocks;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_loop));
+        thlcgwasm(hlcg).incblock;
+
+        if lnf_testatbegin in loopflags then
+        begin
+          pass_generate_code_condition;
+          thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks;
+        end else
+          thlcgwasm(hlcg).loopContBr:=thlcgwasm(hlcg).br_blocks+1;
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
+        thlcgwasm(hlcg).incblock;
+
+        current_procinfo.CurrContinueLabel:=lcont;
+        current_procinfo.CurrBreakLabel:=lbreak;
+
+        secondpass(right);
+
+        if (lnf_testatbegin in loopflags) then
+          current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,1) ); // jump back to the external loop
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
+        thlcgwasm(hlcg).decblock;
+        if not (lnf_testatbegin in loopflags) then begin
+          pass_generate_code_condition;
+        end;
+        current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,0) ); // jump back to loop
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_loop));
+        thlcgwasm(hlcg).decblock;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
+        thlcgwasm(hlcg).decblock;
+
+        current_procinfo.CurrContinueLabel:=oldclabel;
+        current_procinfo.CurrBreakLabel:=oldblabel;
+        thlcgwasm(hlcg).loopContBr:=oldloopcontbroffset;
+        thlcgwasm(hlcg).loopBreakBr:=oldloopbreakbroffset;
+
+        { a break/continue in a while/repeat block can't be seen outside }
+        flowcontrol:=oldflowcontrol+(flowcontrol-[fc_break,fc_continue,fc_inflowcontrol]);
+      end;
+
+{*****************************************************************************
+                               twasmifnode
+*****************************************************************************}
+
+    procedure twasmifnode.pass_generate_code;
+      var
+        oldflowcontrol: tflowcontrol;
+      begin
+        // left  - condition
+        // right - then
+        // t1    - else (optional)
+
+        location_reset(location,LOC_VOID,OS_NO);
+
+        oldflowcontrol := flowcontrol;
+        include(flowcontrol,fc_inflowcontrol);
+
+        //todo: MOVE all current_asm_data actions to Wasm HL CodeGen
+
+        secondpass(left); // condition exprssions
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_if));
+        thlcgwasm(hlcg).incblock;
+        thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+        if Assigned(right) then
+          secondpass(right); // then branchs
+
+        if Assigned(t1) then // else branch
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_none(a_else));
+            secondpass(t1);
+          end;
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_if));
+        thlcgwasm(hlcg).decblock;
+
+        flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
+      end;
+
+{*****************************************************************************
+                             twasmtryexceptnode
+*****************************************************************************}
+
+    procedure twasmtryexceptnode.pass_generate_code;
+      begin
+        location_reset(location,LOC_VOID,OS_NO);
+
+        current_asmdata.CurrAsmList.concat(tai_comment.Create(strpnew('TODO: try..except, try')));
+
+        secondpass(left);
+        //if codegenerror then
+        //  goto errorexit;
+
+        current_asmdata.CurrAsmList.concat(tai_comment.Create(strpnew('TODO: try..except, end')));
+      end;
+
+{*****************************************************************************
+                             twasmtryfinallynode
+*****************************************************************************}
+
+    procedure twasmtryfinallynode.pass_generate_code;
+      begin
+        location_reset(location,LOC_VOID,OS_NO);
+
+        current_asmdata.CurrAsmList.concat(tai_comment.Create(strpnew('TODO: try..finally, try')));
+
+        { try code }
+        if assigned(left) then
+          begin
+            secondpass(left);
+            if codegenerror then
+              exit;
+          end;
+
+        current_asmdata.CurrAsmList.concat(tai_comment.Create(strpnew('TODO: try..finally, finally')));
+
+        { finally code (don't unconditionally set fc_inflowcontrol, since the
+          finally code is unconditionally executed; we do have to filter out
+          flags regarding break/contrinue/etc. because we have to give an
+          error in case one of those is used in the finally-code }
+        //flowcontrol:=finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions];
+        secondpass(right);
+        { goto is allowed if it stays inside the finally block,
+          this is checked using the exception block number }
+        //if (flowcontrol-[fc_gotolabel])<>(finallyexceptionstate.oldflowcontrol*[fc_inflowcontrol,fc_catching_exceptions]) then
+        //  CGMessage(cg_e_control_flow_outside_finally);
+        if codegenerror then
+          exit;
+        current_asmdata.CurrAsmList.concat(tai_comment.Create(strpnew('TODO: try..finally, end')));
+      end;
+
+initialization
+  cifnode:=twasmifnode;
+  cwhilerepeatnode:=twasmwhilerepeatnode;
+  ctryexceptnode:=twasmtryexceptnode;
+  ctryfinallynode:=twasmtryfinallynode;
+end.

+ 213 - 0
compiler/wasm32/nwasminl.pas

@@ -0,0 +1,213 @@
+{
+    Copyright (c) 1998-2002, 2021 by Florian Klaempfl and Nikolay Nikolov
+
+    Generate WebAssembly inline nodes
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasminl;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,ncginl;
+
+    type
+
+      { twasminlinenode }
+
+      twasminlinenode = class(tcginlinenode)
+      private
+        procedure second_memory_size;
+        procedure second_memory_grow;
+        procedure second_unreachable;
+      public
+        function pass_typecheck_cpu: tnode; override;
+        function first_cpu: tnode; override;
+        procedure pass_generate_code_cpu; override;
+        procedure second_length;override;
+      end;
+
+implementation
+
+    uses
+      ninl,compinnr,
+      cpubase,
+      aasmbase,aasmdata,aasmcpu,
+      cgbase,cgutils,
+      hlcgobj,hlcgcpu,
+      defutil,pass_2,
+      symtype,symdef;
+
+{*****************************************************************************
+                               twasminlinenode
+*****************************************************************************}
+
+    procedure twasminlinenode.second_memory_size;
+      begin
+        current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_memory_size));
+        thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getregisterfordef(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+
+    procedure twasminlinenode.second_memory_grow;
+      begin
+        secondpass(left);
+
+        hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+        thlcgwasm(hlcg).a_load_reg_stack(current_asmdata.CurrAsmList,left.resultdef,left.location.register);
+
+        current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_memory_grow));
+
+        location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getregisterfordef(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+      end;
+
+
+    procedure twasminlinenode.second_unreachable;
+      begin
+        location_reset(location,LOC_VOID,OS_NO);
+        current_asmdata.CurrAsmList.Concat(taicpu.op_none(a_unreachable));
+      end;
+
+
+    function twasminlinenode.pass_typecheck_cpu: tnode;
+      begin
+        Result:=nil;
+        case inlinenumber of
+          in_wasm32_memory_size:
+            begin
+              CheckParameters(0);
+              resultdef:=u32inttype;
+            end;
+          in_wasm32_memory_grow:
+            begin
+              CheckParameters(1);
+              resultdef:=u32inttype;
+            end;
+          in_wasm32_unreachable:
+            begin
+              CheckParameters(0);
+              resultdef:=voidtype;
+            end;
+          else
+            Result:=inherited pass_typecheck_cpu;
+        end;
+      end;
+
+
+    function twasminlinenode.first_cpu: tnode;
+      begin
+        Result:=nil;
+        case inlinenumber of
+          in_wasm32_memory_size,
+          in_wasm32_memory_grow:
+            expectloc:=LOC_REGISTER;
+          in_wasm32_unreachable:
+            expectloc:=LOC_VOID;
+          else
+            Result:=inherited first_cpu;
+        end;
+      end;
+
+
+    procedure twasminlinenode.pass_generate_code_cpu;
+      begin
+        case inlinenumber of
+          in_wasm32_memory_size:
+            second_memory_size;
+          in_wasm32_memory_grow:
+            second_memory_grow;
+          in_wasm32_unreachable:
+            second_unreachable;
+          else
+            inherited pass_generate_code_cpu;
+        end;
+      end;
+
+
+    procedure twasminlinenode.second_length;
+      var
+        lendef : tdef;
+        href : treference;
+        extra_slots: LongInt;
+      begin
+        secondpass(left);
+        if is_shortstring(left.resultdef) then
+          begin
+            location_copy(location,left.location);
+            location.size:=OS_8;
+          end
+        else
+          begin
+            { length in ansi/wide strings and high in dynamic arrays is at offset -sizeof(pint) }
+            hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+
+            thlcgwasm(hlcg).a_cmp_const_reg_stack(current_asmdata.CurrAsmList,left.resultdef,OC_EQ,0,left.location.register);
+
+            current_asmdata.CurrAsmList.Concat(taicpu.op_functype(a_if,TWasmFuncType.Create([],[wbt_i32])));
+            thlcgwasm(hlcg).incblock;
+            thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+            current_asmdata.CurrAsmList.Concat(taicpu.op_const(a_i32_const,0));
+            thlcgwasm(hlcg).incstack(current_asmdata.CurrAsmList,1);
+
+            current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_else) );
+            thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+
+            { the length of a widestring is a 32 bit unsigned int. Since every
+              character occupies 2 bytes, on a 32 bit platform you can express
+              the maximum length using 31 bits. On a 64 bit platform, it may be
+              32 bits. This means that regardless of the platform, a location
+              with size OS_SINT/ossinttype can hold the length without
+              overflowing (this code returns an ossinttype value) }
+            if is_widestring(left.resultdef) then
+              lendef:=u32inttype
+            else
+              lendef:=ossinttype;
+            { volatility of the ansistring/widestring refers to the volatility of the
+              string pointer, not of the string data }
+            hlcg.reference_reset_base(href,left.resultdef,left.location.register,-lendef.size,ctempposinvalid,lendef.alignment,[]);
+
+            extra_slots:=thlcgwasm(hlcg).prepare_stack_for_ref(current_asmdata.CurrAsmList,href,false);
+            thlcgwasm(hlcg).a_load_ref_stack(current_asmdata.CurrAsmList,lendef,href,extra_slots);
+            if is_widestring(left.resultdef) then
+              thlcgwasm(hlcg).a_op_const_stack(current_asmdata.CurrAsmList,OP_SHR,resultdef,1);
+
+            { Dynamic arrays do not have their length attached but their maximum index }
+            if is_dynamic_array(left.resultdef) then
+              thlcgwasm(hlcg).a_op_const_stack(current_asmdata.CurrAsmList,OP_ADD,resultdef,1);
+
+            current_asmdata.CurrAsmList.Concat( taicpu.op_none(a_end_if) );
+            thlcgwasm(hlcg).decblock;
+
+            location_reset(location,LOC_REGISTER,def_cgsize(resultdef));
+            location.register:=hlcg.getregisterfordef(current_asmdata.CurrAsmList,resultdef);
+            thlcgwasm(hlcg).a_load_stack_loc(current_asmdata.CurrAsmList,resultdef,location);
+          end;
+      end;
+
+begin
+  cinlinenode:=twasminlinenode;
+end.

+ 233 - 0
compiler/wasm32/nwasmmat.pas

@@ -0,0 +1,233 @@
+{
+    Copyright (c) 1998-2011, 2019 by Florian Klaempfl and Jonas Maebe, Dmitry Boyarintsev
+
+    Generate WebAssembly code for math nodes
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmmat;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,nmat,ncgmat,ncghlmat;
+
+    type
+      twasmmoddivnode = class(tmoddivnode)
+        protected
+          function use_moddiv64bitint_helper: boolean; override;
+        public
+         procedure pass_generate_code;override;
+      end;
+
+      twasmshlshrnode = class(tshlshrnode)
+         procedure pass_generate_code;override;
+      end;
+
+      twasmnotnode = class(tcgnotnode)
+      protected
+        procedure second_boolean;override;
+      end;
+
+      twasmunaryminusnode = class(tcgunaryminusnode)
+        procedure second_float;override;
+      end;
+
+implementation
+
+    uses
+      globtype,systems,constexp,
+      cutils,verbose,globals,compinnr,
+      symconst,symdef,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      defutil,
+      cgbase,cgobj,pass_2,procinfo,
+      ncon,
+      cpubase,
+      hlcgobj,hlcgcpu,cgutils;
+
+{*****************************************************************************
+                             twasmmoddivnode
+*****************************************************************************}
+
+    function twasmmoddivnode.use_moddiv64bitint_helper: boolean;
+      begin
+        result:=
+          (left.resultdef.typ=orddef) and
+          (right.resultdef.typ=orddef) and
+          ((torddef(left.resultdef).ordtype=u64bit) or
+           (torddef(right.resultdef).ordtype=u64bit));
+      end;
+
+
+    procedure twasmmoddivnode.pass_generate_code;
+      var
+        tmpreg: tregister;
+        lab: tasmlabel;
+        ovloc: tlocation;
+        op: topcg;
+        isu32int: boolean;
+      begin
+         secondpass(left);
+         secondpass(right);
+         location_reset(location,LOC_REGISTER,left.location.size);
+         location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+
+
+        if nodetype=divn then
+          begin
+            thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+            if is_signed(resultdef) then
+              op:=OP_IDIV
+            else
+              op:=OP_DIV;
+            thlcgwasm(hlcg).a_op_loc_stack(current_asmdata.CurrAsmList,op,right.resultdef,right.location)
+          end
+        else
+          begin
+            { must be handled via a helper }
+            if torddef(resultdef).ordtype=u64bit then
+              internalerror(2011010416);
+            if (torddef(resultdef).ordtype<>u32bit) then
+              begin
+                isu32int:=false;
+                thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+                thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+              end
+            else
+              begin
+                isu32int:=true;
+                if left.location.loc=LOC_CONSTANT then
+                  thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s64inttype,left.location.value,R_INTREGISTER)
+                else
+                  begin
+                    thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+                    thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,u32inttype,s64inttype,false);
+                  end;
+                if right.location.loc=LOC_CONSTANT then
+                  thlcgwasm(hlcg).a_load_const_stack(current_asmdata.CurrAsmList,s64inttype,right.location.value,R_INTREGISTER)
+                else
+                  begin
+                    thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+                    thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,u32inttype,s64inttype,false);
+                  end;
+              end;
+            if isu32int or
+               (torddef(resultdef).ordtype=s64bit) then
+              begin
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i64_rem_s));
+                thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+              end
+            else
+              begin
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(a_i32_rem_s));
+                thlcgwasm(hlcg).decstack(current_asmdata.CurrAsmList,1);
+              end;
+            if isu32int then
+              thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,s64inttype,u32inttype,false);
+          end;
+         thlcgwasm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+         if (cs_check_overflow in current_settings.localswitches) and
+            is_signed(resultdef) then
+           begin
+             { the JVM raises an exception for integer div-iby-zero -> only
+               overflow in case left is low(inttype) and right is -1 ->
+               check by adding high(inttype) to left and and'ing with right
+               -> result is -1 only in case above conditions are fulfilled)
+             }
+             tmpreg:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+             hlcg.location_force_reg(current_asmdata.CurrAsmList,right.location,right.resultdef,resultdef,true);
+             hlcg.a_op_const_reg_reg(current_asmdata.CurrAsmList,OP_ADD,resultdef,torddef(resultdef).high,right.location.register,tmpreg);
+             hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,resultdef,true);
+             hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_AND,resultdef,left.location.register,tmpreg);
+             current_asmdata.getjumplabel(lab);
+             hlcg.a_cmp_const_reg_label(current_asmdata.CurrAsmList,resultdef,OC_NE,-1,tmpreg,lab);
+             hlcg.g_call_system_proc(current_asmdata.CurrAsmList,'fpc_overflow',[],nil);
+             hlcg.a_label(current_asmdata.CurrAsmList,lab);
+           end;
+      end;
+
+
+{*****************************************************************************
+                             twasmshlshrnode
+*****************************************************************************}
+
+    procedure twasmshlshrnode.pass_generate_code;
+      var
+        op : topcg;
+      begin
+        secondpass(left);
+        secondpass(right);
+        location_reset(location,LOC_REGISTER,left.location.size);
+        location.register:=hlcg.getintregister(current_asmdata.CurrAsmList,resultdef);
+
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,right.resultdef,right.location);
+        thlcgwasm(hlcg).resize_stack_int_val(current_asmdata.CurrAsmList,right.resultdef,left.resultdef,false);
+        if nodetype=shln then
+          op:=OP_SHL
+        else
+          op:=OP_SHR;
+        thlcgwasm(hlcg).a_op_stack(current_asmdata.CurrAsmList,op,resultdef);
+        thlcgwasm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+
+{*****************************************************************************
+                               twasmnotnode
+*****************************************************************************}
+
+    procedure twasmnotnode.second_boolean;
+      begin
+        secondpass(left);
+        if not(left.location.loc in [LOC_REGISTER,LOC_CREGISTER]) then
+          hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,left.resultdef,false);
+        location_reset(location,LOC_REGISTER,left.location.size);
+        location.register:=cg.getintregister(current_asmdata.CurrAsmList,location.size);
+        { perform the NOT operation }
+        hlcg.a_op_reg_reg(current_asmdata.CurrAsmList,OP_NOT,left.resultdef,left.location.register,location.register);
+      end;
+
+{*****************************************************************************
+                            twasmunaryminustnode
+*****************************************************************************}
+
+    procedure twasmunaryminusnode.second_float;
+      var
+        opc: tasmop;
+      begin
+        secondpass(left);
+        location_reset(location,LOC_FPUREGISTER,def_cgsize(resultdef));
+        location.register:=hlcg.getfpuregister(current_asmdata.CurrAsmList,resultdef);
+        thlcgwasm(hlcg).a_load_loc_stack(current_asmdata.CurrAsmList,left.resultdef,left.location);
+        if (tfloatdef(left.resultdef).floattype=s32real) then
+          opc:=a_f32_neg
+        else
+          opc:=a_f64_neg;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(opc));
+        thlcgwasm(hlcg).a_load_stack_reg(current_asmdata.CurrAsmList,resultdef,location.register);
+      end;
+
+
+begin
+   cmoddivnode:=twasmmoddivnode;
+   cshlshrnode:=twasmshlshrnode;
+   cnotnode:=twasmnotnode;
+   cunaryminusnode:=twasmunaryminusnode;
+end.

+ 502 - 0
compiler/wasm32/nwasmset.pas

@@ -0,0 +1,502 @@
+{
+    Copyright (c) 1998-2002, 2021 by Florian Klaempfl and Nikolay Nikolov
+
+    Generate WebAssembly code for in/case nodes
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit nwasmset;
+
+{$i fpcdefs.inc}
+
+interface
+
+    uses
+      node,nset,ncgset;
+
+    type
+
+      { twasminnode }
+
+      twasminnode = class(tcginnode)
+      protected
+        function checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean;override;
+      end;
+
+      { twasmcasenode }
+
+      twasmcasenode = class(tcgcasenode)
+      private
+        ElseBr: Integer;
+        EndBr: Integer;
+
+        function GetBranchBr(Block: TNode; out _Br: Integer): Boolean;
+      protected
+        function BlockBr(id:longint):Integer;
+        procedure genlinearlist(hp : pcaselabel);override;
+        procedure genlinearcmplist(hp : pcaselabel);override;
+      public
+        procedure pass_generate_code;override;
+      end;
+
+implementation
+
+    uses
+      globtype,globals,
+      cpubase,
+      cgbase,cgutils,
+      aasmdata,aasmcpu,
+      hlcgobj,hlcgcpu,
+      nbas,
+      symtype,
+      pass_2,defutil,verbose,constexp;
+
+{*****************************************************************************
+                                 TWASMINNODE
+*****************************************************************************}
+
+    function twasminnode.checkgenjumps(out setparts: Tsetparts; out numparts: byte; out use_small: boolean): boolean;
+      begin
+        result:=false;
+      end;
+
+{*****************************************************************************
+                                TWASMCASENODE
+*****************************************************************************}
+
+    function twasmcasenode.GetBranchBr(Block: TNode; out _Br: Integer): Boolean;
+      begin
+        Result := True;
+
+        if not Assigned(Block) then
+          begin
+            { Block doesn't exist / is empty }
+            _Br := EndBr;
+            Exit;
+          end;
+
+        { These optimisations aren't particularly debugger friendly }
+        if not (cs_opt_level2 in current_settings.optimizerswitches) then
+          begin
+            Result := False;
+            current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
+            thlcgwasm(hlcg).incblock;
+            _Br:=thlcgwasm(hlcg).br_blocks;
+            Exit;
+          end;
+
+        while Assigned(Block) do
+          begin
+            case Block.nodetype of
+              nothingn:
+                begin
+                  _Br := EndBr;
+                  Exit;
+                end;
+              goton:
+                InternalError(2021011801);
+              blockn:
+                begin
+                  Block := TBlockNode(Block).Left;
+                  Continue;
+                end;
+              statementn:
+                begin
+                  { If the right node is assigned, then it's a compound block
+                    that can't be simplified, so fall through, set Result to
+                    False and make a new label }
+
+                  if Assigned(TStatementNode(Block).right) then
+                    Break;
+
+                  Block := TStatementNode(Block).Left;
+                  Continue;
+                end;
+              else
+                ;
+            end;
+
+            Break;
+          end;
+
+        { Create unique label }
+        Result := False;
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
+        thlcgwasm(hlcg).incblock;
+        _Br:=thlcgwasm(hlcg).br_blocks;
+      end;
+
+
+    function twasmcasenode.BlockBr(id: longint): Integer;
+      begin
+        if not assigned(blocks[id]) then
+          internalerror(200411301);
+        result:=pcaseblock(blocks[id])^.BlockBr;
+      end;
+
+
+    procedure twasmcasenode.genlinearlist(hp: pcaselabel);
+
+      var
+        first : boolean;
+        last : TConstExprInt;
+        scratch_reg: tregister;
+        newsize: tcgsize;
+        newdef: tdef;
+
+      procedure gensub(value:tcgint);
+        begin
+          { here, since the sub and cmp are separate we need
+            to move the result before subtract to help
+            the register allocator
+          }
+          hlcg.a_load_reg_reg(current_asmdata.CurrAsmList, opsize, opsize, hregister, scratch_reg);
+          hlcg.a_op_const_reg(current_asmdata.CurrAsmList, OP_SUB, opsize, value, hregister);
+        end;
+
+
+      procedure genitem(t : pcaselabel);
+        begin
+          if assigned(t^.less) then
+            genitem(t^.less);
+          { do we need to test the first value? }
+          if first and (t^._low>get_min_value(left.resultdef)) then
+            thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList,opsize,jmp_lt,tcgint(t^._low.svalue),hregister,thlcgwasm(hlcg).br_blocks-ElseBr);
+          if t^._low=t^._high then
+            begin
+              if t^._low-last=0 then
+                thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList,opsize,OC_EQ,0,hregister,thlcgwasm(hlcg).br_blocks-BlockBr(t^.blockid))
+              else
+                begin
+                  gensub(tcgint(t^._low.svalue-last.svalue));
+                  thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList,opsize,
+                                           OC_EQ,tcgint(t^._low.svalue-last.svalue),scratch_reg,thlcgwasm(hlcg).br_blocks-BlockBr(t^.blockid));
+                end;
+              last:=t^._low;
+            end
+          else
+            begin
+               { it begins with the smallest label, if the value }
+               { is even smaller then jump immediately to the    }
+               { ELSE-label                                }
+               if first then
+                 begin
+                   { have we to ajust the first value ? }
+                   if (t^._low>get_min_value(left.resultdef)) or (get_min_value(left.resultdef)<>0) then
+                     gensub(tcgint(t^._low.svalue));
+                 end
+               else
+                 begin
+                   { if there is no unused label between the last and the }
+                   { present label then the lower limit can be checked    }
+                   { immediately. else check the range in between:       }
+                   gensub(tcgint(t^._low.svalue-last.svalue));
+                   thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize,jmp_lt,tcgint(t^._low.svalue-last.svalue),scratch_reg,thlcgwasm(hlcg).br_blocks-ElseBr);
+                 end;
+               gensub(tcgint(t^._high.svalue-t^._low.svalue));
+               thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList,opsize,jmp_le,tcgint(t^._high.svalue-t^._low.svalue),scratch_reg,thlcgwasm(hlcg).br_blocks-BlockBr(t^.blockid));
+               last:=t^._high;
+            end;
+          first:=false;
+          if assigned(t^.greater) then
+            genitem(t^.greater);
+        end;
+
+      begin
+        { do we need to generate cmps? }
+        if (with_sign and (min_label<0)) then
+          genlinearcmplist(hp)
+        else
+          begin
+            { sign/zero extend the value to a full register before starting to
+              subtract values, so that on platforms that don't have
+              subregisters of the same size as the value we don't generate
+              sign/zero-extensions after every subtraction
+
+              make newsize always signed, since we only do this if the size in
+              bytes of the register is larger than the original opsize, so
+              the value can always be represented by a larger signed type }
+            newsize:=tcgsize2signed[reg_cgsize(hregister)];
+            if tcgsize2size[newsize]>opsize.size then
+              begin
+                newdef:=cgsize_orddef(newsize);
+                scratch_reg:=hlcg.getintregister(current_asmdata.CurrAsmList,newdef);
+                hlcg.a_load_reg_reg(current_asmdata.CurrAsmList,opsize,newdef,hregister,scratch_reg);
+                hregister:=scratch_reg;
+                opsize:=newdef;
+              end;
+            if (labelcnt>1) or not(cs_opt_level1 in current_settings.optimizerswitches) then
+              begin
+                last:=0;
+                first:=true;
+                scratch_reg:=hlcg.getintregister(current_asmdata.CurrAsmList,opsize);
+                genitem(hp);
+              end
+            else
+              begin
+                { If only one label exists, we can greatly simplify the checks to a simple comparison }
+                if hp^._low=hp^._high then
+                  thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize, OC_EQ, tcgint(hp^._low.svalue), hregister, thlcgwasm(hlcg).br_blocks-BlockBr(hp^.blockid))
+                else
+                  begin
+                    scratch_reg:=hlcg.getintregister(current_asmdata.CurrAsmList,opsize);
+                    gensub(tcgint(hp^._low.svalue));
+                    thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize, OC_BE, tcgint(hp^._high.svalue-hp^._low.svalue), hregister, thlcgwasm(hlcg).br_blocks-BlockBr(hp^.blockid))
+                  end;
+              end;
+            current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-ElseBr));
+          end;
+      end;
+
+
+    procedure twasmcasenode.genlinearcmplist(hp : pcaselabel);
+
+      var
+        last : TConstExprInt;
+        lastwasrange: boolean;
+
+      procedure genitem(t : pcaselabel);
+        begin
+          if assigned(t^.less) then
+            genitem(t^.less);
+          if t^._low=t^._high then
+            begin
+              thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize, OC_EQ, tcgint(t^._low.svalue),hregister, thlcgwasm(hlcg).br_blocks-BlockBr(t^.blockid));
+              { Reset last here, because we've only checked for one value and need to compare
+                for the next range both the lower and upper bound }
+              lastwasrange := false;
+            end
+          else
+            begin
+              { it begins with the smallest label, if the value }
+              { is even smaller then jump immediately to the    }
+              { ELSE-label                                }
+              if not lastwasrange or (t^._low-last>1) then
+                thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize, jmp_lt, tcgint(t^._low.svalue), hregister, thlcgwasm(hlcg).br_blocks-ElseBr);
+              thlcgwasm(hlcg).a_cmp_const_reg_br(current_asmdata.CurrAsmList, opsize, jmp_le, tcgint(t^._high.svalue), hregister, thlcgwasm(hlcg).br_blocks-BlockBr(t^.blockid));
+
+              last:=t^._high;
+              lastwasrange := true;
+            end;
+          if assigned(t^.greater) then
+            genitem(t^.greater);
+        end;
+
+      begin
+        last:=0;
+        lastwasrange:=false;
+        genitem(hp);
+        current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-ElseBr));
+      end;
+
+
+    procedure twasmcasenode.pass_generate_code;
+      var
+        oldflowcontrol: tflowcontrol;
+        ShortcutElse: Boolean;
+        i: Integer;
+      begin
+        location_reset(location,LOC_VOID,OS_NO);
+
+        oldflowcontrol := flowcontrol;
+        include(flowcontrol,fc_inflowcontrol);
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_block));
+        thlcgwasm(hlcg).incblock;
+        EndBr:=thlcgwasm(hlcg).br_blocks;
+
+        { Do some optimisation to deal with empty else blocks }
+        ShortcutElse := GetBranchBr(elseblock, ElseBr);
+
+        for i:=blocks.count-1 downto 0 do
+          with pcaseblock(blocks[i])^ do
+            shortcut := GetBranchBr(statement, BlockBr);
+
+        with_sign:=is_signed(left.resultdef);
+        if with_sign then
+          begin
+            jmp_gt:=OC_GT;
+            jmp_lt:=OC_LT;
+            jmp_le:=OC_LTE;
+          end
+        else
+          begin
+            jmp_gt:=OC_A;
+            jmp_lt:=OC_B;
+            jmp_le:=OC_BE;
+          end;
+
+        secondpass(left);
+        if (left.expectloc=LOC_JUMP)<>
+           (left.location.loc=LOC_JUMP) then
+          internalerror(2006050501);
+        { determines the size of the operand }
+        opsize:=left.resultdef;
+        { copy the case expression to a register }
+        hlcg.location_force_reg(current_asmdata.CurrAsmList,left.location,left.resultdef,opsize,false);
+{$if not defined(cpu64bitalu)}
+        if def_cgsize(opsize) in [OS_S64,OS_64] then
+          begin
+            hregister:=left.location.register64.reglo;
+            hregister2:=left.location.register64.reghi;
+          end
+        else
+{$endif not cpu64bitalu and not cpuhighleveltarget}
+          hregister:=left.location.register;
+
+        { we need the min_label always to choose between }
+        { cmps and subs/decs                             }
+        min_label:=case_get_min(labels);
+
+        { Generate the jumps }
+{$ifdef OLDREGVARS}
+        load_all_regvars(current_asmdata.CurrAsmList);
+{$endif OLDREGVARS}
+{$if not defined(cpu64bitalu)}
+        if def_cgsize(opsize) in [OS_64,OS_S64] then
+          genlinearcmplist(labels)
+        else
+{$endif not cpu64bitalu and not cpuhighleveltarget}
+          begin
+            //if cs_opt_level1 in current_settings.optimizerswitches then
+            //  begin
+            //    { procedures are empirically passed on }
+            //    { consumption can also be calculated   }
+            //    { but does it pay on the different     }
+            //    { processors?                       }
+            //    { moreover can the size only be appro- }
+            //    { ximated as it is not known if rel8,  }
+            //    { rel16 or rel32 jumps are used   }
+            //
+            //    max_label := case_get_max(labels);
+            //
+            //    { can we omit the range check of the jump table ? }
+            //    getrange(left.resultdef,lv,hv);
+            //    jumptable_no_range:=(lv=min_label) and (hv=max_label);
+            //
+            //    distv:=max_label-min_label;
+            //    if distv>=0 then
+            //      dist:=distv.uvalue
+            //    else
+            //      dist:=asizeuint(-distv.svalue);
+            //
+            //    { optimize for size ? }
+            //    if cs_opt_size in current_settings.optimizerswitches  then
+            //      begin
+            //        if has_jumptable and
+            //           (min_label>=int64(low(aint))) and
+            //           (max_label<=high(aint)) and
+            //           not((labelcnt<=2) or
+            //               (distv.svalue<0) or
+            //               (dist>3*labelcnt)) then
+            //          begin
+            //            { if the labels less or more a continuum then }
+            //            genjumptable(labels,min_label.svalue,max_label.svalue);
+            //          end
+            //        else
+            //          begin
+            //            { a linear list is always smaller than a jump tree }
+            //            genlinearlist(labels);
+            //          end;
+            //      end
+            //    else
+            //      begin
+            //        max_dist:=4*labelcoverage;
+            //
+            //        { Don't allow jump tables to get too large }
+            //        if max_dist>4*labelcnt then
+            //          max_dist:=min(max_dist,2048);
+            //
+            //        if jumptable_no_range then
+            //          max_linear_list:=4
+            //        else
+            //          max_linear_list:=2;
+            //
+            //        { allow processor specific values }
+            //        optimizevalues(max_linear_list,max_dist);
+            //
+            //        if (labelcnt<=max_linear_list) then
+            //          genlinearlist(labels)
+            //        else
+            //          begin
+            //            if (has_jumptable) and
+            //               (dist<max_dist) and
+            //               (min_label>=int64(low(aint))) and
+            //               (max_label<=high(aint)) then
+            //              genjumptable(labels,min_label.svalue,max_label.svalue)
+            //            { value has been determined on an i7-4770 using a random case with random values
+            //              if more values are known, this can be handled depending on the target CPU
+            //
+            //              Testing on a Core 2 Duo E6850 as well as on a Raspi3 showed also, that 64 is
+            //              a good value }
+            //            else if labelcnt>=64 then
+            //              genjmptree(labels)
+            //            else
+            //              genlinearlist(labels);
+            //          end;
+            //      end;
+            //  end
+            //else
+              { it's always not bad }
+              genlinearlist(labels);
+          end;
+
+        { generate the instruction blocks }
+        for i:=0 to blocks.count-1 do with pcaseblock(blocks[i])^ do
+          begin
+            { If the labels are not equal, then the block label has been shortcut to point elsewhere,
+              so there's no need to implement it }
+            if not shortcut then
+              begin
+                current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
+                thlcgwasm(hlcg).decblock;
+                secondpass(statement);
+                { don't come back to case line }
+                current_filepos:=current_asmdata.CurrAsmList.getlasttaifilepos^;
+{$ifdef OLDREGVARS}
+                load_all_regvars(current_asmdata.CurrAsmList);
+{$endif OLDREGVARS}
+                current_asmdata.CurrAsmList.concat(taicpu.op_const(a_br,thlcgwasm(hlcg).br_blocks-EndBr));
+              end;
+          end;
+
+        { ...and the else block }
+        if not ShortcutElse then
+          begin
+            current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
+            thlcgwasm(hlcg).decblock;
+          end;
+
+        if Assigned(elseblock) then
+          begin
+
+            secondpass(elseblock);
+{$ifdef OLDREGVARS}
+            load_all_regvars(current_asmdata.CurrAsmList);
+{$endif OLDREGVARS}
+          end;
+
+        current_asmdata.CurrAsmList.concat(taicpu.op_none(a_end_block));
+        thlcgwasm(hlcg).decblock;
+
+        flowcontrol := oldflowcontrol + (flowcontrol - [fc_inflowcontrol]);
+      end;
+
+begin
+  cinnode:=twasminnode;
+  ccasenode:=twasmcasenode;
+end.

+ 451 - 0
compiler/wasm32/rgcpu.pas

@@ -0,0 +1,451 @@
+{
+    Copyright (c) 2019 by Dmitry Boyarintsev
+
+    This unit implements the WebAssembly specific class for the register
+    allocator
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************}
+unit rgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+      cclasses,
+      aasmbase,aasmcpu,aasmtai,aasmdata,
+      cgbase,cgutils, procinfo,
+      cpubase,
+      rgobj;
+
+    type
+      tspilltemps = array[tregistertype] of ^Tspill_temp_list;
+
+      { trgcpu }
+
+      trgcpu=class(trgobj)
+       protected
+        class procedure do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
+        class procedure remove_dummy_load_stores(list: TAsmList; headertai: tai);
+       public
+        { performs the register allocation for *all* register types }
+        class procedure do_all_register_allocation(list: TAsmList; headertai: tai);
+      end;
+
+
+implementation
+
+    uses
+      verbose,cutils,
+      globtype,globals,
+      cgobj,
+      tgobj,
+      symtype,symdef,symcpu;
+
+    { trgcpu }
+
+    class procedure trgcpu.do_spill_replace_all(list:TAsmList;instr:taicpu;const spilltemps: tspilltemps);
+      var
+        l: longint;
+        reg: tregister;
+      begin
+        { WebAssebly instructions never have more than one memory (virtual register)
+          operand, so there is no danger of superregister conflicts }
+        for l:=0 to instr.ops-1 do
+          if (instr.oper[l]^.typ=top_reg) and (instr.oper[l]^.reg<>NR_LOCAL_FRAME_POINTER_REG) then
+            begin
+              reg:=instr.oper[l]^.reg;
+              instr.loadref(l,spilltemps[getregtype(reg)]^[getsupreg(reg)]);
+            end;
+      end;
+
+
+    class procedure trgcpu.remove_dummy_load_stores(list: TAsmList; headertai: tai);
+
+      type
+        taitypeset =  set of taitype;
+
+      function nextskipping(p: tai; const skip: taitypeset): tai;
+        begin
+          result:=p;
+          if not assigned(result) then
+            exit;
+          repeat
+            result:=tai(result.next);
+          until not assigned(result) or
+                not(result.typ in skip);
+        end;
+
+      function issimpleregstore(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
+        const
+          simplestoressp = [a_f32_store];
+          simplestoresdp = [a_f64_store];
+        begin
+          result:=
+            assigned(p) and
+            (p.typ=ait_instruction) and
+            ((taicpu(p).opcode in simplestoressp) or
+             (doubleprecisionok and
+              (taicpu(p).opcode in simplestoresdp))) and
+            ((reg=NR_NO) or
+             (taicpu(p).oper[0]^.typ=top_reg) and
+             (taicpu(p).oper[0]^.reg=reg));
+          if result and
+             (reg=NR_NO) then
+            reg:=taicpu(p).oper[0]^.reg;
+        end;
+
+      function issimpleregload(p: tai; var reg: tregister; doubleprecisionok: boolean): boolean;
+        const
+          simpleloadssp = [a_f32_load];
+          simpleloadsdp = [a_f64_load];
+        begin
+          result:=
+            assigned(p) and
+            (p.typ=ait_instruction) and
+            ((taicpu(p).opcode in simpleloadssp) or
+             (doubleprecisionok and
+              (taicpu(p).opcode in simpleloadsdp))) and
+            ((reg=NR_NO) or
+             (taicpu(p).oper[0]^.typ=top_reg) and
+             (taicpu(p).oper[0]^.reg=reg));
+          if result and
+             (reg=NR_NO) then
+            reg:=taicpu(p).oper[0]^.reg;
+        end;
+
+      function isregallocoftyp(p: tai; typ: TRegAllocType;var reg: tregister): boolean;
+        begin
+          result:=
+            assigned(p) and
+            (p.typ=ait_regalloc) and
+            (tai_regalloc(p).ratype=typ);
+          if result then
+            if reg=NR_NO then
+              reg:=tai_regalloc(p).reg
+            else
+              result:=tai_regalloc(p).reg=reg;
+        end;
+
+      function regininstruction(p: tai; reg: tregister): boolean;
+        var
+          sr: tsuperregister;
+          i: longint;
+        begin
+          result:=false;
+          if p.typ<>ait_instruction then
+            exit;
+          sr:=getsupreg(reg);
+          for i:=0 to taicpu(p).ops-1 do
+            case taicpu(p).oper[0]^.typ of
+              top_reg:
+                if (getsupreg(taicpu(p).oper[0]^.reg)=sr) then
+                  exit(true);
+              top_ref:
+                begin
+                  if (getsupreg(taicpu(p).oper[0]^.ref^.base)=sr) then
+                    exit(true);
+                  if (getsupreg(taicpu(p).oper[0]^.ref^.index)=sr) then
+                    exit(true);
+                end;
+              else
+                ;
+            end;
+        end;
+
+      function try_remove_store_dealloc_load(var p: tai): boolean;
+        var
+          dealloc,
+          load: tai;
+          reg: tregister;
+        begin
+          result:=false;
+          { check for:
+              store regx
+              dealloc regx
+              load regx
+            and remove. We don't have to check that the load/store
+            types match, because they have to for this to be
+            valid WebAssembly code }
+          dealloc:=nextskipping(p,[ait_comment,ait_tempalloc]);
+          load:=nextskipping(dealloc,[ait_comment,ait_tempalloc]);
+          reg:=NR_NO;
+          if issimpleregstore(p,reg,true) and
+             isregallocoftyp(dealloc,ra_dealloc,reg) and
+             issimpleregload(load,reg,true) then
+            begin
+              { remove the whole sequence: the store }
+              list.remove(p);
+              p.free;
+              p:=Tai(load.next);
+              { the load }
+              list.remove(load);
+              load.free;
+
+              result:=true;
+            end;
+        end;
+
+
+     function try_swap_store_x_load(var p: tai): boolean;
+       var
+         insertpos,
+         storex,
+         deallocy,
+         loady,
+         deallocx,
+         loadx: tai;
+         swapxy: taicpu;
+         regx, regy: tregister;
+       begin
+         result:=false;
+         { check for:
+             alloc regx (optional)
+             store regx (p)
+             dealloc regy
+             load regy
+             dealloc regx
+             load regx
+           and change to
+             dealloc regy
+             load regy
+             swap
+             alloc regx (if it existed)
+             store regx
+             dealloc regx
+             load  regx
+
+           This will create opportunities to remove the store/load regx
+           (and possibly also for regy)
+         }
+         //regx:=NR_NO;
+         //regy:=NR_NO;
+         //if not issimpleregstore(p,regx,false) then
+         //  exit;
+         //storex:=p;
+         //deallocy:=nextskipping(storex,[ait_comment,ait_tempalloc]);
+         //loady:=nextskipping(deallocy,[ait_comment,ait_tempalloc]);
+         //deallocx:=nextskipping(loady,[ait_comment,ait_tempalloc]);
+         //loadx:=nextskipping(deallocx,[ait_comment,ait_tempalloc]);
+         //if not assigned(loadx) then
+         //  exit;
+         //if not issimpleregload(loady,regy,false) then
+         //  exit;
+         //if not issimpleregload(loadx,regx,false) then
+         //  exit;
+         //if not isregallocoftyp(deallocy,ra_dealloc,regy) then
+         //  exit;
+         //if not isregallocoftyp(deallocx,ra_dealloc,regx) then
+         //  exit;
+         //insertpos:=tai(p.previous);
+         //if not assigned(insertpos) or
+         //   not isregallocoftyp(insertpos,ra_alloc,regx) then
+         //  insertpos:=storex;
+         //list.remove(deallocy);
+         //list.insertbefore(deallocy,insertpos);
+         //list.remove(loady);
+         //list.insertbefore(loady,insertpos);
+         //swapxy:=taicpu.op_none(a_swap);
+         //swapxy.fileinfo:=taicpu(loady).fileinfo;
+         //list.insertbefore(swapxy,insertpos);
+         //result:=true;
+       end;
+
+
+      var
+        p,next,nextnext: tai;
+        reg: tregister;
+        removedsomething: boolean;
+      begin
+        repeat
+          removedsomething:=false;
+          p:=headertai;
+          while assigned(p) do
+            begin
+              case p.typ of
+                ait_regalloc:
+                  begin
+                    reg:=NR_NO;
+                    next:=nextskipping(p,[ait_comment,ait_tempalloc]);
+                    nextnext:=nextskipping(next,[ait_comment,ait_regalloc]);
+                    if assigned(nextnext) then
+                      begin
+                        { remove
+                            alloc reg
+                            dealloc reg
+
+                          (can appear after optimisations, necessary to prevent
+                           useless stack slot allocations) }
+                        if isregallocoftyp(p,ra_alloc,reg) and
+                           isregallocoftyp(next,ra_dealloc,reg) and
+                           not regininstruction(nextnext,reg) then
+                          begin
+                            list.remove(p);
+                            p.free;
+                            p:=tai(next.next);
+                            list.remove(next);
+                            next.free;
+                            removedsomething:=true;
+                            continue;
+                          end;
+                      end;
+                  end;
+                ait_instruction:
+                  begin
+                    if try_remove_store_dealloc_load(p) or
+                       try_swap_store_x_load(p) then
+                      begin
+                        removedsomething:=true;
+                        continue;
+                      end;
+                  end;
+                else
+                  ;
+              end;
+              p:=tai(p.next);
+            end;
+        until not removedsomething;
+      end;
+
+    class procedure trgcpu.do_all_register_allocation(list: TAsmList; headertai: tai);
+      var
+        spill_temps : tspilltemps;
+        templist : TAsmList;
+        intrg,
+        fprg     : trgcpu;
+        p,q      : tai;
+        size     : longint;
+
+        insbefore : TLinkedListItem;
+        lastins   : TLinkedListItem;
+        //locavail  : array[TWasmBasicType] of tlocalalloc; // used or not
+
+        ra      : tai_regalloc;
+        idx     : integer;
+        fidx    : integer;
+        pidx    : integer;
+        t: treftemppos;
+        def: tdef;
+
+      begin
+        { Since there are no actual registers, we simply spill everything. We
+          use tt_regallocator temps, which are not used by the temp allocator
+          during code generation, so that we cannot accidentally overwrite
+          any temporary values }
+
+        { get references to all register allocators }
+        intrg:=trgcpu(cg.rg[R_INTREGISTER]);
+        fprg:=trgcpu(cg.rg[R_FPUREGISTER]);
+        { determine the live ranges of all registers }
+        intrg.insert_regalloc_info_all(list);
+        fprg.insert_regalloc_info_all(list);
+        { Don't do the actual allocation when -sr is passed }
+        if (cs_no_regalloc in current_settings.globalswitches) then
+          exit;
+        { remove some simple useless store/load sequences }
+        remove_dummy_load_stores(list,headertai);
+        { allocate room to store the virtual register -> temp mapping }
+        spill_temps[R_INTREGISTER]:=allocmem(sizeof(treference)*intrg.maxreg);
+        spill_temps[R_FPUREGISTER]:=allocmem(sizeof(treference)*fprg.maxreg);
+        { List to insert temp allocations into }
+        templist:=TAsmList.create;
+        { allocate/replace all registers }
+        p:=headertai;
+        insbefore := nil;
+        while assigned(p) do
+          begin
+            case p.typ of
+              ait_regalloc:
+                  begin
+                    ra := tai_regalloc(p);
+                    case getregtype(ra.reg) of
+                      R_INTREGISTER:
+                        case getsubreg(ra.reg) of
+                          R_SUBD:
+                            begin
+                              size:=4;
+                              def:=s32inttype;
+                            end;
+                          R_SUBQ:
+                            begin
+                              size:=8;
+                              def:=s64inttype;
+                            end;
+                          else
+                            internalerror(2020120803);
+                        end;
+                      R_ADDRESSREGISTER:
+                        begin
+                          size:=4;
+                          def:=voidpointertype;
+                        end;
+                      R_FPUREGISTER:
+                        case getsubreg(ra.reg) of
+                          R_SUBFS:
+                            begin
+                              size:=4;
+                              def:=s32floattype;
+                            end;
+                          R_SUBFD:
+                            begin
+                              size:=8;
+                              def:=s64floattype;
+                            end;
+                          else
+                            internalerror(2020120804);
+                        end;
+                      else
+                        internalerror(2010122912);
+                    end;
+                    case ra.ratype of
+                      ra_alloc :
+                        tg.gethltemp(templist,def,
+                                     size,
+                                     tt_regallocator,spill_temps[getregtype(ra.reg)]^[getsupreg(ra.reg)]);
+                      ra_dealloc :
+                        begin
+                          tg.ungettemp(templist,spill_temps[getregtype(ra.reg)]^[getsupreg(ra.reg)]);
+                          { don't invalidate the temp reference, may still be used one instruction
+                            later }
+                        end;
+                      else
+                        ;
+                    end;
+                    { insert the tempallocation/free at the right place }
+                    { remove the register allocation info for the register
+                      (p.previous is valid because we just inserted the temp
+                       allocation/free before p) }
+                    q:=Tai(p.previous);
+                    list.remove(p);
+                    p.free;
+                    p:=q;
+                  end;
+              ait_instruction:
+                do_spill_replace_all(list,taicpu(p),spill_temps);
+              else
+                ;
+            end;
+            p:=Tai(p.next);
+          end;
+        if templist.count>0 then
+          list.insertListBefore(nil, templist);
+        freemem(spill_temps[R_INTREGISTER]);
+        freemem(spill_temps[R_FPUREGISTER]);
+        templist.free;
+      end;
+
+end.

+ 6 - 0
compiler/wasm32/rwasmcon.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+NR_NO = tregister($00000000);
+NR_R0 = tregister($01000000);
+NR_R1 = tregister($01000001);
+NR_R2 = tregister($01000002);
+NR_R3 = tregister($01000003);

+ 2 - 0
compiler/wasm32/rwasmnor.inc

@@ -0,0 +1,2 @@
+{ don't edit, this file is generated from wasmreg.dat }
+5

+ 6 - 0
compiler/wasm32/rwasmnum.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+tregister($00000000),
+tregister($01000000),
+tregister($01000001),
+tregister($01000002),
+tregister($01000003)

+ 6 - 0
compiler/wasm32/rwasmrni.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+0,
+1,
+2,
+3,
+4

+ 6 - 0
compiler/wasm32/rwasmsri.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+0,
+3,
+1,
+4,
+2

+ 6 - 0
compiler/wasm32/rwasmstd.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+'INVALID',
+'evalstacktopptr',
+'localsstackptr',
+'evalstacktop',
+'localframeptr'

+ 6 - 0
compiler/wasm32/rwasmsup.inc

@@ -0,0 +1,6 @@
+{ don't edit, this file is generated from wasmreg.dat }
+RS_NO = $00;
+RS_R0 = $00;
+RS_R1 = $01;
+RS_R2 = $02;
+RS_R3 = $03;

+ 70 - 0
compiler/wasm32/strinst.inc

@@ -0,0 +1,70 @@
+{
+    Copyright (c) 2016 by Karoly Balogh
+
+    This include file contains the WebAssembly instruction string table
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+
+        '<none>',
+        // control flow
+        'block', 'loop', 'br', 'br_if', 'br_table', 'if', 'else', 'end', 'end', 'end', '',
+        'return', 'unreachable',
+        // basic
+        'nop', 'drop', 'i32.const', 'i64.const', 'f32.const', 'f64.const',
+        'get_local', 'set_local', 'tee_local', 'get_global', 'set_global',
+        'select', 'call', 'call_indirect',
+        // integer
+        'i32.add', 'i64.add', 'i32.sub', 'i64.sub', 'i32.mul', 'i64.mul',
+        'i32.div_s', 'i64.div_s', 'i32.div_u', 'i64.div_u', 'i32.rem_s', 'i64.rem_s',
+        'i32.rem_u', 'i64.rem_u', 'i32.and', 'i64.and', 'i32.or', 'i64.or',
+        'i32.xor', 'i64.xor', 'i32.shl', 'i64.shl', 'i32.shr_s', 'i64.shr_s',
+        'i32.shr_u', 'i64.shr_u', 'i32.rotl', 'i64.rotl', 'i32.rotr', 'i64.rotr',
+        'i32.clz', 'i64.clz', 'i32.ctz', 'i64.ctz', 'i32.popcnt', 'i64.popcnt',
+        'i32.eqz', 'i64.eqz',
+        // floating point
+        'f32.add', 'f64.add', 'f32.sub', 'f64.sub', 'f32.mul', 'f64.mul',
+        'f32.div', 'f64.div', 'f32.sqrt', 'f64.sqrt', 'f32.min', 'f64.min',
+        'f32.max', 'f64.max', 'f32.ceil', 'f64.ceil', 'f32.floor', 'f64.floor',
+        'f32.trunc', 'f64.trunc', 'f32.nearest', 'f64.nearest', 'f32.abs', 'f64.abs',
+        'f32.neg', 'f64.neg', 'f32.copysign', 'f64.copysign',
+        // integer compare
+        'i32.eq', 'i64.eq', 'i32.ne', 'i64.ne', 'i32.lt_s', 'i64.lt_s',
+        'i32.lt_u', 'i64.lt_u', 'i32.le_s', 'i64.le_s', 'i32.le_u', 'i64.le_u',
+        'i32.gt_s', 'i64.gt_s', 'i32.gt_u', 'i64.gt_u', 'i32.ge_s', 'i64.ge_s',
+        'i32.ge_u', 'i64.ge_u',
+        // floating point compare
+        'f32.eq', 'f64.eq', 'f32.ne', 'f64.ne', 'f32.lt', 'f64.lt',
+        'f32.le', 'f64.le', 'f32.gt', 'f64.gt', 'f32.ge', 'f64.gt',
+        // conversion
+        'i32.wrap/i64', 'i64.extend_s/i32', 'i64.extend_u/i32',
+        'i32.extend_s/8','i32.extend_s/16','i64.extend_s/8','i64.extend_s/16','i64.extend_s/32',
+        'i32.trunc_s/f32', 'i32.trunc_s/f64', 'i64.trunc_s/f32', 'i64.trunc_s/f64',
+        'i32.trunc_u/f32', 'i32.trunc_u/f64', 'i64.trunc_u/f32', 'i64.trunc_u/f64',
+        'f32.demote/f64', 'f64.promote/f32',
+        'f32.convert_s/i32', 'f32.convert_s/i64', 'f64.convert_s/i32', 'f64.convert_s/i64',
+        'f32.convert_u/i32', 'f32.convert_u/i64', 'f64.convert_u/i32', 'f64.convert_u/i64',
+        'i32.reinterpret/f32', 'i64.reinterpret/f64', 'f32.reinterpret/i32', 'f64.reinterpret/i64',
+        // load/store
+        'i32.load', 'i64.load', 'f32.load', 'f64.load',
+        'i32.store', 'i64.store', 'f32.store', 'f64.store',
+        'i32.load8_s', 'i32.load16_s', 'i64.load8_s', 'i64.load16_s', 'i64.load32_s',
+        'i32.load8_u', 'i32.load16_u', 'i64.load8_u', 'i64.load16_u', 'i64.load32_u',
+        'i32.store8', 'i32.store16', 'i64.store8', 'i64.store16', 'i64.store32',
+        // additional memory
+        'grow_memory', 'current_memory'
+

+ 351 - 0
compiler/wasm32/symcpu.pas

@@ -0,0 +1,351 @@
+{
+    Copyright (c) 2014 by Florian Klaempfl
+
+    Symbol table overrides for WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit symcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype,
+  cpubase,
+  aasmdata,
+  symtype,
+  symdef,symsym,
+  cgutils;
+
+type
+  { defs }
+  tcpufiledef = class(tfiledef)
+  end;
+  tcpufiledefclass = class of tcpufiledef;
+
+  tcpuvariantdef = class(tvariantdef)
+  end;
+  tcpuvariantdefclass = class of tcpuvariantdef;
+
+  tcpuformaldef = class(tformaldef)
+  end;
+  tcpuformaldefclass = class of tcpuformaldef;
+
+  tcpuforwarddef = class(tforwarddef)
+  end;
+  tcpuforwarddefclass = class of tcpuforwarddef;
+
+  tcpuundefineddef = class(tundefineddef)
+  end;
+  tcpuundefineddefclass = class of tcpuundefineddef;
+
+  tcpuerrordef = class(terrordef)
+  end;
+  tcpuerrordefclass = class of tcpuerrordef;
+
+  tcpupointerdef = class(tpointerdef)
+  end;
+  tcpupointerdefclass = class of tcpupointerdef;
+
+  tcpurecorddef = class(trecorddef)
+  end;
+  tcpurecorddefclass = class of tcpurecorddef;
+
+  tcpuimplementedinterface = class(timplementedinterface)
+  end;
+  tcpuimplementedinterfaceclass = class of tcpuimplementedinterface;
+
+  tcpuobjectdef = class(tobjectdef)
+  end;
+  tcpuobjectdefclass = class of tcpuobjectdef;
+
+  tcpuclassrefdef = class(tclassrefdef)
+  end;
+  tcpuclassrefdefclass = class of tcpuclassrefdef;
+
+  tcpuarraydef = class(tarraydef)
+  end;
+  tcpuarraydefclass = class of tcpuarraydef;
+
+  tcpuorddef = class(torddef)
+  end;
+  tcpuorddefclass = class of tcpuorddef;
+
+  tcpufloatdef = class(tfloatdef)
+  end;
+  tcpufloatdefclass = class of tcpufloatdef;
+
+  { tcpuprocvardef }
+
+  tcpuprocvardef = class(tprocvardef)
+    function is_pushleftright: boolean; override;
+  end;
+  tcpuprocvardefclass = class of tcpuprocvardef;
+
+  { tcpuprocdef }
+
+  tcpuprocdef = class(tprocdef)
+    frame_pointer_ref,
+    base_pointer_ref: treference;
+    { generated assembler code; used by WebAssembly backend so it can afterwards
+      easily write out all methods grouped per class }
+    exprasmlist  : TAsmList;
+    destructor destroy; override;
+    function create_functype: TWasmFuncType;
+    function is_pushleftright: boolean; override;
+  end;
+  tcpuprocdefclass = class of tcpuprocdef;
+
+  tcpustringdef = class(tstringdef)
+  end;
+  tcpustringdefclass = class of tcpustringdef;
+
+  tcpuenumdef = class(tenumdef)
+  end;
+  tcpuenumdefclass = class of tcpuenumdef;
+
+  tcpusetdef = class(tsetdef)
+  end;
+  tcpusetdefclass = class of tcpusetdef;
+
+  { syms }
+  tcpulabelsym = class(tlabelsym)
+  end;
+  tcpulabelsymclass = class of tcpulabelsym;
+
+  tcpuunitsym = class(tunitsym)
+  end;
+  tcpuunitsymclass = class of tcpuunitsym;
+
+  tcpuprogramparasym = class(tprogramparasym)
+  end;
+  tcpuprogramparasymclass = class(tprogramparasym);
+
+  tcpunamespacesym = class(tnamespacesym)
+  end;
+  tcpunamespacesymclass = class of tcpunamespacesym;
+
+  { tcpuprocsym }
+
+  tcpuprocsym = class(tprocsym)
+  end;
+  tcpuprocsymclass = class of tcpuprocsym;
+
+  tcputypesym = class(ttypesym)
+  end;
+  tcpuypesymclass = class of tcputypesym;
+
+  tcpufieldvarsym = class(tfieldvarsym)
+  end;
+  tcpufieldvarsymclass = class of tcpufieldvarsym;
+
+  tcpulocalvarsym = class(tlocalvarsym)
+  end;
+  tcpulocalvarsymclass = class of tcpulocalvarsym;
+
+  tcpuparavarsym = class(tparavarsym)
+  end;
+  tcpuparavarsymclass = class of tcpuparavarsym;
+
+  tcpustaticvarsym = class(tstaticvarsym)
+  end;
+  tcpustaticvarsymclass = class of tcpustaticvarsym;
+
+  tcpuabsolutevarsym = class(tabsolutevarsym)
+  end;
+  tcpuabsolutevarsymclass = class of tcpuabsolutevarsym;
+
+  tcpupropertysym = class(tpropertysym)
+  end;
+  tcpupropertysymclass = class of tcpupropertysym;
+
+  tcpuconstsym = class(tconstsym)
+  end;
+  tcpuconstsymclass = class of tcpuconstsym;
+
+  tcpuenumsym = class(tenumsym)
+  end;
+  tcpuenumsymclass = class of tcpuenumsym;
+
+  tcpusyssym = class(tsyssym)
+  end;
+  tcpusyssymclass = class of tcpusyssym;
+
+
+const
+  pbestrealtype : ^tdef = @s64floattype;
+
+
+implementation
+
+  uses
+    verbose,cutils,cclasses,globals,cgbase,
+    symconst,symbase,symtable,symcreat,wasmdef,
+    pdecsub,pparautl,paramgr,
+    // high-level code generator is needed to get access to type index for ncall
+    hlcgobj,hlcgcpu,
+    tgcpu
+    ;
+
+
+  {****************************************************************************
+                               tcpuproptertysym
+  ****************************************************************************}
+
+
+
+{****************************************************************************
+                             tcpuenumdef
+****************************************************************************}
+
+
+{****************************************************************************
+                             tcpuprocdef
+****************************************************************************}
+
+
+  destructor tcpuprocdef.destroy;
+    begin
+      exprasmlist.free;
+      inherited destroy;
+    end;
+
+
+  function tcpuprocdef.create_functype: TWasmFuncType;
+    var
+      i: Integer;
+      prm: tcpuparavarsym;
+      bt: TWasmBasicType;
+    begin
+      init_paraloc_info(callerside);
+      result:=TWasmFuncType.Create([],[]);
+      if Assigned(paras) and (paras.Count>0) then
+        begin
+          for i:=0 to paras.Count-1 do
+            begin
+              prm := tcpuparavarsym(paras[i]);
+              case prm.paraloc[callerside].Size of
+                OS_8..OS_32, OS_S8..OS_S32:
+                  result.add_param(wbt_i32);
+                OS_64, OS_S64:
+                  result.add_param(wbt_i64);
+                OS_F32:
+                  result.add_param(wbt_f32);
+                OS_F64:
+                  result.add_param(wbt_f64);
+              else
+                begin
+{$ifdef EXTDEBUG}
+                  Writeln('Unsupported caller side parameter type: ', prm.paraloc[callerside].Size);
+{$endif EXTDEBUG}
+                  // unsupported calleeside parameter type
+                  Internalerror(2019093001);
+                end;
+              end;
+            end;
+        end;
+      if Assigned(returndef) and (returndef.size>0) and
+         not paramanager.ret_in_param(returndef,self) then
+        begin
+          if not defToWasmBasic(returndef,bt) then
+            bt:=wbt_i32;
+          case bt of
+            wbt_i64:
+              result.add_result(wbt_i64);
+            wbt_f32:
+              result.add_result(wbt_f32);
+            wbt_f64:
+              result.add_result(wbt_f64);
+          else
+            result.add_result(wbt_i32);
+          end;
+        end;
+    end;
+
+
+  function tcpuprocdef.is_pushleftright: boolean;
+    begin
+      Result:=true;
+    end;
+
+
+{****************************************************************************
+                             tcpuprocvardef
+****************************************************************************}
+
+    function tcpuprocvardef.is_pushleftright: boolean;
+      begin
+        Result:=true;
+      end;
+
+
+{****************************************************************************
+                             tcpuprocsym
+****************************************************************************}
+
+{****************************************************************************
+                             tcpustaticvarsym
+****************************************************************************}
+
+
+{****************************************************************************
+                             tcpufieldvarsym
+****************************************************************************}
+
+
+initialization
+  { used tdef classes }
+  cfiledef:=tcpufiledef;
+  cvariantdef:=tcpuvariantdef;
+  cformaldef:=tcpuformaldef;
+  cforwarddef:=tcpuforwarddef;
+  cundefineddef:=tcpuundefineddef;
+  cerrordef:=tcpuerrordef;
+  cpointerdef:=tcpupointerdef;
+  crecorddef:=tcpurecorddef;
+  cimplementedinterface:=tcpuimplementedinterface;
+  cobjectdef:=tcpuobjectdef;
+  cclassrefdef:=tcpuclassrefdef;
+  carraydef:=tcpuarraydef;
+  corddef:=tcpuorddef;
+  cfloatdef:=tcpufloatdef;
+  cprocvardef:=tcpuprocvardef;
+  cprocdef:=tcpuprocdef;
+  cstringdef:=tcpustringdef;
+  cenumdef:=tcpuenumdef;
+  csetdef:=tcpusetdef;
+
+  { used tsym classes }
+  clabelsym:=tcpulabelsym;
+  cunitsym:=tcpuunitsym;
+  cprogramparasym:=tcpuprogramparasym;
+  cnamespacesym:=tcpunamespacesym;
+  cprocsym:=tcpuprocsym;
+  ctypesym:=tcputypesym;
+  cfieldvarsym:=tcpufieldvarsym;
+  clocalvarsym:=tcpulocalvarsym;
+  cparavarsym:=tcpuparavarsym;
+  cstaticvarsym:=tcpustaticvarsym;
+  cabsolutevarsym:=tcpuabsolutevarsym;
+  cpropertysym:=tcpupropertysym;
+  cconstsym:=tcpuconstsym;
+  cenumsym:=tcpuenumsym;
+  csyssym:=tcpusyssym;
+end.
+

+ 321 - 0
compiler/wasm32/tgcpu.pas

@@ -0,0 +1,321 @@
+{
+    Copyright (C) 2019 Dmitry Boyarintsev
+
+    This unit handles the temporary variables for the WebAssembly
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit tgcpu;
+
+{$i fpcdefs.inc}
+
+  interface
+
+    uses
+       globtype,
+       aasmdata,
+       cgutils, cpubase,
+       symtype,tgobj;
+
+    type
+
+      { TWasmLocal }
+
+      TWasmLocal = class
+        inuse    : Boolean;
+        noreuse  : Boolean;
+        index    : integer;
+        typ      : TWasmBasicType;
+        next     : TWasmLocal; // next in the same basic type
+        nextseq  : TWasmLocal; // from 0 to max
+        constructor create(atype: TWasmBasicType; aindex: integer);
+      end;
+
+      { TWasmLocalVars }
+
+      TWasmLocalVars = class
+      private
+        last: TWasmLocal; // need public?
+      public
+        locv: array[TWasmBasicType] of TWasmLocal;
+        ordered: array of integer;
+        first: TWasmLocal; // first in sequence
+        varindex: integer;
+        constructor Create(astartindex: Integer = 0);
+        destructor Destroy; override;
+        function alloc(bt: TWasmBasicType): integer;
+        function allocnoreuse(bt: TWasmBasicType): integer;
+        procedure dealloc(bt: TWasmBasicType; index: integer);
+        procedure dealloc(index: integer);
+      end;
+
+       { ttgwasm }
+
+       ttgwasm = class(ttgobj)
+        private
+         procedure updateFirstTemp;
+
+         procedure allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
+         procedure allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
+         procedure LocalVarToRef(idx: integer; size: Integer; out ref: treference);
+        public
+         localvars: TWasmLocalVars;
+
+         constructor create; override;
+         destructor destroy; override;
+         procedure setfirsttemp(l : asizeint); override;
+         procedure gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference); override;
+         procedure gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference); override;
+         procedure ungettemp(list: TAsmList; const ref : treference); override;
+         procedure allocframepointer(list: TAsmList; out ref: treference);
+         procedure allocbasepointer(list: TAsmList; out ref: treference);
+       end;
+
+    function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
+
+  implementation
+
+    uses
+       verbose,
+       cgbase,
+       symconst,symtable,symdef,symsym,symcpu,defutil,
+       aasmbase,aasmcpu,
+       hlcgobj,hlcgcpu, procinfo;
+
+    function defToWasmBasic(def: tdef; var wbt: TWasmBasicType): Boolean;
+    begin
+      Result := assigned(def);
+      if not Result then Exit;
+
+      if is_pointer(def) then
+        wbt := wbt_i32 // wasm32
+      else if is_currency(def) then
+        wbt := wbt_i64
+      else if is_ordinal(def) then begin
+        if is_64bit(def) then wbt := wbt_i64
+        else wbt := wbt_i32;
+      end else if is_real(def) then begin
+        if is_single(def) then wbt := wbt_f32
+        else wbt := wbt_f64; // real/double/extended
+      end else
+        Result := false;
+    end;
+
+        { TWasmLocal }
+
+                constructor TWasmLocal.create(atype: TWasmBasicType;
+                  aindex: integer);
+        begin
+          typ:=atype;
+          index:=aindex;
+        end;
+
+    { TWasmLocalVars }
+
+        constructor TWasmLocalVars.Create(astartindex: Integer = 0);
+          begin
+            inherited Create;
+            varindex := astartindex;
+          end;
+
+        destructor TWasmLocalVars.Destroy;
+          var
+            t : TWasmLocal;
+            n : TWasmLocal;
+          begin
+            t := first;
+            while Assigned(t) do
+              begin
+                n:=t;
+                t:=t.nextseq;
+                n.Free;
+              end;
+            inherited Destroy;
+          end;
+
+
+    { ttgwasm }
+
+    procedure ttgwasm.updateFirstTemp;
+    begin
+      firsttemp := localvars.varindex;
+      if lasttemp<firsttemp then lasttemp := firsttemp;
+    end;
+
+    constructor ttgwasm.create;
+      begin
+        inherited create;
+        localvars:=TWasmLocalVars.Create;
+      end;
+
+    destructor ttgwasm.destroy;
+      begin
+        localvars.Free;
+        inherited destroy;
+      end;
+
+    procedure ttgwasm.setfirsttemp(l: asizeint);
+      begin
+        firsttemp:=l;
+        lasttemp:=l;
+        localvars.varindex := l; //?
+      end;
+
+
+    procedure ttgwasm.gethltemp(list: TAsmList; def: tdef; forcesize: asizeint; temptype: ttemptype; out ref: treference);
+      var
+        wbt: TWasmBasicType;
+      begin
+        if temptype=tt_regallocator then
+          begin
+            if Assigned(def) and defToWasmBasic(def, wbt) then
+              allocLocalVarToRef(wbt, ref)
+            else
+              internalerror(2020121801);
+          end
+        else
+          inherited;
+      end;
+
+    procedure ttgwasm.gethltempmanaged(list: TAsmList; def: tdef; temptype: ttemptype; out ref: treference);
+      begin
+        inherited;
+      end;
+
+    procedure ttgwasm.ungettemp(list: TAsmList; const ref: treference);
+      begin
+        if ref.base=NR_LOCAL_STACK_POINTER_REG then
+          localvars.dealloc(ref.offset)
+        else
+          inherited;
+      end;
+
+    procedure ttgwasm.allocframepointer(list: TAsmList; out ref: treference);
+      begin
+        allocLocalVarNoReuseToRef(wbt_i32,ref);
+      end;
+
+    procedure ttgwasm.allocbasepointer(list: TAsmList; out ref: treference);
+      begin
+        allocLocalVarNoReuseToRef(wbt_i32,ref);
+      end;
+
+    procedure ttgwasm.allocLocalVarToRef(wbt: TWasmBasicType; out ref: treference);
+      var
+        idx : integer;
+      begin
+        idx := localvars.alloc(wbt);
+        localVarToRef(idx, 1, ref);
+      end;
+
+    procedure ttgwasm.allocLocalVarNoReuseToRef(wbt: TWasmBasicType; out ref: treference);
+      var
+        idx : integer;
+      begin
+        idx := localvars.allocnoreuse(wbt);
+        localVarToRef(idx, 1, ref);
+      end;
+
+    procedure ttgwasm.localVarToRef(idx: integer; size: integer; out ref: treference);
+      begin
+        reference_reset_base(ref,NR_LOCAL_STACK_POINTER_REG,idx,ctempposinvalid,size,[]);
+        updateFirstTemp;
+      end;
+
+    function TWasmLocalVars.alloc(bt: TWasmBasicType): integer;
+      var
+        i : integer;
+        lc : TWasmLocal;
+        t  : TWasmLocal;
+      begin
+        lc := locv[bt];
+        t := nil;
+        while Assigned(lc) and ((lc.inuse) or (lc.noreuse)) do begin
+          t := lc;
+          lc := lc.next;
+        end;
+        if Assigned(lc) then begin
+          lc.inuse := true;
+        end else begin
+          lc := TWasmLocal.Create(bt, varindex);
+          if Assigned(t)
+            then t.next := lc
+            else locv[bt]:=lc;
+          lc.inuse:=true;
+          inc(varindex);
+
+          if Assigned(last) then last.nextseq := lc;
+          if not Assigned(first) then first := lc;
+          last := lc;
+        end;
+        alloc := lc.index;
+
+      end;
+
+    function TWasmLocalVars.allocnoreuse(bt: TWasmBasicType): integer;
+      var
+        i : integer;
+        lc : TWasmLocal;
+        t  : TWasmLocal;
+      begin
+        lc := locv[bt];
+        t := nil;
+        while Assigned(lc) do
+          begin
+            t := lc;
+            lc := lc.next;
+          end;
+        lc := TWasmLocal.Create(bt, varindex);
+        if Assigned(t) then
+          t.next := lc
+        else
+          locv[bt]:=lc;
+        lc.inuse:=true;
+        lc.noreuse:=true;
+        inc(varindex);
+        if Assigned(last) then
+          last.nextseq := lc;
+        if not Assigned(first) then
+          first := lc;
+        last := lc;
+        allocnoreuse := lc.index;
+      end;
+
+    procedure TWasmLocalVars.dealloc(bt: TWasmBasicType; index: integer);
+      var
+        lc : TWasmLocal;
+      begin
+        lc := locv[bt];
+        while Assigned(lc) and (lc.index <> index) do
+          lc := lc.next;
+        if Assigned(lc) then lc.inuse := false;
+      end;
+
+    procedure TWasmLocalVars.dealloc(index: integer);
+      var
+        lc : TWasmLocal;
+      begin
+        lc := first;
+        while Assigned(lc) and (lc.index <> index) do
+          lc := lc.nextseq;
+        if Assigned(lc) then lc.inuse := false;
+      end;
+
+
+initialization
+  tgobjclass:=ttgwasm;
+end.

+ 45 - 0
compiler/wasm32/tripletcpu.pas

@@ -0,0 +1,45 @@
+{
+    Copyright (c) 2020 by Jonas Maebe
+
+    Construct the cpu part of the triplet
+
+    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., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+ ****************************************************************************
+}
+unit tripletcpu;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  globtype;
+
+function tripletcpustr(tripletstyle: ttripletstyle): ansistring;
+
+implementation
+
+uses
+  globals, cpuinfo;
+
+function tripletcpustr(tripletstyle: ttripletstyle): ansistring;
+  begin
+    result:='wasm32';
+  end;
+
+
+end.
+

+ 155 - 0
compiler/wasm32/wasmdef.pas

@@ -0,0 +1,155 @@
+unit wasmdef;
+
+{$i fpcdefs.inc}
+
+interface
+
+uses
+  symtype, symsym, symdef, symconst, constexp
+  ,defutil, procdefutil, cclasses;
+
+type
+
+    { TWasmTypeEntry }
+
+    TWasmTypeEntry = class(Tobject)
+      name : string; // always empty
+      idx  : integer;
+      constructor Create(aidx: integer; aname: string);
+    end;
+
+    { TWasmProcTypeLookup }
+
+    TWasmProcTypeLookup = class(TObject)
+      list: TFPHashObjectList;
+      idx: integer;
+      constructor Create(astartIndex: integer = 0);
+      destructor Destroy; override;
+      function GetTypeIndex(const typecode: string): Integer;
+    end;
+
+
+    // encodes procedure definition to a code used for the proc type lookup
+    // it's case-sensitive!!!
+    // i = i32, I = i64, f = f32, F = f32
+    function WasmGetTypeCodeForDef(def: tdef; var ch: char): Boolean;
+
+    function WasmGetTypeCode(aprocdef: tabstractprocdef): string;
+
+    { returns whether a def always resides in memory,
+      rather than in wasm local variables...) }
+    function wasmAlwayInMem(def: tdef): boolean;
+
+    function get_para_push_size(def: tdef): tdef;
+
+implementation
+
+  function get_para_push_size(def: tdef): tdef;
+    begin
+      result:=def;
+      if def.typ=orddef then
+        case torddef(def).ordtype of
+          u8bit,uchar:
+            if torddef(def).high>127 then
+              result:=s8inttype;
+          u16bit:
+            begin
+              if torddef(def).high>32767 then
+                result:=s16inttype;
+            end
+          else
+            ;
+        end;
+    end;
+
+  function wasmAlwayInMem(def: tdef): boolean;
+    begin
+      case def.typ of
+        arraydef,
+        filedef,
+        recorddef,
+        objectdef,
+        stringdef:
+          result:=true;
+        else
+          result:=false;
+      end;
+    end;
+
+  function WasmGetTypeCodeForDef(def: tdef; var ch: char): Boolean;
+  begin
+    Result := assigned(def);
+    if not Result then Exit;
+
+    case def.typ of
+      floatdef:
+        if def.size = 4 then ch :='f'
+        else ch :='F';
+      orddef:
+        if def.size = 8 then ch :='I'
+        else ch := 'i';
+      // todo: set can be bigger
+    else
+      ch:='i'; // by address
+    end;
+  end;
+
+  function WasmGetTypeCode(aprocdef: tabstractprocdef): string;
+    var
+      ch : char;
+      i  : integer;
+    begin
+      Result := '';
+      if not Assigned(aprocdef) then exit;
+
+      for i:=0 to aprocdef.paras.Count-1 do begin
+        WasmGetTypeCodeForDef( tparavarsym(aprocdef.paras[i]).paraloc[callerside].Def, ch);
+        result:=result+ch;
+      end;
+
+      if assigned(aprocdef) then begin
+        result:=result+':';
+        WasmGetTypeCodeForDef(aprocdef.returndef, ch);
+        result:=result+ch;
+      end;
+
+    end;
+
+    { TWasmTypeEntry }
+
+     constructor TWasmTypeEntry.Create(aidx: integer; aname: string);
+      begin
+        idx := aidx;
+        name := aname;
+      end;
+
+  { TWasmProcTypeLookup }
+
+    constructor TWasmProcTypeLookup.Create(astartIndex: integer = 0);
+      begin
+        inherited Create;
+        list := TFPHashObjectList.Create(true);
+        idx := astartIndex;
+      end;
+
+    destructor TWasmProcTypeLookup.Destroy;
+      begin
+        list.Free;
+        inherited Destroy;
+      end;
+
+    function TWasmProcTypeLookup.GetTypeIndex(const typecode: string): Integer;
+      var
+        en : TWasmTypeEntry;
+      begin
+        en := TWasmTypeEntry(list.Find(typecode));
+        if not Assigned(en) then begin
+          en := TWasmTypeEntry.Create(idx, ''); // no need to copy
+          inc(idx);
+          list.Add(typecode, en);
+        end;
+        Result := en.idx;
+      end;
+
+
+end.

+ 23 - 0
compiler/wasm32/wasmreg.dat

@@ -0,0 +1,23 @@
+;
+; WebAssembly registers
+;
+; layout
+; <name>,<type>,<subtype>,<value>,<stdname>
+;
+; WebAssembly does not have any registers, since it is stack-based.
+; We do define a few artificial registers to make integration
+; with the rest of the compiler easier though.
+
+; general/int registers
+NO,$00,$00,$00,INVALID
+; used as base register in reference when referring to the top
+; of the evaluation stack (offset = offset on the evaluation
+; stack)
+R0,$01,$00,$00,evalstacktopptr
+; for addressing locals ("stack pointer")
+R1,$01,$00,$01,localsstackptr
+; generic fake evaluation stack register for use by the register allocator
+R2,$01,$00,$02,evalstacktop
+; fake register, representing the local frame pointer. Used for accessing
+; address-taken local variables on the linear stack: (localframeptr+offset).
+R3,$01,$00,$03,localframeptr

+ 22 - 4
installer/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -685,7 +685,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override CLEAN_UNITS+=scroll insthelp
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override CLEAN_UNITS+=scroll insthelp
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override CLEAN_UNITS+=scroll insthelp
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -2907,7 +2910,22 @@ REQUIRE_PACKAGES_CHM=1
 REQUIRE_PACKAGES_REGEXPR=1
 REQUIRE_PACKAGES_IDE=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_RTL-CONSOLE=1
+REQUIRE_PACKAGES_FV=1
+REQUIRE_PACKAGES_UNZIP=1
+REQUIRE_PACKAGES_RTL-EXTRA=1
+REQUIRE_PACKAGES_CHM=1
+REQUIRE_PACKAGES_REGEXPR=1
+REQUIRE_PACKAGES_IDE=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -3741,7 +3759,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 6 - 3
packages/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1417,7 +1417,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 REQUIRE_PACKAGES_RTL=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -1601,7 +1604,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/a52/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/ami-extra/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/amunits/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/arosunits/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/aspell/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/bfd/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/bzip2/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 1 - 1
packages/bzip2/fpmake.pp

@@ -28,7 +28,7 @@ begin
     P.Email := '';
     P.Description := 'BZip2 decompression unit.';
     P.NeedLibC:= true;
-    P.OSes := P.OSes - [embedded,nativent,msdos,win16,macosclassic,palmos,zxspectrum,msxdos,amstradcpc,sinclairql];
+    P.OSes := P.OSes - [embedded,nativent,msdos,win16,macosclassic,palmos,zxspectrum,msxdos,amstradcpc,sinclairql,wasi];
     if Defaults.CPU=jvm then
       P.OSes := P.OSes - [java,android];
 

+ 11 - 3
packages/cairo/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/cdrom/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 24 - 4
packages/cdrom/examples/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -620,7 +620,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_PROGRAMS+=getdiscid showcds
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_PROGRAMS+=getdiscid showcds
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_PROGRAMS+=getdiscid showcds
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -909,10 +912,18 @@ else
 ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),)
 FPCMAKE_CROSSGCCOPT=-mabi=32
 else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv64),)
+FPCMAKE_CROSSGCCOPT=-mabi=lp64
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv32),)
+FPCMAKE_CROSSGCCOPT=-mabi=ilp32
+else
 FPCMAKE_CROSSGCCOPT=-m32
 endif
 endif
 endif
+endif
+endif
 FPCMAKEGCCLIBDIR:=$(shell dirname `gcc $(FPCMAKE_CROSSGCCOPT) -print-libgcc-file-name`)
 endif
 endif
@@ -2233,7 +2244,16 @@ REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 REQUIRE_PACKAGES_CDROM=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_CDROM=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2723,7 +2743,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/chm/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 1 - 1
packages/chm/fpmake.pp

@@ -25,7 +25,7 @@ begin
     P.Email := '';
     P.Description := 'Standalone CHM reader and writer library';
     P.NeedLibC:= false;
-    P.OSes := P.OSes - [embedded,nativent,msdos,win16,macosclassic,palmos,atari,zxspectrum,msxdos,amstradcpc,watcom,sinclairql];
+    P.OSes := P.OSes - [embedded,nativent,msdos,win16,macosclassic,palmos,atari,zxspectrum,msxdos,amstradcpc,watcom,sinclairql,wasi];
     if Defaults.CPU=jvm then
       P.OSes := P.OSes - [java,android];
 

+ 11 - 3
packages/cocoaint/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/dblib/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 11 - 3
packages/dbus/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -1848,7 +1848,15 @@ REQUIRE_PACKAGES_HASH=1
 REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2287,7 +2295,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

+ 24 - 4
packages/dbus/examples/Makefile

@@ -2,7 +2,7 @@
 # Don't edit, this file is generated by FPCMake Version 2.0.0
 #
 default: all
-MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm-wasm sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
+MAKEFILETARGETS=i386-linux i386-go32v2 i386-win32 i386-os2 i386-freebsd i386-beos i386-haiku i386-netbsd i386-solaris i386-netware i386-openbsd i386-wdosx i386-darwin i386-emx i386-watcom i386-netwlibc i386-wince i386-embedded i386-symbian i386-nativent i386-iphonesim i386-android i386-aros m68k-linux m68k-netbsd m68k-amiga m68k-atari m68k-palmos m68k-macosclassic m68k-embedded m68k-sinclairql powerpc-linux powerpc-netbsd powerpc-amiga powerpc-macosclassic powerpc-darwin powerpc-morphos powerpc-embedded powerpc-wii powerpc-aix sparc-linux sparc-netbsd sparc-solaris sparc-embedded x86_64-linux x86_64-freebsd x86_64-haiku x86_64-netbsd x86_64-solaris x86_64-openbsd x86_64-darwin x86_64-win64 x86_64-embedded x86_64-iphonesim x86_64-android x86_64-aros x86_64-dragonfly arm-linux arm-netbsd arm-palmos arm-wince arm-gba arm-nds arm-embedded arm-symbian arm-android arm-aros arm-freertos arm-ios powerpc64-linux powerpc64-darwin powerpc64-embedded powerpc64-aix avr-embedded armeb-linux armeb-embedded mips-linux mipsel-linux mipsel-embedded mipsel-android mips64el-linux jvm-java jvm-android i8086-embedded i8086-msdos i8086-win16 aarch64-linux aarch64-darwin aarch64-win64 aarch64-android aarch64-ios wasm32-embedded wasm32-wasi sparc64-linux riscv32-linux riscv32-embedded riscv64-linux riscv64-embedded xtensa-linux xtensa-embedded xtensa-freertos z80-embedded z80-zxspectrum z80-msxdos z80-amstradcpc
 BSDs = freebsd netbsd openbsd darwin dragonfly
 UNIXs = linux $(BSDs) solaris qnx haiku aix
 LIMIT83fs = go32v2 os2 emx watcom msdos win16 atari
@@ -620,7 +620,10 @@ endif
 ifeq ($(FULL_TARGET),aarch64-ios)
 override TARGET_PROGRAMS+=busexample
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+override TARGET_PROGRAMS+=busexample
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 override TARGET_PROGRAMS+=busexample
 endif
 ifeq ($(FULL_TARGET),sparc64-linux)
@@ -909,10 +912,18 @@ else
 ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),mips mipsel),)
 FPCMAKE_CROSSGCCOPT=-mabi=32
 else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv64),)
+FPCMAKE_CROSSGCCOPT=-mabi=lp64
+else
+ifneq ($(findstring $(FPCFPMAKE_CPU_OPT),riscv32),)
+FPCMAKE_CROSSGCCOPT=-mabi=ilp32
+else
 FPCMAKE_CROSSGCCOPT=-m32
 endif
 endif
 endif
+endif
+endif
 FPCMAKEGCCLIBDIR:=$(shell dirname `gcc $(FPCMAKE_CROSSGCCOPT) -print-libgcc-file-name`)
 endif
 endif
@@ -2233,7 +2244,16 @@ REQUIRE_PACKAGES_LIBTAR=1
 REQUIRE_PACKAGES_FPMKUNIT=1
 REQUIRE_PACKAGES_DBUS=1
 endif
-ifeq ($(FULL_TARGET),wasm-wasm)
+ifeq ($(FULL_TARGET),wasm32-embedded)
+REQUIRE_PACKAGES_RTL=1
+REQUIRE_PACKAGES_PASZLIB=1
+REQUIRE_PACKAGES_FCL-PROCESS=1
+REQUIRE_PACKAGES_HASH=1
+REQUIRE_PACKAGES_LIBTAR=1
+REQUIRE_PACKAGES_FPMKUNIT=1
+REQUIRE_PACKAGES_DBUS=1
+endif
+ifeq ($(FULL_TARGET),wasm32-wasi)
 REQUIRE_PACKAGES_RTL=1
 REQUIRE_PACKAGES_PASZLIB=1
 REQUIRE_PACKAGES_FCL-PROCESS=1
@@ -2723,7 +2743,7 @@ ifdef CREATESHARED
 override FPCOPT+=-Cg
 endif
 ifneq ($(findstring $(OS_TARGET),dragonfly freebsd openbsd netbsd linux solaris),)
-ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel),)
+ifneq ($(findstring $(CPU_TARGET),x86_64 mips mipsel riscv64),)
 override FPCOPT+=-Cg
 endif
 endif

Энэ ялгаанд хэт олон файл өөрчлөгдсөн тул зарим файлыг харуулаагүй болно