aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorZac Pierson <zacpiersonhehe@gmail.com>2017-03-21 14:16:42 -0500
committerZac Pierson <zacpiersonhehe@gmail.com>2017-03-21 14:16:42 -0500
commitc7bb861d3ca19f1a81043b8ad1e014ad10aa225f (patch)
tree56719cc445ebe06b4d2e486e2da3c17c57e216c2
parentd890731716ea96fd69d7543c7d7225702cbd7268 (diff)
parent188b290dd50664aa8a89955ac2ab7dbebf7a653d (diff)
Merge https://github.com/gingerBill/Odin
"Fixed" a proc overload bug. Still needs a *real* fix.
-rw-r--r--.gitignore7
-rw-r--r--README.md4
-rw-r--r--bin/CODE_OWNERS.TXT200
-rw-r--r--bin/CREDITS.TXT467
-rw-r--r--bin/LICENSE.TXT70
-rw-r--r--bin/llc.exebin25395712 -> 0 bytes
-rw-r--r--bin/lli.exebin12783616 -> 0 bytes
-rw-r--r--bin/opt.exebin26361344 -> 0 bytes
-rw-r--r--build.bat16
-rw-r--r--code/demo.odin302
-rw-r--r--core/_preload.odin37
-rw-r--r--core/fmt.odin101
-rw-r--r--core/math.odin67
-rw-r--r--core/mem.odin41
-rw-r--r--core/os_windows.odin90
-rw-r--r--core/strconv.odin50
-rw-r--r--core/sync.odin2
-rw-r--r--core/sys/wgl.odin50
-rw-r--r--core/sys/windows.odin268
-rw-r--r--misc/compile_time_execution_problems.md (renamed from compile_time_execution_problems.md)0
-rw-r--r--misc/lib_maker_clang.bat11
-rw-r--r--misc/libs.txt (renamed from libs.txt)0
-rw-r--r--misc/logo-slim.png (renamed from logo-slim.png)bin251710 -> 251710 bytes
-rw-r--r--misc/roadmap.md (renamed from roadmap.md)0
-rw-r--r--misc/todo.md (renamed from todo.md)0
-rw-r--r--run.bat4
-rw-r--r--src/array.c10
-rw-r--r--src/build_settings.c2
-rw-r--r--src/check_decl.c60
-rw-r--r--src/check_expr.c305
-rw-r--r--src/check_stmt.c229
-rw-r--r--src/checker.c88
-rw-r--r--src/entity.c27
-rw-r--r--src/exact_value.c98
-rw-r--r--src/gb/gb.h438
-rw-r--r--src/ir.c1156
-rw-r--r--src/ir_print.c20
-rw-r--r--src/main.c9
-rw-r--r--src/parser.c222
-rw-r--r--src/ssa.c2269
-rw-r--r--src/ssa_op.c277
-rw-r--r--src/tokenizer.c36
-rw-r--r--src/types.c44
-rw-r--r--src/unicode.c1
-rw-r--r--src/utf8proc/utf8proc.c110
-rw-r--r--src/utf8proc/utf8proc.h104
-rw-r--r--src/utf8proc/utf8proc_data.c25
47 files changed, 4900 insertions, 2417 deletions
diff --git a/.gitignore b/.gitignore
index 27a4b9fa7..9286b374c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -254,10 +254,9 @@ paket-files/
# - Windows
*.sln
-!misc/llvm-bim/lli.exe
-!misc/llvm-bim/opt.exe
-builds
+builds/
+bin/
# - Linux/MacOS
odin
-odin.dSYM
+odin.dSYM \ No newline at end of file
diff --git a/README.md b/README.md
index e63772503..995f5eb38 100644
--- a/README.md
+++ b/README.md
@@ -1,4 +1,4 @@
-<img src="logo-slim.png" alt="Odin logo" height="74">
+<img src="misc/logo-slim.png" alt="Odin logo" height="74">
# The Odin Programming Language
@@ -25,7 +25,7 @@ The Odin programming language is fast, concise, readable, pragmatic and open sou
- Windows
* x86-64
* MSVC 2015 installed (C99 support)
- * LLVM installed
+ * [LLVM binaries](https://github.com/gingerBill/Odin/releases/tag/llvm-4.0-windows) for `opt.exe` and `llc.exe`
* Requires MSVC's link.exe as the linker
* run `vcvarsall.bat` to setup the path
diff --git a/bin/CODE_OWNERS.TXT b/bin/CODE_OWNERS.TXT
deleted file mode 100644
index da0e7a471..000000000
--- a/bin/CODE_OWNERS.TXT
+++ /dev/null
@@ -1,200 +0,0 @@
-This file is a list of the people responsible for ensuring that patches for a
-particular part of LLVM are reviewed, either by themself or by someone else.
-They are also the gatekeepers for their part of LLVM, with the final word on
-what goes in or not.
-
-The list is sorted by surname and formatted to allow easy grepping and
-beautification by scripts. The fields are: name (N), email (E), web-address
-(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
-(S). Each entry should contain at least the (N), (E) and (D) fields.
-
-N: Joe Abbey
-E: jabbey@arxan.com
-D: LLVM Bitcode (lib/Bitcode/* include/llvm/Bitcode/*)
-
-N: Owen Anderson
-E: resistor@mac.com
-D: SelectionDAG (lib/CodeGen/SelectionDAG/*)
-
-N: Rafael Avila de Espindola
-E: rafael.espindola@gmail.com
-D: Gold plugin (tools/gold/*)
-
-N: Justin Bogner
-E: mail@justinbogner.com
-D: InstrProfiling and related parts of ProfileData
-
-N: Chandler Carruth
-E: chandlerc@gmail.com
-E: chandlerc@google.com
-D: Config, ADT, Support, inlining & related passes, SROA/mem2reg & related passes, CMake, library layering
-
-N: Evan Cheng
-E: evan.cheng@apple.com
-D: parts of code generator not covered by someone else
-
-N: Eric Christopher
-E: echristo@gmail.com
-D: Debug Information, autotools/configure/make build, inline assembly
-
-N: Greg Clayton
-E: gclayton@apple.com
-D: LLDB
-
-N: Marshall Clow
-E: mclow.lists@gmail.com
-D: libc++
-
-N: Peter Collingbourne
-E: peter@pcc.me.uk
-D: llgo
-
-N: Quentin Colombet
-E: qcolombet@apple.com
-D: Register allocators
-
-N: Duncan P. N. Exon Smith
-E: dexonsmith@apple.com
-D: Branch weights and BlockFrequencyInfo
-
-N: Hal Finkel
-E: hfinkel@anl.gov
-D: BBVectorize, the loop reroller, alias analysis and the PowerPC target
-
-N: Dan Gohman
-E: sunfish@mozilla.com
-D: WebAssembly Backend (lib/Target/WebAssembly/*)
-
-N: Renato Golin
-E: renato.golin@linaro.org
-D: ARM Linux support
-
-N: Venkatraman Govindaraju
-E: venkatra@cs.wisc.edu
-D: Sparc Backend (lib/Target/Sparc/*)
-
-N: Tobias Grosser
-E: tobias@grosser.es
-D: Polly
-
-N: James Grosbach
-E: grosbach@apple.com
-D: MC layer
-
-N: Justin Holewinski
-E: jholewinski@nvidia.com
-D: NVPTX Target (lib/Target/NVPTX/*)
-
-N: Lang Hames
-E: lhames@gmail.com
-D: MCJIT, RuntimeDyld and JIT event listeners
-
-N: Galina Kistanova
-E: gkistanova@gmail.com
-D: LLVM Buildbot
-
-N: Anton Korobeynikov
-E: anton@korobeynikov.info
-D: Exception handling, Windows codegen, ARM EABI
-
-N: Benjamin Kramer
-E: benny.kra@gmail.com
-D: DWARF Parser
-
-N: Sergei Larin
-E: slarin@codeaurora.org
-D: VLIW Instruction Scheduling, Packetization
-
-N: Chris Lattner
-E: sabre@nondot.org
-W: http://nondot.org/~sabre/
-D: Everything not covered by someone else
-
-N: David Majnemer
-E: david.majnemer@gmail.com
-D: IR Constant Folder, InstCombine
-
-N: Dylan McKay
-E: dylanmckay34@gmail.com
-D: AVR Backend
-
-N: Tim Northover
-E: t.p.northover@gmail.com
-D: AArch64 backend, misc ARM backend
-
-N: Diego Novillo
-E: dnovillo@google.com
-D: SampleProfile and related parts of ProfileData
-
-N: Jakob Olesen
-E: stoklund@2pi.dk
-D: TableGen
-
-N: Richard Osborne
-E: richard@xmos.com
-D: XCore Backend
-
-N: Krzysztof Parzyszek
-E: kparzysz@codeaurora.org
-D: Hexagon Backend
-
-N: Paul Robinson
-E: paul_robinson@playstation.sony.com
-D: Sony PlayStation®4 support
-
-N: Chad Rosier
-E: mcrosier@codeaurora.org
-D: Fast-Isel
-
-N: Nadav Rotem
-E: nrotem@apple.com
-D: X86 Backend, Loop Vectorizer
-
-N: Daniel Sanders
-E: daniel.sanders@imgtec.com
-D: MIPS Backend (lib/Target/Mips/*)
-
-N: Duncan Sands
-E: baldrick@free.fr
-D: DragonEgg
-
-N: Kostya Serebryany
-E: kcc@google.com
-D: AddressSanitizer, ThreadSanitizer (LLVM parts)
-
-N: Michael Spencer
-E: bigcheesegs@gmail.com
-D: Windows parts of Support, Object, ar, nm, objdump, ranlib, size
-
-N: Alexei Starovoitov
-E: alexei.starovoitov@gmail.com
-D: BPF backend
-
-N: Tom Stellard
-E: thomas.stellard@amd.com
-E: mesa-dev@lists.freedesktop.org
-D: Release manager for the 3.5 and 3.6 branches, R600 Backend, libclc
-
-N: Evgeniy Stepanov
-E: eugenis@google.com
-D: MemorySanitizer (LLVM part)
-
-N: Andrew Trick
-E: atrick@apple.com
-D: IndVar Simplify, Loop Strength Reduction, Instruction Scheduling
-
-N: Ulrich Weigand
-E: uweigand@de.ibm.com
-D: SystemZ Backend
-
-N: Bill Wendling
-E: isanbard@gmail.com
-D: libLTO, IR Linker
-
-N: Peter Zotov
-E: whitequark@whitequark.org
-D: OCaml bindings
-
-N: Andrey Churbanov
-E: andrey.churbanov@intel.com
-D: OpenMP runtime library
diff --git a/bin/CREDITS.TXT b/bin/CREDITS.TXT
deleted file mode 100644
index da1fb010e..000000000
--- a/bin/CREDITS.TXT
+++ /dev/null
@@ -1,467 +0,0 @@
-This file is a partial list of people who have contributed to the LLVM
-project. If you have contributed a patch or made some other contribution to
-LLVM, please submit a patch to this file to add yourself, and it will be
-done!
-
-The list is sorted by surname and formatted to allow easy grepping and
-beautification by scripts. The fields are: name (N), email (E), web-address
-(W), PGP key ID and fingerprint (P), description (D), snail-mail address
-(S), and (I) IRC handle.
-
-
-N: Vikram Adve
-E: vadve@cs.uiuc.edu
-W: http://www.cs.uiuc.edu/~vadve/
-D: The Sparc64 backend, provider of much wisdom, and motivator for LLVM
-
-N: Owen Anderson
-E: resistor@mac.com
-D: LCSSA pass and related LoopUnswitch work
-D: GVNPRE pass, DataLayout refactoring, random improvements
-
-N: Henrik Bach
-D: MingW Win32 API portability layer
-
-N: Aaron Ballman
-E: aaron@aaronballman.com
-D: __declspec attributes, Windows support, general bug fixing
-
-N: Nate Begeman
-E: natebegeman@mac.com
-D: PowerPC backend developer
-D: Target-independent code generator and analysis improvements
-
-N: Daniel Berlin
-E: dberlin@dberlin.org
-D: ET-Forest implementation.
-D: Sparse bitmap
-
-N: David Blaikie
-E: dblaikie@gmail.com
-D: General bug fixing/fit & finish, mostly in Clang
-
-N: Neil Booth
-E: neil@daikokuya.co.uk
-D: APFloat implementation.
-
-N: Misha Brukman
-E: brukman+llvm@uiuc.edu
-W: http://misha.brukman.net
-D: Portions of X86 and Sparc JIT compilers, PowerPC backend
-D: Incremental bitcode loader
-
-N: Cameron Buschardt
-E: buschard@uiuc.edu
-D: The `mem2reg' pass - promotes values stored in memory to registers
-
-N: Brendon Cahoon
-E: bcahoon@codeaurora.org
-D: Loop unrolling with run-time trip counts.
-
-N: Chandler Carruth
-E: chandlerc@gmail.com
-E: chandlerc@google.com
-D: Hashing algorithms and interfaces
-D: Inline cost analysis
-D: Machine block placement pass
-D: SROA
-
-N: Casey Carter
-E: ccarter@uiuc.edu
-D: Fixes to the Reassociation pass, various improvement patches
-
-N: Evan Cheng
-E: evan.cheng@apple.com
-D: ARM and X86 backends
-D: Instruction scheduler improvements
-D: Register allocator improvements
-D: Loop optimizer improvements
-D: Target-independent code generator improvements
-
-N: Dan Villiom Podlaski Christiansen
-E: danchr@gmail.com
-E: danchr@cs.au.dk
-W: http://villiom.dk
-D: LLVM Makefile improvements
-D: Clang diagnostic & driver tweaks
-S: Aarhus, Denmark
-
-N: Jeff Cohen
-E: jeffc@jolt-lang.org
-W: http://jolt-lang.org
-D: Native Win32 API portability layer
-
-N: John T. Criswell
-E: criswell@uiuc.edu
-D: Original Autoconf support, documentation improvements, bug fixes
-
-N: Anshuman Dasgupta
-E: adasgupt@codeaurora.org
-D: Deterministic finite automaton based infrastructure for VLIW packetization
-
-N: Stefanus Du Toit
-E: stefanus.du.toit@intel.com
-D: Bug fixes and minor improvements
-
-N: Rafael Avila de Espindola
-E: rafael.espindola@gmail.com
-D: The ARM backend
-
-N: Dave Estes
-E: cestes@codeaurora.org
-D: AArch64 machine description for Cortex-A53
-
-N: Alkis Evlogimenos
-E: alkis@evlogimenos.com
-D: Linear scan register allocator, many codegen improvements, Java frontend
-
-N: Hal Finkel
-E: hfinkel@anl.gov
-D: Basic-block autovectorization, PowerPC backend improvements
-
-N: Eric Fiselier
-E: eric@efcs.ca
-D: LIT patches and documentation.
-
-N: Ryan Flynn
-E: pizza@parseerror.com
-D: Miscellaneous bug fixes
-
-N: Brian Gaeke
-E: gaeke@uiuc.edu
-W: http://www.students.uiuc.edu/~gaeke/
-D: Portions of X86 static and JIT compilers; initial SparcV8 backend
-D: Dynamic trace optimizer
-D: FreeBSD/X86 compatibility fixes, the llvm-nm tool
-
-N: Nicolas Geoffray
-E: nicolas.geoffray@lip6.fr
-W: http://www-src.lip6.fr/homepages/Nicolas.Geoffray/
-D: PPC backend fixes for Linux
-
-N: Louis Gerbarg
-E: lgg@apple.com
-D: Portions of the PowerPC backend
-
-N: Saem Ghani
-E: saemghani@gmail.com
-D: Callgraph class cleanups
-
-N: Mikhail Glushenkov
-E: foldr@codedgers.com
-D: Author of llvmc2
-
-N: Dan Gohman
-E: sunfish@mozilla.com
-D: Miscellaneous bug fixes
-D: WebAssembly Backend
-
-N: David Goodwin
-E: david@goodwinz.net
-D: Thumb-2 code generator
-
-N: David Greene
-E: greened@obbligato.org
-D: Miscellaneous bug fixes
-D: Register allocation refactoring
-
-N: Gabor Greif
-E: ggreif@gmail.com
-D: Improvements for space efficiency
-
-N: James Grosbach
-E: grosbach@apple.com
-I: grosbach
-D: SjLj exception handling support
-D: General fixes and improvements for the ARM back-end
-D: MCJIT
-D: ARM integrated assembler and assembly parser
-D: Led effort for the backend formerly known as ARM64
-
-N: Lang Hames
-E: lhames@gmail.com
-D: PBQP-based register allocator
-
-N: Gordon Henriksen
-E: gordonhenriksen@mac.com
-D: Pluggable GC support
-D: C interface
-D: Ocaml bindings
-
-N: Raul Fernandes Herbster
-E: raul@dsc.ufcg.edu.br
-D: JIT support for ARM
-
-N: Paolo Invernizzi
-E: arathorn@fastwebnet.it
-D: Visual C++ compatibility fixes
-
-N: Patrick Jenkins
-E: patjenk@wam.umd.edu
-D: Nightly Tester
-
-N: Dale Johannesen
-E: dalej@apple.com
-D: ARM constant islands improvements
-D: Tail merging improvements
-D: Rewrite X87 back end
-D: Use APFloat for floating point constants widely throughout compiler
-D: Implement X87 long double
-
-N: Brad Jones
-E: kungfoomaster@nondot.org
-D: Support for packed types
-
-N: Rod Kay
-E: rkay@auroraux.org
-D: Author of LLVM Ada bindings
-
-N: Eric Kidd
-W: http://randomhacks.net/
-D: llvm-config script
-
-N: Anton Korobeynikov
-E: asl@math.spbu.ru
-D: Mingw32 fixes, cross-compiling support, stdcall/fastcall calling conv.
-D: x86/linux PIC codegen, aliases, regparm/visibility attributes
-D: Switch lowering refactoring
-
-N: Sumant Kowshik
-E: kowshik@uiuc.edu
-D: Author of the original C backend
-
-N: Benjamin Kramer
-E: benny.kra@gmail.com
-D: Miscellaneous bug fixes
-
-N: Sundeep Kushwaha
-E: sundeepk@codeaurora.org
-D: Implemented DFA-based target independent VLIW packetizer
-
-N: Christopher Lamb
-E: christopher.lamb@gmail.com
-D: aligned load/store support, parts of noalias and restrict support
-D: vreg subreg infrastructure, X86 codegen improvements based on subregs
-D: address spaces
-
-N: Jim Laskey
-E: jlaskey@apple.com
-D: Improvements to the PPC backend, instruction scheduling
-D: Debug and Dwarf implementation
-D: Auto upgrade mangler
-D: llvm-gcc4 svn wrangler
-
-N: Chris Lattner
-E: sabre@nondot.org
-W: http://nondot.org/~sabre/
-D: Primary architect of LLVM
-
-N: Tanya Lattner (Tanya Brethour)
-E: tonic@nondot.org
-W: http://nondot.org/~tonic/
-D: The initial llvm-ar tool, converted regression testsuite to dejagnu
-D: Modulo scheduling in the SparcV9 backend
-D: Release manager (1.7+)
-
-N: Sylvestre Ledru
-E: sylvestre@debian.org
-W: http://sylvestre.ledru.info/
-W: http://llvm.org/apt/
-D: Debian and Ubuntu packaging
-D: Continuous integration with jenkins
-
-N: Andrew Lenharth
-E: alenhar2@cs.uiuc.edu
-W: http://www.lenharth.org/~andrewl/
-D: Alpha backend
-D: Sampling based profiling
-
-N: Nick Lewycky
-E: nicholas@mxc.ca
-D: PredicateSimplifier pass
-
-N: Tony Linthicum, et. al.
-E: tlinth@codeaurora.org
-D: Backend for Qualcomm's Hexagon VLIW processor.
-
-N: Bruno Cardoso Lopes
-E: bruno.cardoso@gmail.com
-I: bruno
-W: http://brunocardoso.cc
-D: Mips backend
-D: Random ARM integrated assembler and assembly parser improvements
-D: General X86 AVX1 support
-
-N: Duraid Madina
-E: duraid@octopus.com.au
-W: http://kinoko.c.u-tokyo.ac.jp/~duraid/
-D: IA64 backend, BigBlock register allocator
-
-N: John McCall
-E: rjmccall@apple.com
-D: Clang semantic analysis and IR generation
-
-N: Michael McCracken
-E: michael.mccracken@gmail.com
-D: Line number support for llvmgcc
-
-N: Vladimir Merzliakov
-E: wanderer@rsu.ru
-D: Test suite fixes for FreeBSD
-
-N: Scott Michel
-E: scottm@aero.org
-D: Added STI Cell SPU backend.
-
-N: Kai Nacke
-E: kai@redstar.de
-D: Support for implicit TLS model used with MS VC runtime
-D: Dumping of Win64 EH structures
-
-N: Takumi Nakamura
-E: geek4civic@gmail.com
-E: chapuni@hf.rim.or.jp
-D: Cygwin and MinGW support.
-D: Win32 tweaks.
-S: Yokohama, Japan
-
-N: Edward O'Callaghan
-E: eocallaghan@auroraux.org
-W: http://www.auroraux.org
-D: Add Clang support with various other improvements to utils/NewNightlyTest.pl
-D: Fix and maintain Solaris & AuroraUX support for llvm, various build warnings
-D: and error clean ups.
-
-N: Morten Ofstad
-E: morten@hue.no
-D: Visual C++ compatibility fixes
-
-N: Jakob Stoklund Olesen
-E: stoklund@2pi.dk
-D: Machine code verifier
-D: Blackfin backend
-D: Fast register allocator
-D: Greedy register allocator
-
-N: Richard Osborne
-E: richard@xmos.com
-D: XCore backend
-
-N: Devang Patel
-E: dpatel@apple.com
-D: LTO tool, PassManager rewrite, Loop Pass Manager, Loop Rotate
-D: GCC PCH Integration (llvm-gcc), llvm-gcc improvements
-D: Optimizer improvements, Loop Index Split
-
-N: Ana Pazos
-E: apazos@codeaurora.org
-D: Fixes and improvements to the AArch64 backend
-
-N: Wesley Peck
-E: peckw@wesleypeck.com
-W: http://wesleypeck.com/
-D: MicroBlaze backend
-
-N: Francois Pichet
-E: pichet2000@gmail.com
-D: MSVC support
-
-N: Vladimir Prus
-W: http://vladimir_prus.blogspot.com
-E: ghost@cs.msu.su
-D: Made inst_iterator behave like a proper iterator, LowerConstantExprs pass
-
-N: Kalle Raiskila
-E: kalle.rasikila@nokia.com
-D: Some bugfixes to CellSPU
-
-N: Xerxes Ranby
-E: xerxes@zafena.se
-D: Cmake dependency chain and various bug fixes
-
-N: Alex Rosenberg
-E: alexr@leftfield.org
-I: arosenberg
-D: ARM calling conventions rewrite, hard float support
-
-N: Chad Rosier
-E: mcrosier@codeaurora.org
-I: mcrosier
-D: AArch64 fast instruction selection pass
-D: Fixes and improvements to the ARM fast-isel pass
-D: Fixes and improvements to the AArch64 backend
-
-N: Nadav Rotem
-E: nrotem@apple.com
-D: X86 code generation improvements, Loop Vectorizer.
-
-N: Roman Samoilov
-E: roman@codedgers.com
-D: MSIL backend
-
-N: Duncan Sands
-E: baldrick@free.fr
-I: baldrick
-D: Ada support in llvm-gcc
-D: Dragonegg plugin
-D: Exception handling improvements
-D: Type legalizer rewrite
-
-N: Ruchira Sasanka
-E: sasanka@uiuc.edu
-D: Graph coloring register allocator for the Sparc64 backend
-
-N: Arnold Schwaighofer
-E: arnold.schwaighofer@gmail.com
-D: Tail call optimization for the x86 backend
-
-N: Shantonu Sen
-E: ssen@apple.com
-D: Miscellaneous bug fixes
-
-N: Anand Shukla
-E: ashukla@cs.uiuc.edu
-D: The `paths' pass
-
-N: Michael J. Spencer
-E: bigcheesegs@gmail.com
-D: Shepherding Windows COFF support into MC.
-D: Lots of Windows stuff.
-
-N: Reid Spencer
-E: rspencer@reidspencer.com
-W: http://reidspencer.com/
-D: Lots of stuff, see: http://wiki.llvm.org/index.php/User:Reid
-
-N: Alp Toker
-E: alp@nuanti.com
-W: http://atoker.com/
-D: C++ frontend next generation standards implementation
-
-N: Craig Topper
-E: craig.topper@gmail.com
-D: X86 codegen and disassembler improvements. AVX2 support.
-
-N: Edwin Torok
-E: edwintorok@gmail.com
-D: Miscellaneous bug fixes
-
-N: Adam Treat
-E: manyoso@yahoo.com
-D: C++ bugs filed, and C++ front-end bug fixes.
-
-N: Lauro Ramos Venancio
-E: lauro.venancio@indt.org.br
-D: ARM backend improvements
-D: Thread Local Storage implementation
-
-N: Bill Wendling
-I: wendling
-E: isanbard@gmail.com
-D: Release manager, IR Linker, LTO
-D: Bunches of stuff
-
-N: Bob Wilson
-E: bob.wilson@acm.org
-D: Advanced SIMD (NEON) support in the ARM backend.
-
diff --git a/bin/LICENSE.TXT b/bin/LICENSE.TXT
deleted file mode 100644
index 84090c07a..000000000
--- a/bin/LICENSE.TXT
+++ /dev/null
@@ -1,70 +0,0 @@
-==============================================================================
-LLVM Release License
-==============================================================================
-University of Illinois/NCSA
-Open Source License
-
-Copyright (c) 2003-2015 University of Illinois at Urbana-Champaign.
-All rights reserved.
-
-Developed by:
-
- LLVM Team
-
- University of Illinois at Urbana-Champaign
-
- http://llvm.org
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of
-this software and associated documentation files (the "Software"), to deal with
-the Software without restriction, including without limitation the rights to
-use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
-of the Software, and to permit persons to whom the Software is furnished to do
-so, subject to the following conditions:
-
- * Redistributions of source code must retain the above copyright notice,
- this list of conditions and the following disclaimers.
-
- * Redistributions in binary form must reproduce the above copyright notice,
- this list of conditions and the following disclaimers in the
- documentation and/or other materials provided with the distribution.
-
- * Neither the names of the LLVM Team, University of Illinois at
- Urbana-Champaign, nor the names of its contributors may be used to
- endorse or promote products derived from this Software without specific
- prior written permission.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
-IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
-FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
-CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
-LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
-SOFTWARE.
-
-==============================================================================
-Copyrights and Licenses for Third Party Software Distributed with LLVM:
-==============================================================================
-The LLVM software contains code written by third parties. Such software will
-have its own individual LICENSE.TXT file in the directory in which it appears.
-This file will describe the copyrights, license, and restrictions which apply
-to that code.
-
-The disclaimer of warranty in the University of Illinois Open Source License
-applies to all code in the LLVM Distribution, and nothing in any of the
-other licenses gives permission to use the names of the LLVM Team or the
-University of Illinois to endorse or promote products derived from this
-Software.
-
-The following pieces of software have additional or alternate copyrights,
-licenses, and/or restrictions:
-
-Program Directory
-------- ---------
-Autoconf llvm/autoconf
- llvm/projects/ModuleMaker/autoconf
-Google Test llvm/utils/unittest/googletest
-OpenBSD regex llvm/lib/Support/{reg*, COPYRIGHT.regex}
-pyyaml tests llvm/test/YAMLParser/{*.data, LICENSE.TXT}
-ARM contributions llvm/lib/Target/ARM/LICENSE.TXT
-md5 contributions llvm/lib/Support/MD5.cpp llvm/include/llvm/Support/MD5.h
diff --git a/bin/llc.exe b/bin/llc.exe
deleted file mode 100644
index a7bb7cc25..000000000
--- a/bin/llc.exe
+++ /dev/null
Binary files differ
diff --git a/bin/lli.exe b/bin/lli.exe
deleted file mode 100644
index 7691672dc..000000000
--- a/bin/lli.exe
+++ /dev/null
Binary files differ
diff --git a/bin/opt.exe b/bin/opt.exe
deleted file mode 100644
index 9b34c9ac8..000000000
--- a/bin/opt.exe
+++ /dev/null
Binary files differ
diff --git a/build.bat b/build.bat
index 17dbe7e5b..51dfc84b4 100644
--- a/build.bat
+++ b/build.bat
@@ -44,16 +44,12 @@ del *.ilk > NUL 2> NUL
cl %compiler_settings% "src\main.c" ^
/link %linker_settings% -OUT:%exe_name% ^
- && odin build code/Jaze/src/main.odin
- rem && odin run code/demo.odin
- rem && odin build_dll code/example.odin ^
- rem odin run code/demo.odin
-
-rem pushd src\asm
-rem nasm hellope.asm -fwin64 -o hellope.obj ^
-rem && cl /nologo hellope.obj /link kernel32.lib /entry:main ^
-rem && hellope.exe
-rem popd
+ && odin run code/demo.odin
+ rem && odin build code/metagen.odin ^
+ rem && call "code\metagen.exe" "src\ast_nodes.metagen"
+ rem && odin run code/Jaze/src/main.odin
+
+del *.obj > NUL 2> NUL
:end_of_build
diff --git a/code/demo.odin b/code/demo.odin
index 2d03e2ec7..86a132142 100644
--- a/code/demo.odin
+++ b/code/demo.odin
@@ -7,53 +7,21 @@
#import "os.odin";
#import "strconv.odin";
#import "sync.odin";
+#import win32 "sys/windows.odin";
main :: proc() {
- // buf: [64]byte;
- // // len := strconv.generic_ftoa(buf[..], 123.5431, 'f', 4, 64);
- // x := 624.123;
- // s := strconv.format_float(buf[..], x, 'f', 6, 64);
- // fmt.println(s);
- // fmt.printf("%3d\n", 102);
-
- s := new_slice(int, 0, 10);
- append(s, 1, 2, 6, 3, 6, 5, 5, 5, 5, 1, 2);
- fmt.println(s);
-
-
-when false {
/*
- Version 0.1.1
-
Added:
- * Dynamic Arrays `[dynamic]Type`
- * Dynamic Maps `map[Key]Value`
- * Dynamic array and map literals
- * Custom struct alignemnt `struct #align 8 { bar: i8 }`
- * Allow `_` in numbers
- * Variadic `append`
- * fmt.sprint*
- * Entities prefixes with an underscore do not get exported on imports
- * Overloaded `free` for pointers, slices, strings, dynamic arrays, and dynamic maps
- * enum types have an implict `names` field, a []string of all the names in that enum
- * immutable variables are "completely immutable" - rules need a full explanation
- * `slice_to_bytes` - convert any slice to a slice of bytes
- * `union_cast` allows for optional ok check
- * Record type field `names` (struct/raw_union/enum)
- * ?: ternary operator
- * Unions with variants and common fields
- * New built-in procedures
- - `delete` to delete map entries `delete(m, key)`
- - `clear` to clear dynamic maps and arrays `clear(map_or_array)`
- - `reserve` to reserve space for the dynamic maps and arrays `reserve(map_or_array)`
- * Unexported entities and fields using an underscore prefix
+ * Unexported entities and fields using an underscore prefix
+ - See `sync.odin` and explain
Removed:
* Maybe/option types
* Remove `type` keyword and other "reserved" keywords
- * `compile_assert` and `assert`return the value of the condition for semantic reasons
+ * ..< and ... removed and replace with .. (half-closed range)
Changed:
+ * `compile_assert` and `assert`return the value of the condition for semantic reasons
* thread_local -> #thread_local
* #include -> #load
* Files only get checked if they are actually used
@@ -61,20 +29,7 @@ when false {
* Version numbering now starts from 0.1.0 and uses the convention:
- major.minor.patch
* Core library additions to Windows specific stuff
-
- Fixes:
- * Many fmt.* fixes
- * Overloading bug due to comparison of named types
- * Overloading bug due to `#import .` collision
- * disallow a `cast` from pointers of unions
- * Minor bugs in generated IR code for slices
-
- To come very Soon™:
- * Linux and OS X builds (unofficial ones do exist already)
-*/
- {
-
- }
+ */
{
Fruit :: enum {
@@ -86,6 +41,161 @@ when false {
}
{
+ A :: struct {x, y: f32};
+ B :: struct #align 16 {x, y: f32};
+ fmt.println("align_of(A) =", align_of(A));
+ fmt.println("align_of(B) =", align_of(B));
+ }
+
+ {
+ // Removal of ..< and ...
+ for i in 0..16 {
+ }
+ // Is similar to
+ for _i := 0; _i < 16; _i++ { immutable i := _i;
+ }
+ }
+
+ {
+ #label thing
+ for i in 0..10 {
+ for j := i+1; j < 10; j++ {
+ if j == 2 {
+ fmt.println(i, j);
+ break thing;
+ }
+ }
+ }
+ }
+
+ {
+ t := type_info(int);
+ using Type_Info;
+ match i in t {
+ case Integer, Float:
+ fmt.println("It's a number");
+ }
+
+ x: any = 123;
+ match i in x {
+ case int, f32:
+ fmt.println("It's an int or f32");
+ }
+ }
+
+ {
+ cond := true;
+ x: int;
+ if cond {
+ x = 3;
+ } else {
+ x = 4;
+ }
+
+
+ // Ternary operator
+ y := cond ? 3 : 4;
+
+ FOO :: true ? 123 : 432; // Constant ternary expression
+ fmt.println("Ternary values:", y, FOO);
+ }
+
+ {
+ // Slices now store a capacity
+ buf: [256]byte;
+ s: []byte;
+ s = buf[..0]; // == buf[0..0];
+ fmt.println("count =", s.count);
+ fmt.println("capacity =", s.capacity);
+ append(s, 1, 2, 3);
+ fmt.println(s);
+
+ s = buf[1..2..3];
+ fmt.println("count =", s.count);
+ fmt.println("capacity =", s.capacity);
+ fmt.println(s);
+
+ clear(s); // Sets count to zero
+ s.count = 0; // Equivalent
+ }
+
+ {
+ Foo :: struct {
+ x, y, z: f32,
+ ok: bool,
+ flags: u32,
+ }
+ foo_array: [256]Foo;
+ foo_as_bytes: []byte = slice_to_bytes(foo_array[..]);
+ // Useful for things like
+ // os.write(handle, foo_as_bytes);
+
+ foo_slice := slice_ptr(cast(^Foo)foo_as_bytes.data, foo_as_bytes.count/size_of(Foo), foo_as_bytes.capacity/size_of(Foo));
+ // Question: Should there be a bytes_to_slice procedure or is it clearer to do this even if it is error prone?
+ // And if so what would the syntax be?
+ // slice_transmute([]Foo, foo_as_bytes);
+ }
+
+ {
+ Vec3 :: [vector 3]f32;
+
+ x := Vec3{1, 2, 3};
+ y := Vec3{4, 5, 6};
+ fmt.println(x < y);
+ fmt.println(x + y);
+ fmt.println(x - y);
+ fmt.println(x * y);
+ fmt.println(x / y);
+
+ for i in x {
+ fmt.println(i);
+ }
+
+ compile_assert(size_of([vector 7]bool) == size_of([7]bool));
+ compile_assert(size_of([vector 7]i32) == size_of([7]i32));
+ // align_of([vector 7]i32) != align_of([7]i32) // this may be the case
+ }
+
+ {
+ // fmt.* changes
+ // bprint* returns `int` (bytes written)
+ // sprint* returns `string` (bytes written as a string)
+
+ data: [256]byte;
+ str := fmt.sprintf(data[..0], "Hellope %d %s %c", 123, "others", '!');
+ fmt.println(str);
+
+ buf := data[..0];
+ count := fmt.bprintf(^buf, "Hellope %d %s %c", 123, "others", '!');
+ fmt.println(cast(string)buf[..count]);
+
+ // NOTE(bill): We may change this but because this is a library feature, I am not that bothered yet
+ }
+
+ {
+ x: [dynamic]f64;
+ reserve(x, 16);
+ defer free(x); // `free` is overloaded for numerous types
+ // Number literals can have underscores in them for readability
+ append(x, 2_000_000.500_000, 3, 5, 7); // variadic append
+
+ for p, i in x {
+ if i > 0 { fmt.print(", "); }
+ fmt.print(p);
+ }
+ fmt.println();
+ }
+
+ {
+ // Dynamic array "literals"
+ x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
+ defer free(x);
+ fmt.println(x); // fmt.print* supports printing of dynamic types
+ clear(x);
+ fmt.println(x);
+ }
+
+ {
m: map[f32]int;
reserve(m, 16);
defer free(m);
@@ -119,49 +229,79 @@ when false {
c := m["c"];
_, ok := m["c"];
assert(ok && c == 7654);
+ fmt.println(m);
+ delete(m, "c"); // deletes entry with key "c"
+ _, found := m["c"];
+ assert(!found);
+
+ fmt.println(m);
+ clear(m);
fmt.println(m);
+
+ // NOTE: Fixed size maps are planned but we have not yet implemented
+ // them as we have had no need for them as of yet
}
{
- x: [dynamic]f64;
- reserve(x, 16);
- defer free(x);
- append(x, 2_000_000.500_000, 3, 5, 7);
+ Vector3 :: struct{x, y, z: f32};
+ Quaternion :: struct{x, y, z, w: f32};
- for p, i in x {
- if i > 0 { fmt.print(", "); }
- fmt.print(p);
+ Entity :: union {
+ // Common Fields
+ id: u64,
+ name: string,
+ using position: Vector3,
+ orientation: Quaternion,
+ flags: u32,
+
+ // Variants
+ Frog{
+ ribbit_volume: f32,
+ jump_height: f32,
+ },
+ Door{
+ openness: f32,
+ },
+ Map{
+ width, height: f32,
+ place_positions: []Vector3,
+ place_names: []string,
+ },
}
- fmt.println();
- }
- {
- x := [dynamic]f64{2_000_000.500_000, 3, 5, 7};
- defer free(x);
- fmt.println(x);
- }
+ entity: Entity;
+ // implicit conversion from variant to base type
+ entity = Entity.Frog{
+ id = 1337,
+ ribbit_volume = 0.5,
+ jump_height = 2.1,
+ /*other data */
+ };
+ entity.name = "Frank";
+ entity.position = Vector3{1, 4, 9};
- {
- Vec3 :: [vector 3]f32;
-
- x := Vec3{1, 2, 3};
- y := Vec3{4, 5, 6};
- fmt.println(x < y);
- fmt.println(x + y);
- fmt.println(x - y);
- fmt.println(x * y);
- fmt.println(x / y);
+ using Entity;
+ match e in entity {
+ case Frog:
+ fmt.println("Ribbit");
+ case Door:
+ fmt.println("Creak");
+ case Map:
+ fmt.println("Rustle");
+ default:
+ fmt.println("Just a normal entity");
+ }
- for i in x {
- fmt.println(i);
+ if frog, ok := union_cast(Frog)entity; ok {
+ fmt.printf("The frog jumps %f feet high at %v\n", frog.jump_height, frog.position);
}
- compile_assert(size_of([vector 7]bool) == size_of([7]bool));
- compile_assert(size_of([vector 7]i32) == size_of([7]i32));
- // align_of([vector 7]i32) != align_of([7]i32) // this may be the case
+ // Panics if not the correct type
+ frog: Frog;
+ frog = union_cast(Frog)entity;
+ frog, _ = union_cast(Frog)entity; // ignore error and force cast
}
}
-}
diff --git a/core/_preload.odin b/core/_preload.odin
index 953d38c43..3b3e60e0f 100644
--- a/core/_preload.odin
+++ b/core/_preload.odin
@@ -128,9 +128,6 @@ __debug_trap :: proc() #foreign __llvm_core "llvm.debugtrap";
__trap :: proc() #foreign __llvm_core "llvm.trap";
read_cycle_counter :: proc() -> u64 #foreign __llvm_core "llvm.readcyclecounter";
-__cpuid :: proc(level: u32, sig: ^u32) -> i32 #foreign __llvm_core "__get_cpuid";
-
-
@@ -350,6 +347,40 @@ __string_decode_rune :: proc(s: string) -> (rune, int) #inline {
}
+__mem_set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
+ llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
+ llvm_memset_64bit(data, cast(byte)value, len, 1, false);
+ return data;
+}
+__mem_zero :: proc(data: rawptr, len: int) -> rawptr {
+ return __mem_set(data, 0, len);
+}
+__mem_copy :: proc(dst, src: rawptr, len: int) -> rawptr {
+ // NOTE(bill): This _must_ be implemented like C's memmove
+ llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
+ llvm_memmove_64bit(dst, src, len, 1, false);
+ return dst;
+}
+__mem_copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
+ // NOTE(bill): This _must_ be implemented like C's memcpy
+ llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
+ llvm_memcpy_64bit(dst, src, len, 1, false);
+ return dst;
+}
+
+__mem_compare :: proc(a, b: ^byte, n: int) -> int {
+ for i in 0..n {
+ match {
+ case (a+i)^ < (b+i)^:
+ return -1;
+ case (a+i)^ > (b+i)^:
+ return +1;
+ }
+ }
+ return 0;
+}
+
+
Raw_Any :: struct #ordered {
type_info: ^Type_Info,
data: rawptr,
diff --git a/core/fmt.odin b/core/fmt.odin
index abc0d1ac7..ae2d340e8 100644
--- a/core/fmt.odin
+++ b/core/fmt.odin
@@ -102,7 +102,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
default:
write_string(buf, info.signed ? "i" : "u");
fi := Fmt_Info{buf = buf};
- fmt_int(^fi, cast(u64)(8*info.size), false, 'd');
+ fmt_int(^fi, cast(u64)(8*info.size), false, 64, 'd');
}
case Float:
@@ -155,7 +155,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
case Array:
write_string(buf, "[");
fi := Fmt_Info{buf = buf};
- fmt_int(^fi, cast(u64)info.count, false, 'd');
+ fmt_int(^fi, cast(u64)info.count, false, 64, 'd');
write_string(buf, "]");
write_type(buf, info.elem);
case Dynamic_Array:
@@ -168,7 +168,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
case Vector:
write_string(buf, "[vector ");
fi := Fmt_Info{buf = buf};
- fmt_int(^fi, cast(u64)info.count, false, 'd');
+ fmt_int(^fi, cast(u64)info.count, false, 64, 'd');
write_string(buf, "]");
write_type(buf, info.elem);
@@ -185,7 +185,7 @@ write_type :: proc(buf: ^[]byte, ti: ^Type_Info) {
if info.custom_align {
write_string(buf, "#align ");
fi := Fmt_Info{buf = buf};
- fmt_int(^fi, cast(u64)info.align, false, 'd');
+ fmt_int(^fi, cast(u64)info.align, false, 64, 'd');
write_byte(buf, ' ');
}
write_byte(buf, '{');
@@ -295,15 +295,15 @@ bprintln :: proc(buf: ^[]byte, args: ..any) -> int {
sprint :: proc(buf: []byte, args: ..any) -> string {
count := bprint(^buf, ..args);
- return cast(string)buf;
+ return cast(string)buf[..count];
}
sprintln :: proc(buf: []byte, args: ..any) -> string {
count := bprintln(^buf, ..args);
- return cast(string)buf;
+ return cast(string)buf[..count];
}
sprintf :: proc(buf: []byte, fmt: string, args: ..any) -> string {
count := bprintf(^buf, fmt, ..args);
- return cast(string)buf;
+ return cast(string)buf[..count];
}
@@ -435,16 +435,47 @@ fmt_write_padding :: proc(fi: ^Fmt_Info, width: int) {
}
}
-_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string) {
- if neg {
- u = -u;
+
+is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
+ neg := false;
+ if is_signed {
+ match bit_size {
+ case 8:
+ i := cast(i8)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 16:
+ i := cast(i16)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 32:
+ i := cast(i32)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 64:
+ i := cast(i64)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ default:
+ panic("is_integer_negative: Unknown integer size");
+ }
}
+ return u, neg;
+}
+
+_write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, is_signed: bool, bit_size: int, digits: string) {
+ _, neg := is_integer_negative(u, is_signed, bit_size);
+
BUF_SIZE :: 256;
if fi.width_set || fi.prec_set {
width := fi.width + fi.prec + 3; // 3 extra bytes for sign and prefix
if width > BUF_SIZE {
// TODO(bill):????
- panic("_write_int buffer overrun. Width and precision too big");
+ panic("_write_int: buffer overrun. Width and precision too big");
}
}
@@ -467,7 +498,7 @@ _write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string)
}
match base {
- case 2, 8, 10, 16:
+ case 2, 8, 10, 12, 16:
break;
default:
panic("_write_int: unknown base, whoops");
@@ -475,10 +506,10 @@ _write_int :: proc(fi: ^Fmt_Info, u: u64, base: int, neg: bool, digits: string)
buf: [256]byte;
flags: strconv.Int_Flag;
- if fi.hash { flags |= strconv.Int_Flag.PREFIX; }
- if fi.plus { flags |= strconv.Int_Flag.PLUS; }
- if fi.space { flags |= strconv.Int_Flag.SPACE; }
- s := strconv.append_bits(buf[..0], u, base, neg, digits, flags);
+ if fi.hash { flags |= strconv.Int_Flag.PREFIX; }
+ if fi.plus { flags |= strconv.Int_Flag.PLUS; }
+ if fi.space { flags |= strconv.Int_Flag.SPACE; }
+ s := strconv.append_bits(buf[..0], u, base, is_signed, bit_size, digits, flags);
prev_zero := fi.zero;
defer fi.zero = prev_zero;
@@ -493,14 +524,14 @@ fmt_rune :: proc(fi: ^Fmt_Info, r: rune) {
write_rune(fi.buf, r);
}
-fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) {
+fmt_int :: proc(fi: ^Fmt_Info, u: u64, is_signed: bool, bit_size: int, verb: rune) {
match verb {
- case 'v': _write_int(fi, u, 10, neg, __DIGITS_LOWER);
- case 'b': _write_int(fi, u, 2, neg, __DIGITS_LOWER);
- case 'o': _write_int(fi, u, 8, neg, __DIGITS_LOWER);
- case 'd': _write_int(fi, u, 10, neg, __DIGITS_LOWER);
- case 'x': _write_int(fi, u, 16, neg, __DIGITS_LOWER);
- case 'X': _write_int(fi, u, 16, neg, __DIGITS_UPPER);
+ case 'v': _write_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
+ case 'b': _write_int(fi, u, 2, is_signed, bit_size, __DIGITS_LOWER);
+ case 'o': _write_int(fi, u, 8, is_signed, bit_size, __DIGITS_LOWER);
+ case 'd': _write_int(fi, u, 10, is_signed, bit_size, __DIGITS_LOWER);
+ case 'x': _write_int(fi, u, 16, is_signed, bit_size, __DIGITS_LOWER);
+ case 'X': _write_int(fi, u, 16, is_signed, bit_size, __DIGITS_UPPER);
case 'c', 'r':
fmt_rune(fi, cast(rune)u);
case 'U':
@@ -509,7 +540,7 @@ fmt_int :: proc(fi: ^Fmt_Info, u: u64, neg: bool, verb: rune) {
fmt_bad_verb(fi, verb);
} else {
write_string(fi.buf, "U+");
- _write_int(fi, u, 16, false, __DIGITS_UPPER);
+ _write_int(fi, u, 16, false, bit_size, __DIGITS_UPPER);
}
default:
@@ -598,7 +629,7 @@ fmt_pointer :: proc(fi: ^Fmt_Info, p: rawptr, verb: rune) {
if !fi.hash || verb == 'v' {
write_string(fi.buf, "0x");
}
- _write_int(fi, u, 16, false, __DIGITS_UPPER);
+ _write_int(fi, u, 16, false, 8*size_of(rawptr), __DIGITS_UPPER);
}
fmt_enum :: proc(fi: ^Fmt_Info, v: any, verb: rune) {
@@ -876,16 +907,16 @@ fmt_arg :: proc(fi: ^Fmt_Info, arg: any, verb: rune) {
case f32: fmt_float(fi, cast(f64)a, 32, verb);
case f64: fmt_float(fi, a, 64, verb);
- case int: fmt_int(fi, cast(u64)a, a < 0, verb);
- case i8: fmt_int(fi, cast(u64)a, a < 0, verb);
- case i16: fmt_int(fi, cast(u64)a, a < 0, verb);
- case i32: fmt_int(fi, cast(u64)a, a < 0, verb);
- case i64: fmt_int(fi, cast(u64)a, a < 0, verb);
- case uint: fmt_int(fi, cast(u64)a, false, verb);
- case u8: fmt_int(fi, cast(u64)a, false, verb);
- case u16: fmt_int(fi, cast(u64)a, false, verb);
- case u32: fmt_int(fi, cast(u64)a, false, verb);
- case u64: fmt_int(fi, cast(u64)a, false, verb);
+ case int: fmt_int(fi, cast(u64)a, true, 8*size_of(int), verb);
+ case i8: fmt_int(fi, cast(u64)a, true, 8, verb);
+ case i16: fmt_int(fi, cast(u64)a, true, 16, verb);
+ case i32: fmt_int(fi, cast(u64)a, true, 32, verb);
+ case i64: fmt_int(fi, cast(u64)a, true, 64, verb);
+ case uint: fmt_int(fi, cast(u64)a, false, 8*size_of(uint), verb);
+ case u8: fmt_int(fi, cast(u64)a, false, 8, verb);
+ case u16: fmt_int(fi, cast(u64)a, false, 16, verb);
+ case u32: fmt_int(fi, cast(u64)a, false, 32, verb);
+ case u64: fmt_int(fi, cast(u64)a, false, 64, verb);
case string: fmt_string(fi, a, verb);
default: fmt_value(fi, arg, verb);
}
diff --git a/core/math.odin b/core/math.odin
index ef773faf9..7e1e0bb07 100644
--- a/core/math.odin
+++ b/core/math.odin
@@ -27,14 +27,14 @@ Mat4 :: [4]Vec4;
sqrt :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sqrt.f32";
sqrt :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sqrt.f64";
-sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
-sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
+sin :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.sin.f32";
+sin :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.sin.f64";
-cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
-cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
+cos :: proc(x: f32) -> f32 #foreign __llvm_core "llvm.cos.f32";
+cos :: proc(x: f64) -> f64 #foreign __llvm_core "llvm.cos.f64";
-tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
-tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
+tan :: proc(x: f32) -> f32 #inline { return sin(x)/cos(x); }
+tan :: proc(x: f64) -> f64 #inline { return sin(x)/cos(x); }
lerp :: proc(a, b, t: f32) -> f32 { return a*(1-t) + b*t; }
lerp :: proc(a, b, t: f64) -> f64 { return a*(1-t) + b*t; }
@@ -53,36 +53,42 @@ fmuladd :: proc(a, b, c: f64) -> f64 #foreign __llvm_core "llvm.fmuladd.f64";
copy_sign :: proc(x, y: f32) -> f32 {
ix := transmute(u32)x;
iy := transmute(u32)y;
- ix &= 0x7fffffff;
- ix |= iy & 0x80000000;
+ ix &= 0x7fff_ffff;
+ ix |= iy & 0x8000_0000;
return transmute(f32)ix;
}
-round :: proc(x: f32) -> f32 {
- if x >= 0 {
- return floor(x + 0.5);
- }
- return ceil(x - 0.5);
-}
-floor :: proc(x: f32) -> f32 {
- if x >= 0 {
- return cast(f32)cast(int)x;
- }
- return cast(f32)cast(int)(x-0.5);
-}
-ceil :: proc(x: f32) -> f32 {
- if x < 0 {
- return cast(f32)cast(int)x;
- }
- return cast(f32)cast(int)(x+1);
-}
-remainder32 :: proc(x, y: f32) -> f32 {
- return x - round(x/y) * y;
+copy_sign :: proc(x, y: f64) -> f64 {
+ ix := transmute(u64)x;
+ iy := transmute(u64)y;
+ ix &= 0x7fff_ffff_ffff_ff;
+ ix |= iy & 0x8000_0000_0000_0000;
+ return transmute(f64)ix;
}
-fmod32 :: proc(x, y: f32) -> f32 {
+round :: proc(x: f32) -> f32 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
+round :: proc(x: f64) -> f64 { return x >= 0 ? floor(x + 0.5) : ceil(x - 0.5); }
+
+floor :: proc(x: f32) -> f32 { return x >= 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x-0.5); } // TODO: Get accurate versions
+floor :: proc(x: f64) -> f64 { return x >= 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x-0.5); } // TODO: Get accurate versions
+
+ceil :: proc(x: f32) -> f32 { return x < 0 ? cast(f32)cast(i64)x : cast(f32)cast(i64)(x+1); } // TODO: Get accurate versions
+ceil :: proc(x: f64) -> f64 { return x < 0 ? cast(f64)cast(i64)x : cast(f64)cast(i64)(x+1); } // TODO: Get accurate versions
+
+remainder :: proc(x, y: f32) -> f32 { return x - round(x/y) * y; }
+remainder :: proc(x, y: f64) -> f64 { return x - round(x/y) * y; }
+
+mod :: proc(x, y: f32) -> f32 {
+ y = abs(y);
+ result := remainder(abs(x), y);
+ if sign(result) < 0 {
+ result += y;
+ }
+ return copy_sign(result, x);
+}
+mod :: proc(x, y: f64) -> f64 {
y = abs(y);
- result := remainder32(abs(x), y);
+ result := remainder(abs(x), y);
if sign(result) < 0 {
result += y;
}
@@ -95,7 +101,6 @@ to_degrees :: proc(radians: f32) -> f32 { return radians * 360 / TAU; }
-
dot :: proc(a, b: Vec2) -> f32 { c := a*b; return c.x + c.y; }
dot :: proc(a, b: Vec3) -> f32 { c := a*b; return c.x + c.y + c.z; }
dot :: proc(a, b: Vec4) -> f32 { c := a*b; return c.x + c.y + c.z + c.w; }
diff --git a/core/mem.odin b/core/mem.odin
index b5e119921..1560ca410 100644
--- a/core/mem.odin
+++ b/core/mem.odin
@@ -6,41 +6,20 @@ swap :: proc(b: u32) -> u32 #foreign __llvm_core "llvm.bswap.i32";
swap :: proc(b: u64) -> u64 #foreign __llvm_core "llvm.bswap.i64";
-set :: proc(data: rawptr, value: i32, len: int) -> rawptr #link_name "__mem_set" {
- llvm_memset_64bit :: proc(dst: rawptr, val: byte, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memset.p0i8.i64";
- llvm_memset_64bit(data, cast(byte)value, len, 1, false);
- return data;
+set :: proc(data: rawptr, value: i32, len: int) -> rawptr {
+ return __mem_set(data, value, len);
}
-
-zero :: proc(data: rawptr, len: int) -> rawptr #link_name "__mem_zero" {
- return set(data, 0, len);
+zero :: proc(data: rawptr, len: int) -> rawptr {
+ return __mem_zero(data, len);
}
-
-copy :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy" {
- // NOTE(bill): This _must_ be implemented like C's memmove
- llvm_memmove_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memmove.p0i8.p0i8.i64";
- llvm_memmove_64bit(dst, src, len, 1, false);
- return dst;
+copy :: proc(dst, src: rawptr, len: int) -> rawptr {
+ return __mem_copy(dst, src, len);
}
-
-copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr #link_name "__mem_copy_non_overlapping" {
- // NOTE(bill): This _must_ be implemented like C's memcpy
- llvm_memcpy_64bit :: proc(dst, src: rawptr, len: int, align: i32, is_volatile: bool) #foreign __llvm_core "llvm.memcpy.p0i8.p0i8.i64";
- llvm_memcpy_64bit(dst, src, len, 1, false);
- return dst;
+copy_non_overlapping :: proc(dst, src: rawptr, len: int) -> rawptr {
+ return __mem_copy_non_overlapping(dst, src, len);
}
-
-compare :: proc(a, b: []byte) -> int #link_name "__mem_compare" {
- n := min(a.count, b.count);
- for i in 0..n {
- match {
- case a[i] < b[i]:
- return -1;
- case a[i] > b[i]:
- return +1;
- }
- }
- return 0;
+compare :: proc(a, b: []byte) -> int {
+ return __mem_compare(a.data, b.data, min(a.count, b.count));
}
diff --git a/core/os_windows.odin b/core/os_windows.odin
index 8e380f0ba..1adc80d18 100644
--- a/core/os_windows.odin
+++ b/core/os_windows.odin
@@ -1,4 +1,4 @@
-#import win32 "sys/windows.odin";
+#import w "sys/windows.odin";
#import "fmt.odin";
@@ -53,29 +53,28 @@ ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
- using win32;
if path.count == 0 {
return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
}
access: u32;
match mode & (O_RDONLY|O_WRONLY|O_RDWR) {
- case O_RDONLY: access = FILE_GENERIC_READ;
- case O_WRONLY: access = FILE_GENERIC_WRITE;
- case O_RDWR: access = FILE_GENERIC_READ | FILE_GENERIC_WRITE;
+ case O_RDONLY: access = w.FILE_GENERIC_READ;
+ case O_WRONLY: access = w.FILE_GENERIC_WRITE;
+ case O_RDWR: access = w.FILE_GENERIC_READ | w.FILE_GENERIC_WRITE;
}
if mode&O_CREAT != 0 {
- access |= FILE_GENERIC_WRITE;
+ access |= w.FILE_GENERIC_WRITE;
}
if mode&O_APPEND != 0 {
- access &~= FILE_GENERIC_WRITE;
- access |= FILE_APPEND_DATA;
+ access &~= w.FILE_GENERIC_WRITE;
+ access |= w.FILE_APPEND_DATA;
}
- share_mode := cast(u32)(FILE_SHARE_READ|FILE_SHARE_WRITE);
- sa: ^SECURITY_ATTRIBUTES = nil;
- sa_inherit := SECURITY_ATTRIBUTES{length = size_of(SECURITY_ATTRIBUTES), inherit_handle = 1};
+ share_mode := cast(u32)(w.FILE_SHARE_READ|w.FILE_SHARE_WRITE);
+ sa: ^w.Security_Attributes = nil;
+ sa_inherit := w.Security_Attributes{length = size_of(w.Security_Attributes), inherit_handle = 1};
if mode&O_CLOEXEC == 0 {
sa = ^sa_inherit;
}
@@ -83,37 +82,37 @@ open :: proc(path: string, mode: int, perm: u32) -> (Handle, Errno) {
create_mode: u32;
match {
case mode&(O_CREAT|O_EXCL) == (O_CREAT | O_EXCL):
- create_mode = CREATE_NEW;
+ create_mode = w.CREATE_NEW;
case mode&(O_CREAT|O_TRUNC) == (O_CREAT | O_TRUNC):
- create_mode = CREATE_ALWAYS;
+ create_mode = w.CREATE_ALWAYS;
case mode&O_CREAT == O_CREAT:
- create_mode = OPEN_ALWAYS;
+ create_mode = w.OPEN_ALWAYS;
case mode&O_TRUNC == O_TRUNC:
- create_mode = TRUNCATE_EXISTING;
+ create_mode = w.TRUNCATE_EXISTING;
default:
- create_mode = OPEN_EXISTING;
+ create_mode = w.OPEN_EXISTING;
}
buf: [300]byte;
copy(buf[..], cast([]byte)path);
- handle := cast(Handle)CreateFileA(^buf[0], access, share_mode, sa, create_mode, FILE_ATTRIBUTE_NORMAL, nil);
+ handle := cast(Handle)w.CreateFileA(^buf[0], access, share_mode, sa, create_mode, w.FILE_ATTRIBUTE_NORMAL, nil);
if handle != INVALID_HANDLE {
return handle, ERROR_NONE;
}
- err := GetLastError();
+ err := w.GetLastError();
return INVALID_HANDLE, cast(Errno)err;
}
close :: proc(fd: Handle) {
- win32.CloseHandle(cast(win32.HANDLE)fd);
+ w.CloseHandle(cast(w.Handle)fd);
}
write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_written: i32;
- e := win32.WriteFile(cast(win32.HANDLE)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
- if e == win32.FALSE {
- err := win32.GetLastError();
+ e := w.WriteFile(cast(w.Handle)fd, data.data, cast(i32)data.count, ^bytes_written, nil);
+ if e == w.FALSE {
+ err := w.GetLastError();
return 0, cast(Errno)err;
}
return cast(int)bytes_written, ERROR_NONE;
@@ -121,16 +120,16 @@ write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
bytes_read: i32;
- e := win32.ReadFile(cast(win32.HANDLE)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
- if e == win32.FALSE {
- err := win32.GetLastError();
+ e := w.ReadFile(cast(w.Handle)fd, data.data, cast(u32)data.count, ^bytes_read, nil);
+ if e == w.FALSE {
+ err := w.GetLastError();
return 0, cast(Errno)err;
}
return cast(int)bytes_read, ERROR_NONE;
}
seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
- using win32;
+ using w;
w: u32;
match whence {
case 0: w = FILE_BEGIN;
@@ -139,11 +138,11 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
}
hi := cast(i32)(offset>>32);
lo := cast(i32)(offset);
- ft := GetFileType(cast(HANDLE)fd);
+ ft := GetFileType(cast(Handle)fd);
if ft == FILE_TYPE_PIPE {
return 0, ERROR_FILE_IS_PIPE;
}
- dw_ptr := SetFilePointer(cast(HANDLE)fd, lo, ^hi, w);
+ dw_ptr := SetFilePointer(cast(Handle)fd, lo, ^hi, w);
if dw_ptr == INVALID_SET_FILE_POINTER {
err := GetLastError();
return 0, cast(Errno)err;
@@ -153,14 +152,14 @@ seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
// NOTE(bill): Uses startup to initialize it
-stdin := get_std_handle(win32.STD_INPUT_HANDLE);
-stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
-stderr := get_std_handle(win32.STD_ERROR_HANDLE);
+stdin := get_std_handle(w.STD_INPUT_HANDLE);
+stdout := get_std_handle(w.STD_OUTPUT_HANDLE);
+stderr := get_std_handle(w.STD_ERROR_HANDLE);
get_std_handle :: proc(h: int) -> Handle {
- fd := win32.GetStdHandle(cast(i32)h);
- win32.SetHandleInformation(fd, win32.HANDLE_FLAG_INHERIT, 0);
+ fd := w.GetStdHandle(cast(i32)h);
+ w.SetHandleInformation(fd, w.HANDLE_FLAG_INHERIT, 0);
return cast(Handle)fd;
}
@@ -170,23 +169,23 @@ get_std_handle :: proc(h: int) -> Handle {
last_write_time :: proc(fd: Handle) -> File_Time {
- file_info: win32.BY_HANDLE_FILE_INFORMATION;
- win32.GetFileInformationByHandle(cast(win32.HANDLE)fd, ^file_info);
+ file_info: w.By_Handle_File_Information;
+ w.GetFileInformationByHandle(cast(w.Handle)fd, ^file_info);
lo := cast(File_Time)file_info.last_write_time.lo;
hi := cast(File_Time)file_info.last_write_time.hi;
return lo | hi << 32;
}
last_write_time_by_name :: proc(name: string) -> File_Time {
- last_write_time: win32.FILETIME;
- data: win32.FILE_ATTRIBUTE_DATA;
+ last_write_time: w.Filetime;
+ data: w.File_Attribute_Data;
buf: [1024]byte;
assert(buf.count > name.count);
copy(buf[..], cast([]byte)name);
- if win32.GetFileAttributesExA(^buf[0], win32.GetFileExInfoStandard, ^data) != 0 {
+ if w.GetFileAttributesExA(^buf[0], w.GetFileExInfoStandard, ^data) != 0 {
last_write_time = data.last_write_time;
}
@@ -210,7 +209,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
defer close(fd);
length: i64;
- file_size_ok := win32.GetFileSizeEx(cast(win32.HANDLE)fd, ^length) != 0;
+ file_size_ok := w.GetFileSizeEx(cast(w.Handle)fd, ^length) != 0;
if !file_size_ok {
return nil, false;
}
@@ -233,7 +232,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
to_read = MAX;
}
- win32.ReadFile(cast(win32.HANDLE)fd, ^data[total_read], to_read, ^single_read_length, nil);
+ w.ReadFile(cast(w.Handle)fd, ^data[total_read], to_read, ^single_read_length, nil);
if single_read_length <= 0 {
free(data);
return nil, false;
@@ -248,8 +247,7 @@ read_entire_file :: proc(name: string) -> ([]byte, bool) {
heap_alloc :: proc(size: int) -> rawptr {
- assert(size > 0);
- return win32.HeapAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, size);
+ return w.HeapAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, size);
}
heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if new_size == 0 {
@@ -259,24 +257,24 @@ heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
if ptr == nil {
return heap_alloc(new_size);
}
- return win32.HeapReAlloc(win32.GetProcessHeap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
+ return w.HeapReAlloc(w.GetProcessHeap(), w.HEAP_ZERO_MEMORY, ptr, new_size);
}
heap_free :: proc(ptr: rawptr) {
if ptr == nil {
return;
}
- win32.HeapFree(win32.GetProcessHeap(), 0, ptr);
+ w.HeapFree(w.GetProcessHeap(), 0, ptr);
}
exit :: proc(code: int) {
- win32.ExitProcess(cast(u32)code);
+ w.ExitProcess(cast(u32)code);
}
current_thread_id :: proc() -> int {
- return cast(int)win32.GetCurrentThreadId();
+ return cast(int)w.GetCurrentThreadId();
}
diff --git a/core/strconv.odin b/core/strconv.odin
index 53d890a6b..5a14d6660 100644
--- a/core/strconv.odin
+++ b/core/strconv.odin
@@ -25,15 +25,12 @@ append_bool :: proc(buf: []byte, b: bool) -> string {
}
append_uint :: proc(buf: []byte, u: u64, base: int) -> string {
- using Int_Flag;
- return append_bits(buf, u, base, false, digits, 0);
+ return append_bits(buf, u, base, false, 8*size_of(uint), digits, 0);
}
append_int :: proc(buf: []byte, i: i64, base: int) -> string {
- return append_bits(buf, cast(u64)i, base, i < 0, digits, 0);
-}
-itoa :: proc(buf: []byte, i: int) -> string {
- return append_int(buf, cast(i64)i, 10);
+ return append_bits(buf, cast(u64)i, base, true, 8*size_of(int), digits, 0);
}
+itoa :: proc(buf: []byte, i: int) -> string { return append_int(buf, cast(i64)i, 10); }
append_float :: proc(buf: []byte, f: f64, fmt: byte, prec, bit_size: int) -> string {
return cast(string)generic_ftoa(buf, f, fmt, prec, bit_size);
@@ -266,7 +263,39 @@ MAX_BASE :: 32;
immutable digits := "0123456789abcdefghijklmnopqrstuvwxyz";
-append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, flags: Int_Flag) -> string {
+is_integer_negative :: proc(u: u64, is_signed: bool, bit_size: int) -> (unsigned: u64, neg: bool) {
+ neg := false;
+ if is_signed {
+ match bit_size {
+ case 8:
+ i := cast(i8)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 16:
+ i := cast(i16)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 32:
+ i := cast(i32)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ case 64:
+ i := cast(i64)u;
+ neg = i < 0;
+ if neg { i = -i; }
+ u = cast(u64)i;
+ default:
+ panic("is_integer_negative: Unknown integer size");
+ }
+ }
+ return u, neg;
+}
+
+
+append_bits :: proc(buf: []byte, u: u64, base: int, is_signed: bool, bit_size: int, digits: string, flags: Int_Flag) -> string {
is_pow2 :: proc(x: i64) -> bool {
if (x <= 0) {
return false;
@@ -280,9 +309,9 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f
a: [65]byte;
i := a.count;
- if neg {
- u = -u;
- }
+
+ neg: bool;
+ u, neg = is_integer_negative(u, is_signed, bit_size);
if is_pow2(cast(i64)base) {
b := cast(u64)base;
@@ -313,6 +342,7 @@ append_bits :: proc(buf: []byte, u: u64, base: int, neg: bool, digits: string, f
case 2: i--; a[i] = 'b';
case 8: i--; a[i] = 'o';
case 10: i--; a[i] = 'd';
+ case 12: i--; a[i] = 'z';
case 16: i--; a[i] = 'x';
default: ok = false;
}
diff --git a/core/sync.odin b/core/sync.odin
index a2296c3b6..72f784f6d 100644
--- a/core/sync.odin
+++ b/core/sync.odin
@@ -2,7 +2,7 @@
#import "atomic.odin";
Semaphore :: struct {
- _handle: win32.HANDLE,
+ _handle: win32.Handle,
}
Mutex :: struct {
diff --git a/core/sys/wgl.odin b/core/sys/wgl.odin
index bf993ca58..9edbdda11 100644
--- a/core/sys/wgl.odin
+++ b/core/sys/wgl.odin
@@ -8,10 +8,10 @@ CONTEXT_PROFILE_MASK_ARB :: 0x9126;
CONTEXT_FORWARD_COMPATIBLE_BIT_ARB :: 0x0002;
CONTEXT_CORE_PROFILE_BIT_ARB :: 0x00000001;
-HGLRC :: HANDLE;
-COLORREF :: u32;
+Hglrc :: Handle;
+Color_Ref :: u32;
-LAYERPLANEDESCRIPTOR :: struct #ordered {
+Layer_Plane_Descriptor :: struct #ordered {
size: u16,
version: u16,
flags: u32,
@@ -35,38 +35,38 @@ LAYERPLANEDESCRIPTOR :: struct #ordered {
aux_buffers: byte,
layer_type: byte,
reserved: byte,
- transparent: COLORREF,
+ transparent: Color_Ref,
}
-POINTFLOAT :: struct #ordered {
+Point_Float :: struct #ordered {
x, y: f32,
}
-GLYPHMETRICSFLOAT :: struct #ordered {
+Glyph_Metrics_Float :: struct #ordered {
black_box_x: f32,
black_box_y: f32,
- glyph_origin: POINTFLOAT,
+ glyph_origin: Point_Float,
cell_inc_x: f32,
cell_inc_y: f32,
}
-CreateContextAttribsARBType :: #type proc(hdc: HDC, hshareContext: rawptr, attribList: ^i32) -> HGLRC;
-ChoosePixelFormatARBType :: #type proc(hdc: HDC, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> BOOL #cc_c;
+Create_Context_Attribs_ARB_Type :: #type proc(hdc: Hdc, hshareContext: rawptr, attribList: ^i32) -> Hglrc;
+Choose_Pixel_Format_ARB_Type :: #type proc(hdc: Hdc, attrib_i_list: ^i32, attrib_f_list: ^f32, max_formats: u32, formats: ^i32, num_formats : ^u32) -> Bool #cc_c;
-CreateContext :: proc(hdc: HDC) -> HGLRC #foreign opengl32 "wglCreateContext";
-MakeCurrent :: proc(hdc: HDC, hglrc: HGLRC) -> BOOL #foreign opengl32 "wglMakeCurrent";
-GetProcAddress :: proc(c_str: ^u8) -> PROC #foreign opengl32 "wglGetProcAddress";
-DeleteContext :: proc(hglrc: HGLRC) -> BOOL #foreign opengl32 "wglDeleteContext";
-CopyContext :: proc(src, dst: HGLRC, mask: u32) -> BOOL #foreign opengl32 "wglCopyContext";
-CreateLayerContext :: proc(hdc: HDC, layer_plane: i32) -> HGLRC #foreign opengl32 "wglCreateLayerContext";
-DescribeLayerPlane :: proc(hdc: HDC, pixel_format, layer_plane: i32, bytes: u32, pd: ^LAYERPLANEDESCRIPTOR) -> BOOL #foreign opengl32 "wglDescribeLayerPlane";
-GetCurrentContext :: proc() -> HGLRC #foreign opengl32 "wglGetCurrentContext";
-GetCurrentDC :: proc() -> HDC #foreign opengl32 "wglGetCurrentDC";
-GetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
-RealizeLayerPalette :: proc(hdc: HDC, layer_plane: i32, realize: BOOL) -> BOOL #foreign opengl32 "wglRealizeLayerPalette";
-SetLayerPaletteEntries :: proc(hdc: HDC, layer_plane, start, entries: i32, cr: ^COLORREF) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
-ShareLists :: proc(hglrc1, hglrc2: HGLRC) -> BOOL #foreign opengl32 "wglShareLists";
-SwapLayerBuffers :: proc(hdc: HDC, planes: u32) -> BOOL #foreign opengl32 "wglSwapLayerBuffers";
-UseFontBitmaps :: proc(hdc: HDC, first, count, list_base: u32) -> BOOL #foreign opengl32 "wglUseFontBitmaps";
-UseFontOutlines :: proc(hdc: HDC, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^GLYPHMETRICSFLOAT) -> BOOL #foreign opengl32 "wglUseFontOutlines";
+CreateContext :: proc(hdc: Hdc) -> Hglrc #foreign opengl32 "wglCreateContext";
+MakeCurrent :: proc(hdc: Hdc, hglrc: Hglrc) -> Bool #foreign opengl32 "wglMakeCurrent";
+GetProcAddress :: proc(c_str: ^u8) -> Proc #foreign opengl32 "wglGetProcAddress";
+DeleteContext :: proc(hglrc: Hglrc) -> Bool #foreign opengl32 "wglDeleteContext";
+CopyContext :: proc(src, dst: Hglrc, mask: u32) -> Bool #foreign opengl32 "wglCopyContext";
+CreateLayerContext :: proc(hdc: Hdc, layer_plane: i32) -> Hglrc #foreign opengl32 "wglCreateLayerContext";
+DescribeLayerPlane :: proc(hdc: Hdc, pixel_format, layer_plane: i32, bytes: u32, pd: ^Layer_Plane_Descriptor) -> Bool #foreign opengl32 "wglDescribeLayerPlane";
+GetCurrentContext :: proc() -> Hglrc #foreign opengl32 "wglGetCurrentContext";
+GetCurrentDC :: proc() -> Hdc #foreign opengl32 "wglGetCurrentDC";
+GetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglGetLayerPaletteEntries";
+RealizeLayerPalette :: proc(hdc: Hdc, layer_plane: i32, realize: Bool) -> Bool #foreign opengl32 "wglRealizeLayerPalette";
+SetLayerPaletteEntries :: proc(hdc: Hdc, layer_plane, start, entries: i32, cr: ^Color_Ref) -> i32 #foreign opengl32 "wglSetLayerPaletteEntries";
+ShareLists :: proc(hglrc1, hglrc2: Hglrc) -> Bool #foreign opengl32 "wglShareLists";
+SwapLayerBuffers :: proc(hdc: Hdc, planes: u32) -> Bool #foreign opengl32 "wglSwapLayerBuffers";
+UseFontBitmaps :: proc(hdc: Hdc, first, count, list_base: u32) -> Bool #foreign opengl32 "wglUseFontBitmaps";
+UseFontOutlines :: proc(hdc: Hdc, first, count, list_base: u32, deviation, extrusion: f32, format: i32, gmf: ^Glyph_Metrics_Float) -> Bool #foreign opengl32 "wglUseFontOutlines";
diff --git a/core/sys/windows.odin b/core/sys/windows.odin
index c9af1961a..2493a29e1 100644
--- a/core/sys/windows.odin
+++ b/core/sys/windows.odin
@@ -2,29 +2,29 @@
#foreign_system_library "user32.lib" when ODIN_OS == "windows";
#foreign_system_library "gdi32.lib" when ODIN_OS == "windows";
#foreign_system_library "winmm.lib" when ODIN_OS == "windows";
-
-HANDLE :: rawptr;
-HWND :: HANDLE;
-HDC :: HANDLE;
-HINSTANCE :: HANDLE;
-HICON :: HANDLE;
-HCURSOR :: HANDLE;
-HMENU :: HANDLE;
-HBRUSH :: HANDLE;
-HGDIOBJ :: HANDLE;
-HMODULE :: HANDLE;
-WPARAM :: uint;
-LPARAM :: int;
-LRESULT :: int;
-ATOM :: i16;
-BOOL :: i32;
-WNDPROC :: #type proc(HWND, u32, WPARAM, LPARAM) -> LRESULT #cc_c;
-
-
-INVALID_HANDLE_VALUE :: cast(HANDLE)~cast(int)0;
-
-FALSE: BOOL : 0;
-TRUE: BOOL : 1;
+#foreign_system_library "shell32.lib" when ODIN_OS == "windows";
+
+Handle :: rawptr;
+Hwnd :: Handle;
+Hdc :: Handle;
+Hinstance :: Handle;
+Hicon :: Handle;
+Hcursor :: Handle;
+Hmenu :: Handle;
+Hbrush :: Handle;
+Hgdiobj :: Handle;
+Hmodule :: Handle;
+Wparam :: uint;
+Lparam :: int;
+Lresult :: int;
+Bool :: i32;
+Wnd_Proc :: #type proc(Hwnd, u32, Wparam, Lparam) -> Lresult #cc_c;
+
+
+INVALID_HANDLE :: cast(Handle)~cast(int)0;
+
+FALSE: Bool : 0;
+TRUE: Bool : 1;
CS_VREDRAW :: 0x0001;
CS_HREDRAW :: 0x0002;
@@ -56,7 +56,7 @@ WM_CHAR :: 0x0102;
PM_REMOVE :: 1;
-COLOR_BACKGROUND :: cast(HBRUSH)(cast(int)1);
+COLOR_BACKGROUND :: cast(Hbrush)(cast(int)1);
BLACK_BRUSH :: 4;
SM_CXSCREEN :: 0;
@@ -65,53 +65,53 @@ SM_CYSCREEN :: 1;
SW_SHOW :: 5;
-POINT :: struct #ordered {
+Point :: struct #ordered {
x, y: i32,
}
-WNDCLASSEXA :: struct #ordered {
+WndClassExA :: struct #ordered {
size, style: u32,
- wnd_proc: WNDPROC,
+ wnd_proc: Wnd_Proc,
cls_extra, wnd_extra: i32,
- instance: HINSTANCE,
- icon: HICON,
- cursor: HCURSOR,
- background: HBRUSH,
+ instance: Hinstance,
+ icon: Hicon,
+ cursor: Hcursor,
+ background: Hbrush,
menu_name, class_name: ^u8,
- sm: HICON,
+ sm: Hicon,
}
-MSG :: struct #ordered {
- hwnd: HWND,
+Msg :: struct #ordered {
+ hwnd: Hwnd,
message: u32,
- wparam: WPARAM,
- lparam: LPARAM,
+ wparam: Wparam,
+ lparam: Lparam,
time: u32,
- pt: POINT,
+ pt: Point,
}
-RECT :: struct #ordered {
+Rect :: struct #ordered {
left: i32,
top: i32,
right: i32,
bottom: i32,
}
-FILETIME :: struct #ordered {
+Filetime :: struct #ordered {
lo, hi: u32,
}
-SYSTEMTIME :: struct #ordered {
+Systemtime :: struct #ordered {
year, month: u16,
day_of_week, day: u16,
hour, minute, second, millisecond: u16,
}
-BY_HANDLE_FILE_INFORMATION :: struct #ordered {
+By_Handle_File_Information :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
- last_write_time: FILETIME,
+ last_write_time: Filetime,
volume_serial_number,
file_size_high,
file_size_low,
@@ -120,11 +120,11 @@ BY_HANDLE_FILE_INFORMATION :: struct #ordered {
file_index_low: u32,
}
-FILE_ATTRIBUTE_DATA :: struct #ordered {
+File_Attribute_Data :: struct #ordered {
file_attributes: u32,
creation_time,
last_access_time,
- last_write_time: FILETIME,
+ last_write_time: Filetime,
file_size_high,
file_size_low: u32,
}
@@ -136,13 +136,13 @@ GetFileExMaxInfoLevel: GET_FILEEX_INFO_LEVELS : 1;
GetLastError :: proc() -> i32 #foreign kernel32;
ExitProcess :: proc(exit_code: u32) #foreign kernel32;
-GetDesktopWindow :: proc() -> HWND #foreign user32;
-GetCursorPos :: proc(p: ^POINT) -> i32 #foreign user32;
-ScreenToClient :: proc(h: HWND, p: ^POINT) -> i32 #foreign user32;
-GetModuleHandleA :: proc(module_name: ^u8) -> HINSTANCE #foreign kernel32;
-GetStockObject :: proc(fn_object: i32) -> HGDIOBJ #foreign gdi32;
+GetDesktopWindow :: proc() -> Hwnd #foreign user32;
+GetCursorPos :: proc(p: ^Point) -> i32 #foreign user32;
+ScreenToClient :: proc(h: Hwnd, p: ^Point) -> i32 #foreign user32;
+GetModuleHandleA :: proc(module_name: ^u8) -> Hinstance #foreign kernel32;
+GetStockObject :: proc(fn_object: i32) -> Hgdiobj #foreign gdi32;
PostQuitMessage :: proc(exit_code: i32) #foreign user32;
-SetWindowTextA :: proc(hwnd: HWND, c_string: ^u8) -> BOOL #foreign user32;
+SetWindowTextA :: proc(hwnd: Hwnd, c_string: ^u8) -> Bool #foreign user32;
QueryPerformanceFrequency :: proc(result: ^i64) -> i32 #foreign kernel32;
QueryPerformanceCounter :: proc(result: ^i64) -> i32 #foreign kernel32;
@@ -152,28 +152,28 @@ Sleep :: proc(ms: i32) -> i32 #foreign kernel32;
OutputDebugStringA :: proc(c_str: ^u8) #foreign kernel32;
-RegisterClassExA :: proc(wc: ^WNDCLASSEXA) -> ATOM #foreign user32;
+RegisterClassExA :: proc(wc: ^WndClassExA) -> i16 #foreign user32;
CreateWindowExA :: proc(ex_style: u32,
class_name, title: ^u8,
style: u32,
x, y, w, h: i32,
- parent: HWND, menu: HMENU, instance: HINSTANCE,
- param: rawptr) -> HWND #foreign user32;
+ parent: Hwnd, menu: Hmenu, instance: Hinstance,
+ param: rawptr) -> Hwnd #foreign user32;
-ShowWindow :: proc(hwnd: HWND, cmd_show: i32) -> BOOL #foreign user32;
-TranslateMessage :: proc(msg: ^MSG) -> BOOL #foreign user32;
-DispatchMessageA :: proc(msg: ^MSG) -> LRESULT #foreign user32;
-UpdateWindow :: proc(hwnd: HWND) -> BOOL #foreign user32;
-PeekMessageA :: proc(msg: ^MSG, hwnd: HWND,
- msg_filter_min, msg_filter_max, remove_msg: u32) -> BOOL #foreign user32;
+ShowWindow :: proc(hwnd: Hwnd, cmd_show: i32) -> Bool #foreign user32;
+TranslateMessage :: proc(msg: ^Msg) -> Bool #foreign user32;
+DispatchMessageA :: proc(msg: ^Msg) -> Lresult #foreign user32;
+UpdateWindow :: proc(hwnd: Hwnd) -> Bool #foreign user32;
+PeekMessageA :: proc(msg: ^Msg, hwnd: Hwnd,
+ msg_filter_min, msg_filter_max, remove_msg: u32) -> Bool #foreign user32;
-DefWindowProcA :: proc(hwnd: HWND, msg: u32, wparam: WPARAM, lparam: LPARAM) -> LRESULT #foreign user32;
+DefWindowProcA :: proc(hwnd: Hwnd, msg: u32, wparam: Wparam, lparam: Lparam) -> Lresult #foreign user32;
-AdjustWindowRect :: proc(rect: ^RECT, style: u32, menu: BOOL) -> BOOL #foreign user32;
-GetActiveWindow :: proc() -> HWND #foreign user32;
+AdjustWindowRect :: proc(rect: ^Rect, style: u32, menu: Bool) -> Bool #foreign user32;
+GetActiveWindow :: proc() -> Hwnd #foreign user32;
-DestroyWindow :: proc(wnd: HWND) -> BOOL #foreign user32;
-DescribePixelFormat :: proc(dc: HDC, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
+DestroyWindow :: proc(wnd: Hwnd) -> Bool #foreign user32;
+DescribePixelFormat :: proc(dc: Hdc, pixel_format: i32, bytes : u32, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign user32;
GetQueryPerformanceFrequency :: proc() -> i64 {
@@ -182,34 +182,36 @@ GetQueryPerformanceFrequency :: proc() -> i64 {
return r;
}
-GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
-GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
-GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
+GetCommandLineA :: proc() -> ^u8 #foreign kernel32;
+GetCommandLineW :: proc() -> ^u16 #foreign kernel32;
+GetSystemMetrics :: proc(index: i32) -> i32 #foreign kernel32;
+GetCurrentThreadId :: proc() -> u32 #foreign kernel32;
+CommandLineToArgvW :: proc(cmd_list: ^u16, num_args: ^i32) -> ^^u16 #foreign shell32;
-timeGetTime :: proc() -> u32 #foreign winmm;
-GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^FILETIME) #foreign kernel32;
-FileTimeToLocalFileTime :: proc(file_time: ^FILETIME, local_file_time: ^FILETIME) -> BOOL #foreign kernel32;
-FileTimeToSystemTime :: proc(file_time: ^FILETIME, system_time: ^SYSTEMTIME) -> BOOL #foreign kernel32;
-SystemTimeToFileTime :: proc(system_time: ^SYSTEMTIME, file_time: ^FILETIME) -> BOOL #foreign kernel32;
+timeGetTime :: proc() -> u32 #foreign winmm;
+GetSystemTimeAsFileTime :: proc(system_time_as_file_time: ^Filetime) #foreign kernel32;
+FileTimeToLocalFileTime :: proc(file_time: ^Filetime, local_file_time: ^Filetime) -> Bool #foreign kernel32;
+FileTimeToSystemTime :: proc(file_time: ^Filetime, system_time: ^Systemtime) -> Bool #foreign kernel32;
+SystemTimeToFileTime :: proc(system_time: ^Systemtime, file_time: ^Filetime) -> Bool #foreign kernel32;
// File Stuff
-CloseHandle :: proc(h: HANDLE) -> i32 #foreign kernel32;
-GetStdHandle :: proc(h: i32) -> HANDLE #foreign kernel32;
+CloseHandle :: proc(h: Handle) -> i32 #foreign kernel32;
+GetStdHandle :: proc(h: i32) -> Handle #foreign kernel32;
CreateFileA :: proc(filename: ^u8, desired_access, share_mode: u32,
security: rawptr,
- creation, flags_and_attribs: u32, template_file: HANDLE) -> HANDLE #foreign kernel32;
-ReadFile :: proc(h: HANDLE, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
-WriteFile :: proc(h: HANDLE, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> BOOL #foreign kernel32;
+ creation, flags_and_attribs: u32, template_file: Handle) -> Handle #foreign kernel32;
+ReadFile :: proc(h: Handle, buf: rawptr, to_read: u32, bytes_read: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
+WriteFile :: proc(h: Handle, buf: rawptr, len: i32, written_result: ^i32, overlapped: rawptr) -> Bool #foreign kernel32;
-GetFileSizeEx :: proc(file_handle: HANDLE, file_size: ^i64) -> BOOL #foreign kernel32;
-GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> BOOL #foreign kernel32;
-GetFileInformationByHandle :: proc(file_handle: HANDLE, file_info: ^BY_HANDLE_FILE_INFORMATION) -> BOOL #foreign kernel32;
+GetFileSizeEx :: proc(file_handle: Handle, file_size: ^i64) -> Bool #foreign kernel32;
+GetFileAttributesExA :: proc(filename: ^u8, info_level_id: GET_FILEEX_INFO_LEVELS, file_info: rawptr) -> Bool #foreign kernel32;
+GetFileInformationByHandle :: proc(file_handle: Handle, file_info: ^By_Handle_File_Information) -> Bool #foreign kernel32;
-GetFileType :: proc(file_handle: HANDLE) -> u32 #foreign kernel32;
-SetFilePointer :: proc(file_handle: HANDLE, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
+GetFileType :: proc(file_handle: Handle) -> u32 #foreign kernel32;
+SetFilePointer :: proc(file_handle: Handle, distance_to_move: i32, distance_to_move_high: ^i32, move_method: u32) -> u32 #foreign kernel32;
-SetHandleInformation :: proc(obj: HANDLE, mask, flags: u32) -> BOOL #foreign kernel32;
+SetHandleInformation :: proc(obj: Handle, mask, flags: u32) -> Bool #foreign kernel32;
HANDLE_FLAG_INHERIT :: 1;
HANDLE_FLAG_PROTECT_FROM_CLOSE :: 2;
@@ -242,13 +244,13 @@ TRUNCATE_EXISTING :: 5;
FILE_ATTRIBUTE_READONLY :: 0x00000001;
FILE_ATTRIBUTE_HIDDEN :: 0x00000002;
FILE_ATTRIBUTE_SYSTEM :: 0x00000004;
-FILE_ATTRIBUTE_DIRECTORY :: 0x00000010;
+FILE_ATTRIBUTE_DIRectORY :: 0x00000010;
FILE_ATTRIBUTE_ARCHIVE :: 0x00000020;
FILE_ATTRIBUTE_DEVICE :: 0x00000040;
FILE_ATTRIBUTE_NORMAL :: 0x00000080;
FILE_ATTRIBUTE_TEMPORARY :: 0x00000100;
FILE_ATTRIBUTE_SPARSE_FILE :: 0x00000200;
-FILE_ATTRIBUTE_REPARSE_POINT :: 0x00000400;
+FILE_ATTRIBUTE_REPARSE_Point :: 0x00000400;
FILE_ATTRIBUTE_COMPRESSED :: 0x00000800;
FILE_ATTRIBUTE_OFFLINE :: 0x00001000;
FILE_ATTRIBUTE_NOT_CONTENT_INDEXED :: 0x00002000;
@@ -263,27 +265,27 @@ INVALID_SET_FILE_POINTER :: ~cast(u32)0;
-HeapAlloc :: proc (h: HANDLE, flags: u32, bytes: int) -> rawptr #foreign kernel32;
-HeapReAlloc :: proc (h: HANDLE, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
-HeapFree :: proc (h: HANDLE, flags: u32, memory: rawptr) -> BOOL #foreign kernel32;
-GetProcessHeap :: proc () -> HANDLE #foreign kernel32;
+HeapAlloc :: proc (h: Handle, flags: u32, bytes: int) -> rawptr #foreign kernel32;
+HeapReAlloc :: proc (h: Handle, flags: u32, memory: rawptr, bytes: int) -> rawptr #foreign kernel32;
+HeapFree :: proc (h: Handle, flags: u32, memory: rawptr) -> Bool #foreign kernel32;
+GetProcessHeap :: proc () -> Handle #foreign kernel32;
HEAP_ZERO_MEMORY :: 0x00000008;
// Synchronization
-SECURITY_ATTRIBUTES :: struct #ordered {
+Security_Attributes :: struct #ordered {
length: u32,
security_descriptor: rawptr,
- inherit_handle: BOOL,
+ inherit_handle: Bool,
}
INFINITE :: 0xffffffff;
-CreateSemaphoreA :: proc(attributes: ^SECURITY_ATTRIBUTES, initial_count, maximum_count: i32, name: ^byte) -> HANDLE #foreign kernel32;
-ReleaseSemaphore :: proc(semaphore: HANDLE, release_count: i32, previous_count: ^i32) -> BOOL #foreign kernel32;
-WaitForSingleObject :: proc(handle: HANDLE, milliseconds: u32) -> u32 #foreign kernel32;
+CreateSemaphoreA :: proc(attributes: ^Security_Attributes, initial_count, maximum_count: i32, name: ^byte) -> Handle #foreign kernel32;
+ReleaseSemaphore :: proc(semaphore: Handle, release_count: i32, previous_count: ^i32) -> Bool #foreign kernel32;
+WaitForSingleObject :: proc(handle: Handle, milliseconds: u32) -> u32 #foreign kernel32;
InterlockedCompareExchange :: proc(dst: ^i32, exchange, comparand: i32) -> i32 #foreign kernel32;
@@ -307,11 +309,11 @@ ReadBarrier :: proc() #foreign kernel32;
-HMONITOR :: HANDLE;
+Hmonitor :: Handle;
GWL_STYLE :: -16;
-HWND_TOP :: cast(HWND)cast(uint)0;
+Hwnd_TOP :: cast(Hwnd)cast(uint)0;
MONITOR_DEFAULTTONULL :: 0x00000000;
MONITOR_DEFAULTTOPRIMARY :: 0x00000001;
@@ -324,39 +326,39 @@ SWP_NOSIZE :: 0x0001;
SWP_NOMOVE :: 0x0002;
-MONITORINFO :: struct #ordered {
+Monitor_Info :: struct #ordered {
size: u32,
- monitor: RECT,
- work: RECT,
+ monitor: Rect,
+ work: Rect,
flags: u32,
}
-WINDOWPLACEMENT :: struct #ordered {
+Window_Placement :: struct #ordered {
length: u32,
flags: u32,
show_cmd: u32,
- min_pos: POINT,
- max_pos: POINT,
- normal_pos: RECT,
+ min_pos: Point,
+ max_pos: Point,
+ normal_pos: Rect,
}
-GetMonitorInfoA :: proc(monitor: HMONITOR, mi: ^MONITORINFO) -> BOOL #foreign user32;
-MonitorFromWindow :: proc(wnd: HWND, flags : u32) -> HMONITOR #foreign user32;
+GetMonitorInfoA :: proc(monitor: Hmonitor, mi: ^Monitor_Info) -> Bool #foreign user32;
+MonitorFromWindow :: proc(wnd: Hwnd, flags : u32) -> Hmonitor #foreign user32;
-SetWindowPos :: proc(wnd: HWND, wndInsertAfter: HWND, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
+SetWindowPos :: proc(wnd: Hwnd, wndInsertAfter: Hwnd, x, y, width, height: i32, flags: u32) #foreign user32 "SetWindowPos";
-GetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
-SetWindowPlacement :: proc(wnd: HWND, wndpl: ^WINDOWPLACEMENT) -> BOOL #foreign user32;
+GetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
+SetWindowPlacement :: proc(wnd: Hwnd, wndpl: ^Window_Placement) -> Bool #foreign user32;
-GetWindowLongPtrA :: proc(wnd: HWND, index: i32) -> i64 #foreign user32;
-SetWindowLongPtrA :: proc(wnd: HWND, index: i32, new: i64) -> i64 #foreign user32;
+GetWindowLongPtrA :: proc(wnd: Hwnd, index: i32) -> i64 #foreign user32;
+SetWindowLongPtrA :: proc(wnd: Hwnd, index: i32, new: i64) -> i64 #foreign user32;
-GetWindowText :: proc(wnd: HWND, str: ^byte, maxCount: i32) -> i32 #foreign user32;
+GetWindowText :: proc(wnd: Hwnd, str: ^byte, maxCount: i32) -> i32 #foreign user32;
-HIWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
-HIWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
-LOWORD :: proc(wParam: WPARAM) -> u16 { return cast(u16)wParam; }
-LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
+HIWORD :: proc(wParam: Wparam) -> u16 { return cast(u16)((cast(u32)wParam >> 16) & 0xffff); }
+HIWORD :: proc(lParam: Lparam) -> u16 { return cast(u16)((cast(u32)lParam >> 16) & 0xffff); }
+LOWORD :: proc(wParam: Wparam) -> u16 { return cast(u16)wParam; }
+LOWORD :: proc(lParam: Lparam) -> u16 { return cast(u16)lParam; }
@@ -367,7 +369,7 @@ LOWORD :: proc(lParam: LPARAM) -> u16 { return cast(u16)lParam; }
-BITMAPINFOHEADER :: struct #ordered {
+Bitmap_Info_Header :: struct #ordered {
size: u32,
width, height: i32,
planes, bit_count: i16,
@@ -378,33 +380,33 @@ BITMAPINFOHEADER :: struct #ordered {
clr_used: u32,
clr_important: u32,
}
-BITMAPINFO :: struct #ordered {
- using header: BITMAPINFOHEADER,
- colors: [1]RGBQUAD,
+Bitmap_Info :: struct #ordered {
+ using header: Bitmap_Info_Header,
+ colors: [1]Rgb_Quad,
}
-RGBQUAD :: struct #ordered { blue, green, red, reserved: byte }
+Rgb_Quad :: struct #ordered { blue, green, red, reserved: byte }
BI_RGB :: 0;
DIB_RGB_COLORS :: 0x00;
SRCCOPY: u32 : 0x00cc0020;
-StretchDIBits :: proc (hdc: HDC,
+StretchDIBits :: proc (hdc: Hdc,
x_dst, y_dst, width_dst, height_dst: i32,
x_src, y_src, width_src, header_src: i32,
- bits: rawptr, bits_info: ^BITMAPINFO,
+ bits: rawptr, bits_info: ^Bitmap_Info,
usage: u32,
rop: u32) -> i32 #foreign gdi32;
-LoadLibraryA :: proc (c_str: ^u8) -> HMODULE #foreign kernel32;
-FreeLibrary :: proc (h: HMODULE) #foreign kernel32;
-GetProcAddress :: proc (h: HMODULE, c_str: ^u8) -> PROC #foreign kernel32;
+LoadLibraryA :: proc (c_str: ^u8) -> Hmodule #foreign kernel32;
+FreeLibrary :: proc (h: Hmodule) #foreign kernel32;
+GetProcAddress :: proc (h: Hmodule, c_str: ^u8) -> Proc #foreign kernel32;
-GetClientRect :: proc(hwnd: HWND, rect: ^RECT) -> BOOL #foreign user32;
+GetClientRect :: proc(hwnd: Hwnd, rect: ^Rect) -> Bool #foreign user32;
// Windows OpenGL
PFD_TYPE_RGBA :: 0;
@@ -461,14 +463,14 @@ PIXELFORMATDESCRIPTOR :: struct #ordered {
damage_mask: u32,
}
-GetDC :: proc(h: HWND) -> HDC #foreign user32;
-SetPixelFormat :: proc(hdc: HDC, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> BOOL #foreign gdi32;
-ChoosePixelFormat :: proc(hdc: HDC, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
-SwapBuffers :: proc(hdc: HDC) -> BOOL #foreign gdi32;
-ReleaseDC :: proc(wnd: HWND, hdc: HDC) -> i32 #foreign user32;
+GetDC :: proc(h: Hwnd) -> Hdc #foreign user32;
+SetPixelFormat :: proc(hdc: Hdc, pixel_format: i32, pfd: ^PIXELFORMATDESCRIPTOR) -> Bool #foreign gdi32;
+ChoosePixelFormat :: proc(hdc: Hdc, pfd: ^PIXELFORMATDESCRIPTOR) -> i32 #foreign gdi32;
+SwapBuffers :: proc(hdc: Hdc) -> Bool #foreign gdi32;
+ReleaseDC :: proc(wnd: Hwnd, hdc: Hdc) -> i32 #foreign user32;
-PROC :: #type proc() #cc_c;
+Proc :: #type proc() #cc_c;
GetKeyState :: proc(v_key: i32) -> i16 #foreign user32;
@@ -611,7 +613,7 @@ Key_Code :: enum i32 {
RCONTROL = 0xA3,
LMENU = 0xA4,
RMENU = 0xA5,
- PROCESSKEY = 0xE5,
+ ProcESSKEY = 0xE5,
ATTN = 0xF6,
CRSEL = 0xF7,
EXSEL = 0xF8,
diff --git a/compile_time_execution_problems.md b/misc/compile_time_execution_problems.md
index 8cfeca4e4..8cfeca4e4 100644
--- a/compile_time_execution_problems.md
+++ b/misc/compile_time_execution_problems.md
diff --git a/misc/lib_maker_clang.bat b/misc/lib_maker_clang.bat
new file mode 100644
index 000000000..14899f6ef
--- /dev/null
+++ b/misc/lib_maker_clang.bat
@@ -0,0 +1,11 @@
+@echo off
+setlocal EnableDelayedExpansion
+
+set file_input=%1
+set name=%1
+FOR %%f IN (name) do (
+ FOR %%g in (!%%f!) do set "%%f=%%~ng"
+)
+
+call clang -O2 -c %file_input% -o %name%.o ^
+ && call ar %name%.o -rcs %name%.lib
diff --git a/libs.txt b/misc/libs.txt
index f13b0fcc0..f13b0fcc0 100644
--- a/libs.txt
+++ b/misc/libs.txt
diff --git a/logo-slim.png b/misc/logo-slim.png
index 2b70e6a0c..2b70e6a0c 100644
--- a/logo-slim.png
+++ b/misc/logo-slim.png
Binary files differ
diff --git a/roadmap.md b/misc/roadmap.md
index 83fbbb695..83fbbb695 100644
--- a/roadmap.md
+++ b/misc/roadmap.md
diff --git a/todo.md b/misc/todo.md
index ab35c7830..ab35c7830 100644
--- a/todo.md
+++ b/misc/todo.md
diff --git a/run.bat b/run.bat
deleted file mode 100644
index b3fb31397..000000000
--- a/run.bat
+++ /dev/null
@@ -1,4 +0,0 @@
-@echo off
-
-
-rem call clang -c -emit-llvm -DGB_IMPLEMENTATION -DGB_DEF=GB_DLL_EXPORT ..\src\gb\gb.h
diff --git a/src/array.c b/src/array.c
index d169a99ef..bb9e789db 100644
--- a/src/array.c
+++ b/src/array.c
@@ -87,14 +87,8 @@ void array__set_capacity(void *ptr, isize capacity, isize element_size) {
x->count = capacity;
}
- {
- // TODO(bill): Resize rather than copy and delete
- void *new_data = gb_alloc(x->allocator, element_size*capacity);
- gb_memmove(new_data, x->e, element_size*x->count);
- gb_free(x->allocator, x->e);
- x->capacity = capacity;
- x->e = new_data;
- }
+ x->e = gb_resize(x->allocator, x->e, element_size*x->capacity, element_size*capacity);
+ x->capacity = capacity;
}
diff --git a/src/build_settings.c b/src/build_settings.c
index c50150827..6d7dbe939 100644
--- a/src/build_settings.c
+++ b/src/build_settings.c
@@ -264,7 +264,7 @@ String get_fullpath_core(gbAllocator a, String path) {
void init_build_context(void) {
BuildContext *bc = &build_context;
bc->ODIN_VENDOR = str_lit("odin");
- bc->ODIN_VERSION = str_lit("0.1.1");
+ bc->ODIN_VERSION = str_lit("0.1.3");
bc->ODIN_ROOT = odin_root_dir();
#if defined(GB_SYSTEM_WINDOWS)
diff --git a/src/check_decl.c b/src/check_decl.c
index bc49e36c1..12ce52142 100644
--- a/src/check_decl.c
+++ b/src/check_decl.c
@@ -12,6 +12,7 @@ Type *check_init_variable(Checker *c, Entity *e, Operand *operand, String contex
gbString expr_str = expr_to_string(operand->expr);
// TODO(bill): is this a good enough error message?
+ // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
@@ -276,12 +277,6 @@ void check_proc_lit(Checker *c, Entity *e, DeclInfo *d) {
error_node(pd->body, "A procedure tagged as `#foreign` cannot have a body");
}
- // TODO(bill): Is this the best option? What about passing to external shit?!
- // if (proc_type->Proc.calling_convention != ProcCC_Odin) {
- // error_node(d->proc_lit, "An internal procedure may only have the Odin calling convention");
- // proc_type->Proc.calling_convention = ProcCC_Odin;
- // }
-
d->scope = c->context.scope;
GB_ASSERT(pd->body->kind == AstNode_BlockStmt);
@@ -408,6 +403,56 @@ void check_var_decl(Checker *c, Entity *e, Entity **entities, isize entity_count
}
+void check_alias_decl(Checker *c, Entity *e, AstNode *expr) {
+ GB_ASSERT(e->type == NULL);
+ GB_ASSERT(e->kind == Entity_Alias);
+
+ if (e->flags & EntityFlag_Visited) {
+ e->type = t_invalid;
+ return;
+ }
+ e->flags |= EntityFlag_Visited;
+ e->type = t_invalid;
+
+ expr = unparen_expr(expr);
+
+ if (expr->kind == AstNode_Alias) {
+ error_node(expr, "#alias of an #alias is not allowed");
+ return;
+ }
+
+ if (expr->kind == AstNode_Ident) {
+ Operand o = {0};
+ Entity *f = check_ident(c, &o, expr, NULL, NULL, true);
+ if (f != NULL) {
+ e->Alias.original = f;
+ e->type = f->type;
+ }
+ return;
+ } else if (expr->kind == AstNode_SelectorExpr) {
+ Operand o = {0};
+ Entity *f = check_selector(c, &o, expr, NULL);
+ if (f != NULL) {
+ e->Alias.original = f;
+ e->type = f->type;
+ }
+ return;
+ }
+
+ Operand o = {0};
+ check_expr_or_type(c, &o, expr);
+ if (o.mode == Addressing_Invalid) {
+ return;
+ }
+ switch (o.mode) {
+ case Addressing_Type:
+ e->type = o.type;
+ break;
+ default:
+ error_node(expr, "#alias declarations only allow types");
+ }
+}
+
void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
if (e->type != NULL) {
return;
@@ -443,6 +488,9 @@ void check_entity_decl(Checker *c, Entity *e, DeclInfo *d, Type *named_type) {
case Entity_Procedure:
check_proc_lit(c, e, d);
break;
+ case Entity_Alias:
+ check_alias_decl(c, e, d->init_expr);
+ break;
}
c->context = prev;
diff --git a/src/check_expr.c b/src/check_expr.c
index 7e273fba4..fcb3e948e 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -272,6 +272,7 @@ void check_assignment(Checker *c, Operand *operand, Type *type, String context_n
if (operand->mode == Addressing_Builtin) {
// TODO(bill): is this a good enough error message?
+ // TODO(bill): Actually allow built in procedures to be passed around and thus be created on use
error_node(operand->expr,
"Cannot assign builtin procedure `%s` in %.*s",
expr_str,
@@ -379,7 +380,8 @@ isize check_fields(Checker *c, AstNode *node, AstNodeArray decls,
Entity **found = map_entity_get(&entity_map, key);
if (found != NULL) {
Entity *e = *found;
- // TODO(bill): Scope checking already checks the declaration
+ // NOTE(bill): Scope checking already checks the declaration but in many cases, this can happen so why not?
+ // This may be a little janky but it's not really that much of a problem
error(name_token, "`%.*s` is already declared in this type", LIT(name_token.string));
error(e->token, "\tpreviously declared");
} else {
@@ -604,16 +606,11 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
{
ast_node(fl, FieldList, f->list);
- // TODO(bill): Just do a gb_memcopy here
// NOTE(bill): Copy the contents for the common fields for now
AstNodeArray list = {0};
array_init_count(&list, c->allocator, ut->fields.count+fl->list.count);
- for (isize j = 0; j < ut->fields.count; j++) {
- list.e[j] = ut->fields.e[j];
- }
- for (isize j = 0; j < fl->list.count; j++) {
- list.e[j+ut->fields.count] = fl->list.e[j];
- }
+ gb_memmove_array(list.e, ut->fields.e, ut->fields.count);
+ gb_memmove_array(list.e+ut->fields.count, fl->list.e, fl->list.count);
isize list_count = 0;
for_array(j, list) {
@@ -654,7 +651,7 @@ void check_union_type(Checker *c, Type *union_type, AstNode *node) {
HashKey key = hash_string(name_token.string);
if (map_entity_get(&entity_map, key) != NULL) {
- // TODO(bill): Scope checking already checks the declaration
+ // NOTE(bill): Scope checking already checks the declaration
error(name_token, "`%.*s` is already declared in this union", LIT(name_token.string));
} else {
map_entity_set(&entity_map, key, e);
@@ -746,9 +743,9 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
constant_type = named_type;
}
- ExactValue iota = make_exact_value_integer(-1);
- ExactValue min_value = make_exact_value_integer(0);
- ExactValue max_value = make_exact_value_integer(0);
+ ExactValue iota = exact_value_integer(-1);
+ ExactValue min_value = exact_value_integer(0);
+ ExactValue max_value = exact_value_integer(0);
for_array(i, et->fields) {
AstNode *field = et->fields.e[i];
@@ -783,10 +780,10 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
if (o.mode != Addressing_Invalid) {
iota = o.value;
} else {
- iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
+ iota = exact_binary_operator_value(Token_Add, iota, exact_value_integer(1));
}
} else {
- iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
+ iota = exact_binary_operator_value(Token_Add, iota, exact_value_integer(1));
}
@@ -839,7 +836,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
enum_type->Record.field_count = field_count;
enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope,
- make_token_ident(str_lit("count")), t_int, make_exact_value_integer(field_count));
+ make_token_ident(str_lit("count")), t_int, exact_value_integer(field_count));
enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope,
make_token_ident(str_lit("min_value")), constant_type, min_value);
enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
@@ -1028,7 +1025,7 @@ void check_procedure_type(Checker *c, Type *type, AstNode *proc_type_node) {
}
-void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint) {
+Entity *check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *type_hint, bool allow_import_name) {
GB_ASSERT(n->kind == AstNode_Ident);
o->mode = Addressing_Invalid;
o->expr = n;
@@ -1046,7 +1043,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
if (named_type != NULL) {
set_base_type(named_type, t_invalid);
}
- return;
+ return NULL;
}
bool is_overloaded = false;
@@ -1095,7 +1092,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
o->type = t_invalid;
o->overload_count = overload_count;
o->overload_entities = procs;
- return;
+ return NULL;
}
gb_free(heap_allocator(), procs);
}
@@ -1106,20 +1103,26 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
if (e->type == NULL) {
compiler_error("Compiler error: How did this happen? type: %s; identifier: %.*s\n", type_to_string(e->type), LIT(name));
- return;
+ return NULL;
}
- Type *type = e->type;
+ e->flags |= EntityFlag_Used;
+ Entity *original_e = e;
+ while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) {
+ e = e->Alias.original;
+ }
+
+ Type *type = e->type;
switch (e->kind) {
case Entity_Constant:
if (type == t_invalid) {
o->type = t_invalid;
- return;
+ return e;
}
o->value = e->Constant.value;
if (o->value.kind == ExactValue_Invalid) {
- return;
+ return e;
}
o->mode = Addressing_Constant;
break;
@@ -1128,7 +1131,7 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
e->flags |= EntityFlag_Used;
if (type == t_invalid) {
o->type = t_invalid;
- return;
+ return e;
}
o->mode = Addressing_Variable;
if (e->Variable.is_immutable) {
@@ -1136,10 +1139,10 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
}
break;
- case Entity_TypeName: {
+ case Entity_TypeName:
+ // NOTE(bill): Cyclical dependency checking is handled in the "type system" not here
o->mode = Addressing_Type;
- // TODO(bill): Fix cyclical dependancy checker
- } break;
+ break;
case Entity_Procedure:
o->mode = Addressing_Value;
@@ -1151,22 +1154,29 @@ void check_ident(Checker *c, Operand *o, AstNode *n, Type *named_type, Type *typ
break;
case Entity_ImportName:
- error_node(n, "Use of import `%.*s` not in selector", LIT(e->ImportName.name));
- return;
+ if (!allow_import_name) {
+ error_node(n, "Use of import `%.*s` not in selector", LIT(name));
+ }
+ return e;
case Entity_LibraryName:
- error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(e->LibraryName.name));
- return;
+ error_node(n, "Use of library `%.*s` not in #foreign tag", LIT(name));
+ return e;
+
+ case Entity_Label:
+ o->mode = Addressing_NoValue;
+ break;
case Entity_Nil:
o->mode = Addressing_Value;
break;
default:
- compiler_error("Compiler error: Unknown EntityKind");
+ compiler_error("Unknown EntityKind");
break;
}
o->type = type;
+ return e;
}
i64 check_array_or_map_count(Checker *c, AstNode *e, bool is_map) {
@@ -1342,7 +1352,7 @@ Type *check_type_extra(Checker *c, AstNode *e, Type *named_type) {
switch (e->kind) {
case_ast_node(i, Ident, e);
Operand o = {0};
- check_ident(c, &o, e, named_type, NULL);
+ check_ident(c, &o, e, named_type, NULL, false);
switch (o.mode) {
case Addressing_Invalid:
@@ -1663,7 +1673,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
return true;
}
- type = base_type(base_enum_type(type));
+ type = core_type(type);
if (is_type_boolean(type)) {
return in_value.kind == ExactValue_Bool;
@@ -1682,7 +1692,7 @@ bool check_representable_as_constant(Checker *c, ExactValue in_value, Type *type
if (s < 64) {
umax = (1ull << s) - 1ull;
} else {
- // TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats
+ // IMPORTANT TODO(bill): I NEED A PROPER BIG NUMBER LIBRARY THAT CAN SUPPORT 128 bit integers and floats
s = 64;
}
i64 imax = (1ll << (s-1ll));
@@ -1860,7 +1870,7 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
}
x->mode = Addressing_Constant;
x->type = t_untyped_bool;
- x->value = make_exact_value_bool(comp);
+ x->value = exact_value_bool(comp);
return;
}
@@ -1913,10 +1923,11 @@ void check_comparison(Checker *c, Operand *x, Operand *y, TokenKind op) {
} else {
if (x->mode == Addressing_Constant &&
y->mode == Addressing_Constant) {
- x->value = make_exact_value_bool(compare_exact_values(op, x->value, y->value));
+ x->value = exact_value_bool(compare_exact_values(op, x->value, y->value));
} else {
x->mode = Addressing_Value;
+
update_expr_type(c, x->expr, default_type(x->type), true);
update_expr_type(c, y->expr, default_type(y->type), true);
}
@@ -1995,7 +2006,7 @@ void check_shift(Checker *c, Operand *x, Operand *y, AstNode *node) {
x->type = t_untyped_integer;
}
- x->value = exact_value_shift(be->op.kind, x_val, make_exact_value_integer(amount));
+ x->value = exact_value_shift(be->op.kind, x_val, exact_value_integer(amount));
if (is_type_typed(x->type)) {
check_is_expressible(c, x, base_type(x->type));
@@ -2094,7 +2105,7 @@ Operand check_ptr_addition(Checker *c, TokenKind op, Operand *ptr, Operand *offs
new_ptr_val -= elem_size*offset_val;
}
operand.mode = Addressing_Constant;
- operand.value = make_exact_value_pointer(new_ptr_val);
+ operand.value = exact_value_pointer(new_ptr_val);
}
return operand;
@@ -2108,8 +2119,8 @@ bool check_is_castable_to(Checker *c, Operand *operand, Type *y) {
}
Type *x = operand->type;
- Type *src = base_type(base_enum_type(x));
- Type *dst = base_type(base_enum_type(y));
+ Type *src = core_type(x);
+ Type *dst = core_type(y);
if (are_types_identical(src, dst)) {
return true;
}
@@ -2372,7 +2383,7 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
GB_ASSERT(op.kind == Token_Sub);
i64 bytes = a.value_pointer - b.value_pointer;
i64 diff = bytes/type_size_of(c->allocator, type);
- x->value = make_exact_value_pointer(diff);
+ x->value = exact_value_pointer(diff);
return;
}
@@ -2517,7 +2528,7 @@ void convert_to_typed(Checker *c, Operand *operand, Type *target_type, i32 level
return;
}
- Type *t = base_type(base_enum_type(target_type));
+ Type *t = core_type(target_type);
switch (t->kind) {
case Type_Basic:
if (operand->mode == Addressing_Constant) {
@@ -2678,6 +2689,11 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
add_entity_use(c, op_expr, e);
expr_entity = e;
+ Entity *original_e = e;
+ while (e != NULL && e->kind == Entity_Alias && e->Alias.original != NULL) {
+ e = e->Alias.original;
+ }
+
if (e != NULL && e->kind == Entity_ImportName && selector->kind == AstNode_Ident) {
// IMPORTANT NOTE(bill): This is very sloppy code but it's also very fragile
// It pretty much needs to be in this order and this way
@@ -2832,7 +2848,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
operand->type != NULL && is_type_untyped(operand->type) && is_type_string(operand->type)) {
String s = operand->value.value_string;
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(s.len);
+ operand->value = exact_value_integer(s.len);
operand->type = t_untyped_integer;
return NULL;
}
@@ -2869,7 +2885,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node, Type *type_h
operand->value = entity->Constant.value;
break;
case Entity_Variable:
- // TODO(bill): This is the rule I need?
+ // TODO(bill): Is this the rule I need?
if (operand->mode == Addressing_Immutable) {
// Okay
} else if (sel.indirect || operand->mode != Addressing_Value) {
@@ -3058,9 +3074,11 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
case BuiltinProc_clear: {
Type *type = operand->type;
- if (!is_type_dynamic_array(type) && !is_type_map(type)) {
+ bool is_pointer = is_type_pointer(type);
+ type = base_type(type_deref(type));
+ if (!is_type_dynamic_array(type) && !is_type_map(type) && !is_type_slice(type)) {
gbString str = type_to_string(type);
- error_node(operand->expr, "Expected a map or dynamic array, got `%s`", str);
+ error_node(operand->expr, "Invalid type for `clear`, got `%s`", str);
gb_string_free(str);
return false;
}
@@ -3092,14 +3110,12 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
}
Type *elem = NULL;
- Type *slice_elem = NULL;
if (is_type_dynamic_array(type)) {
- // TODO(bill): Semi-memory leaks
elem = type->DynamicArray.elem;
} else {
elem = type->Slice.elem;
}
- slice_elem = make_type_slice(c->allocator, elem);
+ Type *slice_elem = make_type_slice(c->allocator, elem);
Type *proc_type_params = make_type_tuple(c->allocator);
proc_type_params->Tuple.variables = gb_alloc_array(c->allocator, Entity *, 2);
@@ -3158,7 +3174,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
}
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(type_size_of(c->allocator, type));
+ operand->value = exact_value_integer(type_size_of(c->allocator, type));
operand->type = t_untyped_integer;
} break;
@@ -3171,7 +3187,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
}
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(type_size_of(c->allocator, operand->type));
+ operand->value = exact_value_integer(type_size_of(c->allocator, operand->type));
operand->type = t_untyped_integer;
break;
@@ -3183,7 +3199,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false;
}
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(type_align_of(c->allocator, type));
+ operand->value = exact_value_integer(type_align_of(c->allocator, type));
operand->type = t_untyped_integer;
} break;
@@ -3195,7 +3211,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
}
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(type_align_of(c->allocator, operand->type));
+ operand->value = exact_value_integer(type_align_of(c->allocator, operand->type));
operand->type = t_untyped_integer;
break;
@@ -3239,7 +3255,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
}
operand->mode = Addressing_Constant;
- operand->value = make_exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel));
+ operand->value = exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel));
operand->type = t_untyped_integer;
} break;
@@ -3288,7 +3304,7 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_Constant;
// IMPORTANT TODO(bill): Fix for anonymous fields
- operand->value = make_exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel));
+ operand->value = exact_value_integer(type_offset_of_from_selection(c->allocator, type, sel));
operand->type = t_untyped_integer;
} break;
@@ -3486,113 +3502,9 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
operand->mode = Addressing_Value;
} break;
-#if 0
- case BuiltinProc_ptr_offset: {
- // ptr_offset :: proc(ptr: ^T, offset: int) -> ^T
- // ^T cannot be rawptr
- Type *ptr_type = base_type(operand->type);
- if (!is_type_pointer(ptr_type)) {
- gbString type_str = type_to_string(operand->type);
- defer (gb_string_free(type_str));
- error_node(call,
- "Expected a pointer to `ptr_offset`, got `%s`",
- type_str);
- return false;
- }
-
- if (ptr_type == t_rawptr) {
- error_node(call,
- "`rawptr` cannot have pointer arithmetic");
- return false;
- }
-
- AstNode *offset = ce->args.e[1];
- Operand op = {0};
- check_expr(c, &op, offset);
- if (op.mode == Addressing_Invalid)
- return false;
- Type *offset_type = base_type(op.type);
- if (!is_type_integer(offset_type)) {
- error_node(op.expr, "Pointer offsets for `ptr_offset` must be an integer");
- return false;
- }
-
- if (operand->mode == Addressing_Constant &&
- op.mode == Addressing_Constant) {
- i64 ptr = operand->value.value_pointer;
- i64 elem_size = type_size_of(c->allocator, ptr_type->Pointer.elem);
- ptr += elem_size * op.value.value_integer;
- operand->value.value_pointer = ptr;
- } else {
- operand->mode = Addressing_Value;
- }
-
- } break;
-
- case BuiltinProc_ptr_sub: {
- // ptr_sub :: proc(a, b: ^T) -> int
- // ^T cannot be rawptr
- Type *ptr_type = base_type(operand->type);
- if (!is_type_pointer(ptr_type)) {
- gbString type_str = type_to_string(operand->type);
- defer (gb_string_free(type_str));
- error_node(call,
- "Expected a pointer to `ptr_add`, got `%s`",
- type_str);
- return false;
- }
-
- if (ptr_type == t_rawptr) {
- error_node(call,
- "`rawptr` cannot have pointer arithmetic");
- return false;
- }
- AstNode *offset = ce->args[1];
- Operand op = {0};
- check_expr(c, &op, offset);
- if (op.mode == Addressing_Invalid)
- return false;
- if (!is_type_pointer(op.type)) {
- gbString type_str = type_to_string(operand->type);
- defer (gb_string_free(type_str));
- error_node(call,
- "Expected a pointer to `ptr_add`, got `%s`",
- type_str);
- return false;
- }
-
- if (base_type(op.type) == t_rawptr) {
- error_node(call,
- "`rawptr` cannot have pointer arithmetic");
- return false;
- }
-
- if (!are_types_identical(operand->type, op.type)) {
- gbString a = type_to_string(operand->type);
- gbString b = type_to_string(op.type);
- defer (gb_string_free(a));
- defer (gb_string_free(b));
- error_node(op.expr,
- "`ptr_sub` requires to pointer of the same type. Got `%s` and `%s`.", a, b);
- return false;
- }
-
- operand->type = t_int;
-
- if (operand->mode == Addressing_Constant &&
- op.mode == Addressing_Constant) {
- u8 *ptr_a = cast(u8 *)operand->value.value_pointer;
- u8 *ptr_b = cast(u8 *)op.value.value_pointer;
- isize elem_size = type_size_of(c->allocator, ptr_type->Pointer.elem);
- operand->value = make_exact_value_integer((ptr_a - ptr_b) / elem_size);
- } else {
- operand->mode = Addressing_Value;
- }
- } break;
-#endif
-
case BuiltinProc_slice_ptr: {
// slice_ptr :: proc(a: ^T, len: int) -> []T
+ // slice_ptr :: proc(a: ^T, len, cap: int) -> []T
// ^T cannot be rawptr
Type *ptr_type = base_type(operand->type);
if (!is_type_pointer(ptr_type)) {
@@ -3610,21 +3522,28 @@ bool check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id
return false;
}
- AstNode *len = ce->args.e[1];
+ isize arg_count = ce->args.count;
+ if (arg_count < 2 || 3 < arg_count) {
+ error_node(ce->args.e[0], "`slice_ptr` expects 2 or 3 arguments, found %td", arg_count);
+ // NOTE(bill): Return the correct type to reduce errors
+ } else {
+ // If any are constant
+ i64 sizes[2] = {0};
+ isize size_count = 0;
+ for (isize i = 1; i < arg_count; i++) {
+ i64 val = 0;
+ bool ok = check_index_value(c, ce->args.e[i], -1, &val);
+ if (ok && val >= 0) {
+ GB_ASSERT(size_count < gb_count_of(sizes));
+ sizes[size_count++] = val;
+ }
+ }
- Operand op = {0};
- check_expr(c, &op, len);
- if (op.mode == Addressing_Invalid)
- return false;
- if (!is_type_integer(op.type)) {
- gbString type_str = type_to_string(operand->type);
- error_node(call,
- "Length for `slice_ptr` must be an integer, got `%s`",
- type_str);
- gb_string_free(type_str);
- return false;
+ if (size_count == 2 && sizes[0] > sizes[1]) {
+ error_node(ce->args.e[1], "`slice_ptr` count and capacity are swapped");
+ // No need quit
+ }
}
-
operand->type = make_type_slice(c->allocator, ptr_type->Pointer.elem);
operand->mode = Addressing_Value;
} break;
@@ -4412,7 +4331,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case_end;
case_ast_node(i, Ident, node);
- check_ident(c, o, node, NULL, type_hint);
+ check_ident(c, o, node, NULL, type_hint, false);
case_end;
case_ast_node(bl, BasicLit, node);
@@ -4426,24 +4345,24 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
}
o->mode = Addressing_Constant;
o->type = t;
- o->value = make_exact_value_from_basic_literal(*bl);
+ o->value = exact_value_from_basic_literal(*bl);
case_end;
case_ast_node(bd, BasicDirective, node);
if (str_eq(bd->name, str_lit("file"))) {
o->type = t_untyped_string;
- o->value = make_exact_value_string(bd->token.pos.file);
+ o->value = exact_value_string(bd->token.pos.file);
} else if (str_eq(bd->name, str_lit("line"))) {
o->type = t_untyped_integer;
- o->value = make_exact_value_integer(bd->token.pos.line);
+ o->value = exact_value_integer(bd->token.pos.line);
} else if (str_eq(bd->name, str_lit("procedure"))) {
if (c->proc_stack.count == 0) {
error_node(node, "#procedure may only be used within procedures");
o->type = t_untyped_string;
- o->value = make_exact_value_string(str_lit(""));
+ o->value = exact_value_string(str_lit(""));
} else {
o->type = t_untyped_string;
- o->value = make_exact_value_string(c->context.proc_name);
+ o->value = exact_value_string(c->context.proc_name);
}
} else {
@@ -4476,13 +4395,9 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
case_end;
case_ast_node(te, TernaryExpr, node);
- if (c->proc_stack.count == 0) {
- error_node(node, "A ternary expression is only allowed within a procedure");
- goto error;
- }
- Operand operand = {Addressing_Invalid};
- check_expr(c, &operand, te->cond);
- if (operand.mode != Addressing_Invalid && !is_type_boolean(operand.type)) {
+ Operand cond = {Addressing_Invalid};
+ check_expr(c, &cond, te->cond);
+ if (cond.mode != Addressing_Invalid && !is_type_boolean(cond.type)) {
error_node(te->cond, "Non-boolean condition in if expression");
}
@@ -4524,6 +4439,20 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
o->type = x.type;
o->mode = Addressing_Value;
+
+ if (cond.mode == Addressing_Constant && is_type_boolean(cond.type) &&
+ x.mode == Addressing_Constant &&
+ y.mode == Addressing_Constant) {
+
+ o->mode = Addressing_Constant;
+
+ if (cond.value.value_bool) {
+ o->value = x.value;
+ } else {
+ o->value = y.value;
+ }
+ }
+
case_end;
case_ast_node(cl, CompoundLit, node);
@@ -4850,7 +4779,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
if (is_constant) {
o->mode = Addressing_Constant;
- o->value = make_exact_value_compound(node);
+ o->value = exact_value_compound(node);
} else {
o->mode = Addressing_Value;
}
@@ -5625,7 +5554,7 @@ gbString write_expr_to_string(gbString str, AstNode *node) {
case_end;
case_ast_node(ht, HelperType, node);
- str = gb_string_appendc(str, "type ");
+ str = gb_string_appendc(str, "#type ");
str = write_expr_to_string(str, ht->type);
case_end;
}
diff --git a/src/check_stmt.c b/src/check_stmt.c
index 768410803..2eabaf798 100644
--- a/src/check_stmt.c
+++ b/src/check_stmt.c
@@ -307,16 +307,21 @@ Type *check_assignment_variable(Checker *c, Operand *rhs, AstNode *lhs_node) {
return rhs->type;
}
-bool check_valid_type_match_type(Type *type, bool *is_union_ptr, bool *is_any) {
- if (is_type_pointer(type)) {
- *is_union_ptr = is_type_union(type_deref(type));
- return *is_union_ptr;
+typedef enum MatchTypeKind {
+ MatchType_Invalid,
+ MatchType_Union,
+ MatchType_Any,
+} MatchTypeKind;
+
+MatchTypeKind check_valid_type_match_type(Type *type) {
+ type = type_deref(type);
+ if (is_type_union(type)) {
+ return MatchType_Union;
}
if (is_type_any(type)) {
- *is_any = true;
- return *is_any;
+ return MatchType_Any;
}
- return false;
+ return MatchType_Invalid;
}
void check_stmt_internal(Checker *c, AstNode *node, u32 flags);
@@ -385,6 +390,47 @@ void check_when_stmt(Checker *c, AstNodeWhenStmt *ws, u32 flags) {
}
}
+void check_label(Checker *c, AstNode *label) {
+ if (label == NULL) {
+ return;
+ }
+ ast_node(l, Label, label);
+ if (l->name->kind != AstNode_Ident) {
+ error_node(l->name, "A label's name must be an identifier");
+ return;
+ }
+ String name = l->name->Ident.string;
+ if (str_eq(name, str_lit("_"))) {
+ error_node(l->name, "A label's name cannot be a blank identifier");
+ return;
+ }
+
+
+ if (c->proc_stack.count == 0) {
+ error_node(l->name, "A label is only allowed within a procedure");
+ return;
+ }
+ GB_ASSERT(c->context.decl != NULL);
+
+ bool ok = true;
+ for_array(i, c->context.decl->labels) {
+ BlockLabel bl = c->context.decl->labels.e[i];
+ if (str_eq(bl.name, name)) {
+ error_node(label, "Duplicate label with the name `%.*s`", LIT(name));
+ ok = false;
+ break;
+ }
+ }
+
+ Entity *e = make_entity_label(c->allocator, c->context.scope, l->name->Ident, t_invalid, label);
+ add_entity(c, c->context.scope, l->name, e);
+
+ if (ok) {
+ BlockLabel bl = {name, label};
+ array_add(&c->context.decl->labels, bl);
+ }
+}
+
void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
u32 mod_flags = flags & (~Stmt_FallthroughAllowed);
switch (node->kind) {
@@ -475,9 +521,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
return;
}
- // TODO(bill): This is a very similar to check_init_variables, should I merge the two some how or just
- // leave it?
-
gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&c->tmp_arena);
// NOTE(bill): If there is a bad syntax error, rhs > lhs which would mean there would need to be
@@ -515,7 +558,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(op, "Unknown Assignment operation `%.*s`", LIT(op.string));
return;
}
- // TODO(bill): Check if valid assignment operator
Operand operand = {Addressing_Invalid};
AstNode binary_expr = {AstNode_BinaryExpr};
ast_node(be, BinaryExpr, &binary_expr);
@@ -580,7 +622,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
if (c->context.in_defer) {
error(rs->token, "You cannot `return` within a defer statement");
- // TODO(bill): Should I break here?
break;
}
@@ -619,7 +660,9 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case_ast_node(fs, ForStmt, node);
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
+
check_open_scope(c, node);
+ check_label(c, fs->label); // TODO(bill): What should the label's "scope" be?
if (fs->init != NULL) {
check_stmt(c, fs->init, 0);
@@ -648,6 +691,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
u32 new_flags = mod_flags | Stmt_BreakAllowed | Stmt_ContinueAllowed;
check_open_scope(c, node);
+ check_label(c, rs->label);
+
Type *val = NULL;
Type *idx = NULL;
Entity *entities[2] = {0};
@@ -718,7 +763,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
case Token_Ellipsis: op = Token_Lt; break;
default: error(ie->op, "Invalid range operator"); break;
}
- bool ok = compare_exact_values(Token_Lt, a, b);
+ bool ok = compare_exact_values(op, a, b);
if (!ok) {
// TODO(bill): Better error message
error(ie->op, "Invalid interval range");
@@ -850,7 +895,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
} else {
x.mode = Addressing_Constant;
x.type = t_bool;
- x.value = make_exact_value_bool(true);
+ x.value = exact_value_bool(true);
Token token = {0};
token.pos = ast_node_token(ms->body).pos;
@@ -897,7 +942,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
ast_node(cc, CaseClause, stmt);
-
for_array(j, cc->list) {
AstNode *expr = cc->list.e[j];
Operand y = {0};
@@ -982,8 +1026,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
mod_flags |= Stmt_BreakAllowed;
check_open_scope(c, node);
- bool is_union_ptr = false;
- bool is_any = false;
+ MatchTypeKind match_type_kind = MatchType_Invalid;
if (ms->tag->kind != AstNode_AssignStmt) {
error_node(ms->tag, "Expected an `in` assignment for this type match statement");
@@ -1005,7 +1048,8 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
check_expr(c, &x, rhs);
check_assignment(c, &x, NULL, str_lit("type match expression"));
- if (!check_valid_type_match_type(x.type, &is_union_ptr, &is_any)) {
+ match_type_kind = check_valid_type_match_type(x.type);
+ if (check_valid_type_match_type(x.type) == MatchType_Invalid) {
gbString str = type_to_string(x.type);
error_node(x.expr,
"Invalid type for this type match expression, got `%s`", str);
@@ -1013,7 +1057,6 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
break;
}
-
// NOTE(bill): Check for multiple defaults
AstNode *first_default = NULL;
ast_node(bs, BlockStmt, ms->body);
@@ -1048,7 +1091,7 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
}
- MapBool seen = {0};
+ MapBool seen = {0}; // Multimap
map_bool_init(&seen, heap_allocator());
for_array(i, bs->stmts) {
@@ -1062,74 +1105,68 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
// TODO(bill): Make robust
Type *bt = base_type(type_deref(x.type));
-
- AstNode *type_expr = cc->list.count > 0 ? cc->list.e[0] : NULL;
Type *case_type = NULL;
- if (type_expr != NULL) { // Otherwise it's a default expression
- Operand y = {0};
- check_expr_or_type(c, &y, type_expr);
-
- if (is_union_ptr) {
- GB_ASSERT(is_type_union(bt));
- bool tag_type_found = false;
- for (isize i = 0; i < bt->Record.variant_count; i++) {
- Entity *f = bt->Record.variants[i];
- if (are_types_identical(f->type, y.type)) {
- tag_type_found = true;
- break;
+ for_array(type_index, cc->list) {
+ AstNode *type_expr = cc->list.e[type_index];
+ if (type_expr != NULL) { // Otherwise it's a default expression
+ Operand y = {0};
+ check_expr_or_type(c, &y, type_expr);
+
+ if (match_type_kind == MatchType_Union) {
+ GB_ASSERT(is_type_union(bt));
+ bool tag_type_found = false;
+ for (isize i = 0; i < bt->Record.variant_count; i++) {
+ Entity *f = bt->Record.variants[i];
+ if (are_types_identical(f->type, y.type)) {
+ tag_type_found = true;
+ break;
+ }
}
+ if (!tag_type_found) {
+ gbString type_str = type_to_string(y.type);
+ error_node(y.expr, "Unknown tag type, got `%s`", type_str);
+ gb_string_free(type_str);
+ continue;
+ }
+ case_type = y.type;
+ } else if (match_type_kind == MatchType_Any) {
+ case_type = y.type;
+ } else {
+ GB_PANIC("Unknown type to type match statement");
}
- if (!tag_type_found) {
- gbString type_str = type_to_string(y.type);
- error_node(y.expr, "Unknown tag type, got `%s`", type_str);
- gb_string_free(type_str);
- continue;
- }
- case_type = y.type;
- } else if (is_any) {
- case_type = y.type;
- } else {
- GB_PANIC("Unknown type to type match statement");
- }
- HashKey key = hash_pointer(y.type);
- bool *found = map_bool_get(&seen, key);
- if (found) {
- TokenPos pos = cc->token.pos;
- gbString expr_str = expr_to_string(y.expr);
- error_node(y.expr,
- "Duplicate type case `%s`\n"
- "\tprevious type case at %.*s(%td:%td)",
- expr_str,
- LIT(pos.file), pos.line, pos.column);
- gb_string_free(expr_str);
- break;
+ HashKey key = hash_pointer(y.type);
+ bool *found = map_bool_get(&seen, key);
+ if (found) {
+ TokenPos pos = cc->token.pos;
+ gbString expr_str = expr_to_string(y.expr);
+ error_node(y.expr,
+ "Duplicate type case `%s`\n"
+ "\tprevious type case at %.*s(%td:%td)",
+ expr_str,
+ LIT(pos.file), pos.line, pos.column);
+ gb_string_free(expr_str);
+ break;
+ }
+ map_bool_set(&seen, key, cast(bool)true);
}
- map_bool_set(&seen, key, cast(bool)true);
}
- check_open_scope(c, stmt);
+ if (cc->list.count > 1) {
+ case_type = NULL;
+ }
if (case_type == NULL) {
- if (is_union_ptr) {
- case_type = type_deref(x.type);
- } else {
- case_type = x.type;
- }
+ case_type = x.type;
}
-
add_type_info_type(c, case_type);
+ check_open_scope(c, stmt);
{
- // NOTE(bill): Dummy type
- Type *tt = case_type;
- if (is_union_ptr) {
- tt = make_type_pointer(c->allocator, case_type);
- add_type_info_type(c, tt);
- }
- Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, tt, true);
+ Entity *tag_var = make_entity_variable(c->allocator, c->context.scope, lhs->Ident, case_type, true);
tag_var->flags |= EntityFlag_Used;
add_entity(c, c->context.scope, lhs, tag_var);
add_entity_use(c, lhs, tag_var);
+ add_implicit_entity(c, stmt, tag_var);
}
check_stmt_list(c, cc->stmts, mod_flags);
check_close_scope(c);
@@ -1173,20 +1210,38 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(token, "Invalid AST: Branch Statement `%.*s`", LIT(token.string));
break;
}
+
+ if (bs->label != NULL) {
+ if (bs->label->kind != AstNode_Ident) {
+ error_node(bs->label, "A branch statement's label name must be an identifier");
+ return;
+ }
+ AstNode *ident = bs->label;
+ String name = ident->Ident.string;
+ Entity *e = scope_lookup_entity(c->context.scope, name);
+ if (e == NULL) {
+ error_node(ident, "Undeclared label name: %.*s", LIT(name));
+ return;
+ }
+ add_entity_use(c, ident, e);
+ if (e->kind != Entity_Label) {
+ error_node(ident, "`%.*s` is not a label", LIT(name));
+ return;
+ }
+ }
+
case_end;
case_ast_node(us, UsingStmt, node);
- switch (us->node->kind) {
- default:
- // TODO(bill): Better error message for invalid using statement
- error(us->token, "Invalid `using` statement");
- break;
- case_ast_node(es, ExprStmt, us->node);
- // TODO(bill): Allow for just a LHS expression list rather than this silly code
+ if (us->list.count == 0) {
+ error(us->token, "Empty `using` list");
+ return;
+ }
+ for_array(i, us->list) {
+ AstNode *expr = unparen_expr(us->list.e[0]);
Entity *e = NULL;
bool is_selector = false;
- AstNode *expr = unparen_expr(es->expr);
if (expr->kind == AstNode_Ident) {
String name = expr->Ident.string;
e = scope_lookup_entity(c->context.scope, name);
@@ -1194,11 +1249,14 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
Operand o = {0};
e = check_selector(c, &o, expr, NULL);
is_selector = true;
+ } else if (expr->kind == AstNode_Implicit) {
+ error(us->token, "`using` applied to an implicit value");
+ continue;
}
if (e == NULL) {
error(us->token, "`using` applied to an unknown entity");
- return;
+ continue;
}
switch (e->kind) {
@@ -1296,6 +1354,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
error(us->token, "`using` cannot be applied to `nil`");
break;
+ case Entity_Label:
+ error(us->token, "`using` cannot be applied to a label");
+ break;
+
case Entity_Invalid:
error(us->token, "`using` cannot be applied to an invalid entity");
break;
@@ -1303,13 +1365,10 @@ void check_stmt_internal(Checker *c, AstNode *node, u32 flags) {
default:
GB_PANIC("TODO(bill): `using` other expressions?");
}
- case_end;
-
}
case_end;
-
case_ast_node(pa, PushAllocator, node);
Operand op = {0};
check_expr(c, &op, pa->expr);
diff --git a/src/checker.c b/src/checker.c
index ecb0f033b..e942916df 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -98,7 +98,7 @@ gb_global BuiltinProc builtin_procs[BuiltinProc_Count] = {
// {STR_LIT("ptr_offset"), 2, false, Expr_Expr},
// {STR_LIT("ptr_sub"), 2, false, Expr_Expr},
- {STR_LIT("slice_ptr"), 2, false, Expr_Expr},
+ {STR_LIT("slice_ptr"), 2, true, Expr_Expr},
{STR_LIT("slice_to_bytes"), 1, false, Expr_Stmt},
{STR_LIT("min"), 2, false, Expr_Expr},
@@ -163,6 +163,11 @@ bool is_operand_nil(Operand o) {
}
+typedef struct BlockLabel {
+ String name;
+ AstNode *label; // AstNode_Label;
+} BlockLabel;
+
// DeclInfo is used to store information of certain declarations to allow for "any order" usage
typedef struct DeclInfo {
Scope *scope;
@@ -175,16 +180,19 @@ typedef struct DeclInfo {
AstNode *proc_lit; // AstNode_ProcLit
MapBool deps; // Key: Entity *
+ Array(BlockLabel) labels;
} DeclInfo;
// ProcedureInfo stores the information needed for checking a procedure
+
+
typedef struct ProcedureInfo {
- AstFile * file;
- Token token;
- DeclInfo *decl;
- Type * type; // Type_Procedure
- AstNode * body; // AstNode_BlockStmt
- u32 tags;
+ AstFile * file;
+ Token token;
+ DeclInfo * decl;
+ Type * type; // Type_Procedure
+ AstNode * body; // AstNode_BlockStmt
+ u32 tags;
} ProcedureInfo;
// ExprInfo stores information used for "untyped" expressions
@@ -208,21 +216,21 @@ ExprInfo make_expr_info(bool is_lhs, AddressingMode mode, Type *type, ExactValue
#include "map.c"
typedef struct Scope {
- Scope * parent;
- Scope * prev, *next;
- Scope * first_child;
- Scope * last_child;
- MapEntity elements; // Key: String
- MapBool implicit; // Key: Entity *
-
- Array(Scope *) shared;
- Array(Scope *) imported;
- bool is_proc;
- bool is_global;
- bool is_file;
- bool is_init;
- bool has_been_imported; // This is only applicable to file scopes
- AstFile * file;
+ Scope * parent;
+ Scope * prev, *next;
+ Scope * first_child;
+ Scope * last_child;
+ MapEntity elements; // Key: String
+ MapBool implicit; // Key: Entity *
+
+ Array(Scope *) shared;
+ Array(Scope *) imported;
+ bool is_proc;
+ bool is_global;
+ bool is_file;
+ bool is_init;
+ bool has_been_imported; // This is only applicable to file scopes
+ AstFile * file;
} Scope;
gb_global Scope *universal_scope = NULL;
@@ -278,6 +286,7 @@ typedef struct CheckerInfo {
MapScope scopes; // Key: AstNode * | Node -> Scope
MapExprInfo untyped; // Key: AstNode * | Expression -> ExprInfo
MapDeclInfo entities; // Key: Entity *
+ MapEntity implicits; // Key: AstNode *
MapEntity foreigns; // Key: String
MapAstFile files; // Key: String (full path)
MapIsize type_info_map; // Key: Type *
@@ -320,6 +329,7 @@ typedef Array(DelayedEntity) DelayedEntities;
void init_declaration_info(DeclInfo *d, Scope *scope) {
d->scope = scope;
map_bool_init(&d->deps, heap_allocator());
+ array_init(&d->labels, heap_allocator());
}
DeclInfo *make_declaration_info(gbAllocator a, Scope *scope) {
@@ -357,9 +367,9 @@ Scope *make_scope(Scope *parent, gbAllocator allocator) {
Scope *s = gb_alloc_item(allocator, Scope);
s->parent = parent;
map_entity_init(&s->elements, heap_allocator());
- map_bool_init(&s->implicit, heap_allocator());
- array_init(&s->shared, heap_allocator());
- array_init(&s->imported, heap_allocator());
+ map_bool_init(&s->implicit, heap_allocator());
+ array_init(&s->shared, heap_allocator());
+ array_init(&s->imported, heap_allocator());
if (parent != NULL && parent != universal_scope) {
DLIST_APPEND(parent->first_child, parent->last_child, s);
@@ -455,6 +465,9 @@ void scope_lookup_parent_entity(Scope *scope, String name, Scope **scope_, Entit
if (found) {
Entity *e = *found;
if (gone_thru_proc) {
+ if (e->kind == Entity_Label) {
+ continue;
+ }
if (e->kind == Entity_Variable &&
!e->scope->is_file &&
!e->scope->is_global) {
@@ -596,7 +609,7 @@ void add_global_constant(gbAllocator a, String name, Type *type, ExactValue valu
void add_global_string_constant(gbAllocator a, String name, String value) {
- add_global_constant(a, name, t_untyped_string, make_exact_value_string(value));
+ add_global_constant(a, name, t_untyped_string, exact_value_string(value));
}
@@ -616,8 +629,8 @@ void init_universal_scope(void) {
}
// Constants
- add_global_constant(a, str_lit("true"), t_untyped_bool, make_exact_value_bool(true));
- add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false));
+ add_global_constant(a, str_lit("true"), t_untyped_bool, exact_value_bool(true));
+ add_global_constant(a, str_lit("false"), t_untyped_bool, exact_value_bool(false));
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
add_global_entity(make_entity_library_name(a, universal_scope,
@@ -662,6 +675,7 @@ void init_checker_info(CheckerInfo *i) {
map_decl_info_init(&i->entities, a);
map_expr_info_init(&i->untyped, a);
map_entity_init(&i->foreigns, a);
+ map_entity_init(&i->implicits, a);
map_isize_init(&i->type_info_map, a);
map_ast_file_init(&i->files, a);
i->type_info_count = 0;
@@ -676,6 +690,7 @@ void destroy_checker_info(CheckerInfo *i) {
map_decl_info_destroy(&i->entities);
map_expr_info_destroy(&i->untyped);
map_entity_destroy(&i->foreigns);
+ map_entity_destroy(&i->implicits);
map_isize_destroy(&i->type_info_map);
map_ast_file_destroy(&i->files);
}
@@ -816,7 +831,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
- "Redeclararation of `%.*s` in this scope through `using`\n"
+ "Redeclaration of `%.*s` in this scope through `using`\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(up->token.pos.file), up->token.pos.line, up->token.pos.column);
@@ -827,7 +842,7 @@ bool add_entity(Checker *c, Scope *scope, AstNode *identifier, Entity *entity) {
return false;
}
error(entity->token,
- "Redeclararation of `%.*s` in this scope\n"
+ "Redeclaration of `%.*s` in this scope\n"
"\tat %.*s(%td:%td)",
LIT(name),
LIT(pos.file), pos.line, pos.column);
@@ -861,6 +876,12 @@ void add_entity_and_decl_info(Checker *c, AstNode *identifier, Entity *e, DeclIn
}
+void add_implicit_entity(Checker *c, AstNode *node, Entity *e) {
+ GB_ASSERT(node != NULL);
+ GB_ASSERT(e != NULL);
+ map_entity_set(&c->info.implicits, hash_pointer(node), e);
+}
+
void add_type_info_type(Checker *c, Type *t) {
if (t == NULL) {
@@ -1467,7 +1488,12 @@ void check_collect_entities(Checker *c, AstNodeArray nodes, bool is_file_scope)
// TODO(bill): What if vd->type != NULL??? How to handle this case?
d->type_expr = init;
d->init_expr = init;
- } else if (init != NULL && up_init->kind == AstNode_ProcLit) {
+ } else if (up_init != NULL && up_init->kind == AstNode_Alias) {
+ error_node(up_init, "#alias declarations are not yet supported");
+ continue;
+ // e = make_entity_alias(c->allocator, d->scope, name->Ident, NULL, NULL);
+ // d->init_expr = init->Alias.expr;
+ }else if (init != NULL && up_init->kind == AstNode_ProcLit) {
e = make_entity_procedure(c->allocator, d->scope, name->Ident, NULL, up_init->ProcLit.tags);
d->proc_lit = up_init;
d->type_expr = vd->type;
diff --git a/src/entity.c b/src/entity.c
index 32d070953..aa1b8f52a 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -13,13 +13,15 @@ typedef struct Type Type;
ENTITY_KIND(Builtin) \
ENTITY_KIND(ImportName) \
ENTITY_KIND(LibraryName) \
+ ENTITY_KIND(Alias) \
ENTITY_KIND(Nil) \
- ENTITY_KIND(Count)
+ ENTITY_KIND(Label)
typedef enum EntityKind {
#define ENTITY_KIND(k) GB_JOIN2(Entity_, k),
ENTITY_KINDS
#undef ENTITY_KIND
+ Entity_Count,
} EntityKind;
String const entity_strings[] = {
@@ -95,7 +97,14 @@ struct Entity {
String name;
bool used;
} LibraryName;
+ struct {
+ Entity *original;
+ } Alias;
i32 Nil;
+ struct {
+ String name;
+ AstNode *node;
+ } Label;
};
};
@@ -218,12 +227,28 @@ Entity *make_entity_library_name(gbAllocator a, Scope *scope, Token token, Type
return entity;
}
+Entity *make_entity_alias(gbAllocator a, Scope *scope, Token token, Type *type,
+ Entity *original) {
+ Entity *entity = alloc_entity(a, Entity_Alias, scope, token, type);
+ entity->Alias.original = original;
+ return entity;
+}
+
Entity *make_entity_nil(gbAllocator a, String name, Type *type) {
Token token = make_token_ident(name);
Entity *entity = alloc_entity(a, Entity_Nil, NULL, token, type);
return entity;
}
+Entity *make_entity_label(gbAllocator a, Scope *scope, Token token, Type *type,
+ AstNode *node) {
+ Entity *entity = alloc_entity(a, Entity_Label, scope, token, type);
+ entity->Label.node = node;
+ return entity;
+}
+
+
+
Entity *make_entity_dummy_variable(gbAllocator a, Scope *scope, Token token) {
token.string = str_lit("_");
return make_entity_variable(a, scope, token, NULL, false);
diff --git a/src/exact_value.c b/src/exact_value.c
index 57c8ae81d..7e8e69f50 100644
--- a/src/exact_value.c
+++ b/src/exact_value.c
@@ -35,45 +35,45 @@ HashKey hash_exact_value(ExactValue v) {
}
-ExactValue make_exact_value_compound(AstNode *node) {
+ExactValue exact_value_compound(AstNode *node) {
ExactValue result = {ExactValue_Compound};
result.value_compound = node;
return result;
}
-ExactValue make_exact_value_bool(bool b) {
+ExactValue exact_value_bool(bool b) {
ExactValue result = {ExactValue_Bool};
result.value_bool = (b != 0);
return result;
}
-ExactValue make_exact_value_string(String string) {
+ExactValue exact_value_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
ExactValue result = {ExactValue_String};
result.value_string = string;
return result;
}
-ExactValue make_exact_value_integer(i64 i) {
+ExactValue exact_value_integer(i64 i) {
ExactValue result = {ExactValue_Integer};
result.value_integer = i;
return result;
}
-ExactValue make_exact_value_float(f64 f) {
+ExactValue exact_value_float(f64 f) {
ExactValue result = {ExactValue_Float};
result.value_float = f;
return result;
}
-ExactValue make_exact_value_pointer(i64 ptr) {
+ExactValue exact_value_pointer(i64 ptr) {
ExactValue result = {ExactValue_Pointer};
result.value_pointer = ptr;
return result;
}
-ExactValue make_exact_value_integer_from_string(String string) {
+ExactValue exact_value_integer_from_string(String string) {
// TODO(bill): Allow for numbers with underscores in them
i32 base = 10;
bool has_prefix = false;
@@ -82,6 +82,7 @@ ExactValue make_exact_value_integer_from_string(String string) {
case 'b': base = 2; has_prefix = true; break;
case 'o': base = 8; has_prefix = true; break;
case 'd': base = 10; has_prefix = true; break;
+ case 'z': base = 12; has_prefix = true; break;
case 'x': base = 16; has_prefix = true; break;
}
}
@@ -100,25 +101,21 @@ ExactValue make_exact_value_integer_from_string(String string) {
continue;
}
i64 v = 0;
- if (gb_char_is_digit(r)) {
- v = r - '0';
- } else if (gb_char_is_hex_digit(r)) {
- v = gb_hex_digit_to_int(r);
- } else {
+ v = digit_value(r);
+ if (v >= base) {
break;
}
-
result *= base;
result += v;
}
- return make_exact_value_integer(result);
+ return exact_value_integer(result);
}
-ExactValue make_exact_value_float_from_string(String string) {
+ExactValue exact_value_float_from_string(String string) {
isize i = 0;
u8 *str = string.text;
isize len = string.len;
@@ -137,10 +134,10 @@ ExactValue make_exact_value_float_from_string(String string) {
if (r == '_') {
continue;
}
- if (!gb_char_is_digit(r)) {
+ i64 v = digit_value(r);
+ if (v >= 10) {
break;
}
- i64 v = r - '0';
value *= 10.0;
value += v;
}
@@ -153,29 +150,38 @@ ExactValue make_exact_value_float_from_string(String string) {
if (r == '_') {
continue;
}
- if (!gb_char_is_digit(r)) {
+ i64 v = digit_value(r);
+ if (v >= 10) {
break;
}
- value += (r-'0')/pow10;
+ value += v/pow10;
pow10 *= 10.0;
}
}
- f64 frac = 0;
+ bool frac = false;
f64 scale = 1.0;
if ((str[i] == 'e') || (str[i] == 'E')) {
i++;
if (str[i] == '-') {
- frac = 1;
+ frac = true;
i++;
} else if (str[i] == '+') {
i++;
}
- u32 exp;
- for (exp = 0; gb_char_is_digit(str[i]); i++) {
- exp = exp * 10 + (str[i]-'0');
+ u32 exp = 0;
+ for (; i < len; i++) {
+ Rune r = cast(Rune)str[i];
+ if (r == '_') {
+ continue;
+ }
+ u32 d = cast(u32)digit_value(r);
+ if (d >= 10) {
+ break;
+ }
+ exp = exp * 10 + d;
}
if (exp > 308) exp = 308;
@@ -185,20 +191,20 @@ ExactValue make_exact_value_float_from_string(String string) {
}
f64 result = sign * (frac ? (value / scale) : (value * scale));
- return make_exact_value_float(result);
+ return exact_value_float(result);
}
-ExactValue make_exact_value_from_basic_literal(Token token) {
+ExactValue exact_value_from_basic_literal(Token token) {
switch (token.kind) {
- case Token_String: return make_exact_value_string(token.string);
- case Token_Integer: return make_exact_value_integer_from_string(token.string);
- case Token_Float: return make_exact_value_float_from_string(token.string);
+ case Token_String: return exact_value_string(token.string);
+ case Token_Integer: return exact_value_integer_from_string(token.string);
+ case Token_Float: return exact_value_float_from_string(token.string);
case Token_Rune: {
Rune r = GB_RUNE_INVALID;
gb_utf8_decode(token.string.text, token.string.len, &r);
// gb_printf("%.*s rune: %d\n", LIT(token.string), r);
- return make_exact_value_integer(r);
+ return exact_value_integer(r);
}
default:
GB_PANIC("Invalid token for basic literal");
@@ -217,12 +223,12 @@ ExactValue exact_value_to_integer(ExactValue v) {
i64 i = cast(i64)v.value_float;
f64 f = cast(f64)i;
if (f == v.value_float) {
- return make_exact_value_integer(i);
+ return exact_value_integer(i);
}
} break;
case ExactValue_Pointer:
- return make_exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
+ return exact_value_integer(cast(i64)cast(intptr)v.value_pointer);
}
ExactValue r = {ExactValue_Invalid};
return r;
@@ -231,7 +237,7 @@ ExactValue exact_value_to_integer(ExactValue v) {
ExactValue exact_value_to_float(ExactValue v) {
switch (v.kind) {
case ExactValue_Integer:
- return make_exact_value_float(cast(i64)v.value_integer);
+ return exact_value_float(cast(i64)v.value_integer);
case ExactValue_Float:
return v;
}
@@ -287,14 +293,14 @@ ExactValue exact_unary_operator_value(TokenKind op, ExactValue v, i32 precision)
i &= ~((~0ll)<<precision);
}
- return make_exact_value_integer(i);
+ return exact_value_integer(i);
} break;
case Token_Not: {
switch (v.kind) {
case ExactValue_Invalid: return v;
case ExactValue_Bool:
- return make_exact_value_bool(!v.value_bool);
+ return exact_value_bool(!v.value_bool);
}
} break;
}
@@ -348,7 +354,7 @@ void match_exact_values(ExactValue *x, ExactValue *y) {
return;
case ExactValue_Float:
// TODO(bill): Is this good enough?
- *x = make_exact_value_float(cast(f64)x->value_integer);
+ *x = exact_value_float(cast(f64)x->value_integer);
return;
}
break;
@@ -372,10 +378,10 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case ExactValue_Bool:
switch (op) {
- case Token_CmpAnd: return make_exact_value_bool(x.value_bool && y.value_bool);
- case Token_CmpOr: return make_exact_value_bool(x.value_bool || y.value_bool);
- case Token_And: return make_exact_value_bool(x.value_bool & y.value_bool);
- case Token_Or: return make_exact_value_bool(x.value_bool | y.value_bool);
+ case Token_CmpAnd: return exact_value_bool(x.value_bool && y.value_bool);
+ case Token_CmpOr: return exact_value_bool(x.value_bool || y.value_bool);
+ case Token_And: return exact_value_bool(x.value_bool & y.value_bool);
+ case Token_Or: return exact_value_bool(x.value_bool | y.value_bool);
default: goto error;
}
break;
@@ -388,7 +394,7 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
case Token_Add: c = a + b; break;
case Token_Sub: c = a - b; break;
case Token_Mul: c = a * b; break;
- case Token_Quo: return make_exact_value_float(fmod(cast(f64)a, cast(f64)b));
+ case Token_Quo: return exact_value_float(fmod(cast(f64)a, cast(f64)b));
case Token_QuoEq: c = a / b; break; // NOTE(bill): Integer division
case Token_Mod: c = a % b; break;
case Token_And: c = a & b; break;
@@ -400,17 +406,17 @@ ExactValue exact_binary_operator_value(TokenKind op, ExactValue x, ExactValue y)
default: goto error;
}
- return make_exact_value_integer(c);
+ return exact_value_integer(c);
} break;
case ExactValue_Float: {
f64 a = x.value_float;
f64 b = y.value_float;
switch (op) {
- case Token_Add: return make_exact_value_float(a + b);
- case Token_Sub: return make_exact_value_float(a - b);
- case Token_Mul: return make_exact_value_float(a * b);
- case Token_Quo: return make_exact_value_float(a / b);
+ case Token_Add: return exact_value_float(a + b);
+ case Token_Sub: return exact_value_float(a - b);
+ case Token_Mul: return exact_value_float(a * b);
+ case Token_Quo: return exact_value_float(a / b);
default: goto error;
}
} break;
diff --git a/src/gb/gb.h b/src/gb/gb.h
index c2462f260..5b839fecf 100644
--- a/src/gb/gb.h
+++ b/src/gb/gb.h
@@ -1,4 +1,4 @@
-/* gb.h - v0.27 - Ginger Bill's C Helper Library - public domain
+/* gb.h - v0.28 - Ginger Bill's C Helper Library - public domain
- no warranty implied; use at your own risk
This is a single header file with a bunch of useful stuff
@@ -58,6 +58,7 @@ TODOS
- More date & time functions
VERSION HISTORY
+ 0.28 - Handle UCS2 correctly in Win32 part
0.27 - OSX fixes and Linux gbAffinity
0.26d - Minor changes to how gbFile works
0.26c - gb_str_to_f* fix
@@ -806,6 +807,14 @@ GB_DEF void const *gb_memchr (void const *data, u8 byte_value, isize size);
GB_DEF void const *gb_memrchr (void const *data, u8 byte_value, isize size);
+#ifndef gb_memcopy_array
+#define gb_memcopy_array(dst, src, count) gb_memcopy((dst), (src), gb_size_of(*(dst))*(count))
+#endif
+
+#ifndef gb_memmove_array
+#define gb_memmove_array(dst, src, count) gb_memmove((dst), (src), gb_size_of(*(dst))*(count))
+#endif
+
// NOTE(bill): Very similar to doing `*cast(T *)(&u)`
#ifndef GB_BIT_CAST
#define GB_BIT_CAST(dest, source) do { \
@@ -1925,6 +1934,7 @@ typedef enum gbSeekWhenceType {
typedef enum gbFileError {
gbFileError_None,
gbFileError_Invalid,
+ gbFileError_InvalidFilename,
gbFileError_Exists,
gbFileError_NotExists,
gbFileError_Permission,
@@ -3238,6 +3248,8 @@ extern "C" {
#define STD_OUTPUT_HANDLE ((DWORD)-11)
#define STD_ERROR_HANDLE ((DWORD)-12)
+ GB_DLL_IMPORT int MultiByteToWideChar(UINT code_page, DWORD flags, char const * multi_byte_str, int multi_byte_len, wchar_t const *wide_char_str, int wide_char_len);
+ GB_DLL_IMPORT int WideCharToMultiByte(UINT code_page, DWORD flags, wchar_t const *wide_char_str, int wide_char_len, char const * multi_byte_str, int multi_byte_len);
GB_DLL_IMPORT BOOL WINAPI SetFilePointerEx(HANDLE file, LARGE_INTEGER distance_to_move,
LARGE_INTEGER *new_file_pointer, DWORD move_method);
GB_DLL_IMPORT BOOL WINAPI ReadFile (HANDLE file, void *buffer, DWORD bytes_to_read, DWORD *bytes_read, OVERLAPPED *overlapped);
@@ -3646,8 +3658,9 @@ gb_inline void *gb_memcopy(void *dest, void const *source, isize n) {
u8 const *s = cast(u8 const *)source;
u32 w, x;
- for (; cast(uintptr)s % 4 && n; n--)
+ for (; cast(uintptr)s % 4 && n; n--) {
*d++ = *s++;
+ }
if (cast(uintptr)d % 4 == 0) {
for (; n >= 16;
@@ -5442,8 +5455,9 @@ GB_ALLOCATOR_PROC(gb_pool_allocator_proc) {
gb_inline gbAllocationHeader *gb_allocation_header(void *data) {
isize *p = cast(isize *)data;
- while (p[-1] == cast(isize)(-1))
+ while (p[-1] == cast(isize)(-1)) {
p--;
+ }
return cast(gbAllocationHeader *)p - 1;
}
@@ -5451,8 +5465,9 @@ gb_inline void gb_allocation_header_fill(gbAllocationHeader *header, void *data,
isize *ptr;
header->size = size;
ptr = cast(isize *)(header + 1);
- while (cast(void *)ptr < data)
+ while (cast(void *)ptr < data) {
*ptr++ = cast(isize)(-1);
+ }
}
@@ -5895,8 +5910,9 @@ void gb_shuffle(void *base, isize count, isize size) {
void gb_reverse(void *base, isize count, isize size) {
isize i, j = count-1;
- for (i = 0; i < j; i++, j++)
+ for (i = 0; i < j; i++, j++) {
gb_memswap(cast(u8 *)base + i*size, cast(u8 *)base + j*size, size);
+ }
}
@@ -6001,18 +6017,21 @@ gb_inline isize gb_strlen(char const *str) {
str++;
}
w = cast(isize const *)str;
- while (!GB__HAS_ZERO(*w))
+ while (!GB__HAS_ZERO(*w)) {
w++;
+ }
str = cast(char const *)w;
- while (*str)
+ while (*str) {
str++;
+ }
return str - begin;
}
gb_inline isize gb_strnlen(char const *str, isize max_len) {
char const *end = cast(char const *)gb_memchr(str, 0, max_len);
- if (end)
+ if (end) {
return end - str;
+ }
return max_len;
}
@@ -6121,18 +6140,20 @@ gb_inline char *gb_strrev(char *str) {
gb_inline i32 gb_strncmp(char const *s1, char const *s2, isize len) {
for (; len > 0;
s1++, s2++, len--) {
- if (*s1 != *s2)
+ if (*s1 != *s2) {
return ((s1 < s2) ? -1 : +1);
- else if (*s1 == '\0')
+ } else if (*s1 == '\0') {
return 0;
+ }
}
return 0;
}
gb_inline char const *gb_strtok(char *output, char const *src, char const *delimit) {
- while (*src && gb_char_first_occurence(delimit, *src) != NULL)
+ while (*src && gb_char_first_occurence(delimit, *src) != NULL) {
*output++ = *src++;
+ }
*output = 0;
return *src ? src+1 : src;
@@ -6140,8 +6161,9 @@ gb_inline char const *gb_strtok(char *output, char const *src, char const *delim
gb_inline b32 gb_str_has_prefix(char const *str, char const *prefix) {
while (*prefix) {
- if (*str++ != *prefix++)
+ if (*str++ != *prefix++) {
return false;
+ }
}
return true;
}
@@ -6149,8 +6171,9 @@ gb_inline b32 gb_str_has_prefix(char const *str, char const *prefix) {
gb_inline b32 gb_str_has_suffix(char const *str, char const *suffix) {
isize i = gb_strlen(str);
isize j = gb_strlen(suffix);
- if (j <= i)
+ if (j <= i) {
return gb_strcmp(str+i-j, suffix) == 0;
+ }
return false;
}
@@ -6160,8 +6183,9 @@ gb_inline b32 gb_str_has_suffix(char const *str, char const *suffix) {
gb_inline char const *gb_char_first_occurence(char const *s, char c) {
char ch = c;
for (; *s != ch; s++) {
- if (*s == '\0')
+ if (*s == '\0') {
return NULL;
+ }
}
return s;
}
@@ -6170,8 +6194,9 @@ gb_inline char const *gb_char_first_occurence(char const *s, char c) {
gb_inline char const *gb_char_last_occurence(char const *s, char c) {
char const *result = NULL;
do {
- if (*s == c)
+ if (*s == c) {
result = s;
+ }
} while (*s++);
return result;
@@ -6201,17 +6226,19 @@ gb_internal isize gb__scan_i64(char const *text, i32 base, i64 *value) {
text++;
}
- if (base == 16 && gb_strncmp(text, "0x", 2) == 0)
+ if (base == 16 && gb_strncmp(text, "0x", 2) == 0) {
text += 2;
+ }
for (;;) {
i64 v;
- if (gb_char_is_digit(*text))
+ if (gb_char_is_digit(*text)) {
v = *text - '0';
- else if (base == 16 && gb_char_is_hex_digit(*text))
+ } else if (base == 16 && gb_char_is_hex_digit(*text)) {
v = gb_hex_digit_to_int(*text);
- else
+ } else {
break;
+ }
result *= base;
result += v;
@@ -6230,16 +6257,17 @@ gb_internal isize gb__scan_u64(char const *text, i32 base, u64 *value) {
char const *text_begin = text;
u64 result = 0;
- if (base == 16 && gb_strncmp(text, "0x", 2) == 0)
+ if (base == 16 && gb_strncmp(text, "0x", 2) == 0) {
text += 2;
+ }
for (;;) {
u64 v;
- if (gb_char_is_digit(*text))
+ if (gb_char_is_digit(*text)) {
v = *text - '0';
- else if (base == 16 && gb_char_is_hex_digit(*text))
+ } else if (base == 16 && gb_char_is_hex_digit(*text)) {
v = gb_hex_digit_to_int(*text);
- else {
+ } else {
break;
}
@@ -6248,9 +6276,7 @@ gb_internal isize gb__scan_u64(char const *text, i32 base, u64 *value) {
text++;
}
- if (value)
- *value = result;
-
+ if (value) *value = result;
return (text - text_begin);
}
@@ -6261,15 +6287,15 @@ u64 gb_str_to_u64(char const *str, char **end_ptr, i32 base) {
u64 value = 0;
if (!base) {
- if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0))
+ if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0)) {
base = 16;
- else
+ } else {
base = 10;
+ }
}
len = gb__scan_u64(str, base, &value);
- if (end_ptr)
- *end_ptr = (char *)str + len;
+ if (end_ptr) *end_ptr = (char *)str + len;
return value;
}
@@ -6278,15 +6304,15 @@ i64 gb_str_to_i64(char const *str, char **end_ptr, i32 base) {
i64 value;
if (!base) {
- if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0))
+ if ((gb_strlen(str) > 2) && (gb_strncmp(str, "0x", 2) == 0)) {
base = 16;
- else
+ } else {
base = 10;
+ }
}
len = gb__scan_i64(str, base, &value);
- if (end_ptr)
- *end_ptr = (char *)str + len;
+ if (end_ptr) *end_ptr = (char *)str + len;
return value;
}
@@ -6432,8 +6458,9 @@ gbString gb_string_make_length(gbAllocator a, void const *init_str, isize num_by
header->allocator = a;
header->length = num_bytes;
header->capacity = num_bytes;
- if (num_bytes && init_str)
+ if (num_bytes && init_str) {
gb_memcopy(str, init_str, num_bytes);
+ }
str[num_bytes] = '\0';
return str;
@@ -6454,8 +6481,9 @@ gb_inline isize gb_string_capacity(gbString const str) { return GB_STRING_HEADER
gb_inline isize gb_string_available_space(gbString const str) {
gbStringHeader *h = GB_STRING_HEADER(str);
- if (h->capacity > h->length)
+ if (h->capacity > h->length) {
return h->capacity - h->length;
+ }
return 0;
}
@@ -6469,8 +6497,9 @@ gbString gb_string_append_length(gbString str, void const *other, isize other_le
isize curr_len = gb_string_length(str);
str = gb_string_make_space_for(str, other_len);
- if (str == NULL)
+ if (str == NULL) {
return NULL;
+ }
gb_memcopy(str + curr_len, other, other_len);
str[curr_len + other_len] = '\0';
@@ -6488,8 +6517,9 @@ gbString gb_string_set(gbString str, char const *cstr) {
isize len = gb_strlen(cstr);
if (gb_string_capacity(str) < len) {
str = gb_string_make_space_for(str, len - gb_string_length(str));
- if (str == NULL)
+ if (str == NULL) {
return NULL;
+ }
}
gb_memcopy(str, cstr, len);
@@ -6541,12 +6571,14 @@ gb_inline b32 gb_string_are_equal(gbString const lhs, gbString const rhs) {
isize lhs_len, rhs_len, i;
lhs_len = gb_string_length(lhs);
rhs_len = gb_string_length(rhs);
- if (lhs_len != rhs_len)
+ if (lhs_len != rhs_len) {
return false;
+ }
for (i = 0; i < lhs_len; i++) {
- if (lhs[i] != rhs[i])
+ if (lhs[i] != rhs[i]) {
return false;
+ }
}
return true;
@@ -6560,10 +6592,12 @@ gbString gb_string_trim(gbString str, char const *cut_set) {
start_pos = start = str;
end_pos = end = str + gb_string_length(str) - 1;
- while (start_pos <= end && gb_char_first_occurence(cut_set, *start_pos))
+ while (start_pos <= end && gb_char_first_occurence(cut_set, *start_pos)) {
start_pos++;
- while (end_pos > start_pos && gb_char_first_occurence(cut_set, *end_pos))
+ }
+ while (end_pos > start_pos && gb_char_first_occurence(cut_set, *end_pos)) {
end_pos--;
+ }
len = cast(isize)((start_pos > end_pos) ? 0 : ((end_pos - start_pos)+1));
@@ -6917,8 +6951,9 @@ u32 gb_adler32(void const *data, isize len) {
bytes += 8;
}
- for (; i < block_len; i++)
+ for (; i < block_len; i++) {
a += *bytes++, b += a;
+ }
a %= MOD_ALDER, b %= MOD_ALDER;
len -= block_len;
@@ -7067,8 +7102,9 @@ u32 gb_crc32(void const *data, isize len) {
isize remaining;
u32 result = ~(cast(u32)0);
u8 const *c = cast(u8 const *)data;
- for (remaining = len; remaining--; c++)
+ for (remaining = len; remaining--; c++) {
result = (result >> 8) ^ (GB__CRC32_TABLE[(result ^ *c) & 0xff]);
+ }
return ~result;
}
@@ -7076,8 +7112,9 @@ u64 gb_crc64(void const *data, isize len) {
isize remaining;
u64 result = ~(cast(u64)0);
u8 const *c = cast(u8 const *)data;
- for (remaining = len; remaining--; c++)
+ for (remaining = len; remaining--; c++) {
result = (result >> 8) ^ (GB__CRC64_TABLE[(result ^ *c) & 0xff]);
+ }
return ~result;
}
@@ -7086,8 +7123,9 @@ u32 gb_fnv32(void const *data, isize len) {
u32 h = 0x811c9dc5;
u8 const *c = cast(u8 const *)data;
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
h = (h * 0x01000193) ^ c[i];
+ }
return h;
}
@@ -7097,8 +7135,9 @@ u64 gb_fnv64(void const *data, isize len) {
u64 h = 0xcbf29ce484222325ull;
u8 const *c = cast(u8 const *)data;
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
h = (h * 0x100000001b3ll) ^ c[i];
+ }
return h;
}
@@ -7108,8 +7147,9 @@ u32 gb_fnv32a(void const *data, isize len) {
u32 h = 0x811c9dc5;
u8 const *c = cast(u8 const *)data;
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
h = (h ^ c[i]) * 0x01000193;
+ }
return h;
}
@@ -7119,8 +7159,9 @@ u64 gb_fnv64a(void const *data, isize len) {
u64 h = 0xcbf29ce484222325ull;
u8 const *c = cast(u8 const *)data;
- for (i = 0; i < len; i++)
+ for (i = 0; i < len; i++) {
h = (h ^ c[i]) * 0x100000001b3ll;
+ }
return h;
}
@@ -7288,6 +7329,36 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
//
#if defined(GB_SYSTEM_WINDOWS)
+
+ gb_internal wchar_t *gb__alloc_utf8_to_ucs2(gbAllocator a, char const *text, isize *w_len_) {
+ wchar_t *w_text = NULL;
+ isize len = 0, w_len = 0, w_len1 = 0;
+ if (text == NULL) {
+ if (w_len_) *w_len_ = w_len;
+ return NULL;
+ }
+ len = gb_strlen(text);
+ if (len == 0) {
+ if (w_len_) *w_len_ = w_len;
+ return NULL;
+ }
+ w_len = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, NULL, 0);
+ if (w_len == 0) {
+ if (w_len_) *w_len_ = w_len;
+ return NULL;
+ }
+ w_text = gb_alloc_array(a, wchar_t, w_len+1);
+ w_len1 = MultiByteToWideChar(CP_UTF8, MB_ERR_INVALID_CHARS, text, len, w_text, w_len);
+ if (w_len1 == 0) {
+ gb_free(a, w_text);
+ if (w_len_) *w_len_ = 0;
+ return NULL;
+ }
+ w_text[w_len] = 0;
+ if (w_len_) *w_len_ = w_len;
+ return w_text;
+ }
+
gb_internal GB_FILE_SEEK_PROC(gb__win32_file_seek) {
LARGE_INTEGER li_offset;
li_offset.QuadPart = offset;
@@ -7338,7 +7409,7 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
DWORD desired_access;
DWORD creation_disposition;
void *handle;
- u16 path[1024] = {0}; // TODO(bill): Is this really enough or should I heap allocate this if it's too large?
+ wchar_t *w_text;
switch (mode & gbFileMode_Modes) {
case gbFileMode_Read:
@@ -7370,11 +7441,17 @@ u64 gb_murmur64_seed(void const *data_, isize len, u64 seed) {
return gbFileError_Invalid;
}
- handle = CreateFileW(cast(wchar_t const *)gb_utf8_to_ucs2(path, gb_count_of(path), cast(u8 *)filename),
+ w_text = gb__alloc_utf8_to_ucs2(gb_heap_allocator(), filename, NULL);
+ if (w_text == NULL) {
+ return gbFileError_InvalidFilename;
+ }
+ handle = CreateFileW(w_text,
desired_access,
FILE_SHARE_READ|FILE_SHARE_DELETE, NULL,
creation_disposition, FILE_ATTRIBUTE_NORMAL, NULL);
+ gb_free(gb_heap_allocator(), w_text);
+
if (handle == INVALID_HANDLE_VALUE) {
DWORD err = GetLastError();
switch (err) {
@@ -7505,23 +7582,27 @@ gbFileError gb_file_open_mode(gbFile *f, gbFileMode mode, char const *filename)
#else
err = gb__posix_file_open(&f->fd, &f->ops, mode, filename);
#endif
- if (err == gbFileError_None)
+ if (err == gbFileError_None) {
return gb_file_new(f, f->fd, f->ops, filename);
+ }
return err;
}
gbFileError gb_file_close(gbFile *f) {
- if (!f)
+ if (!f) {
return gbFileError_Invalid;
+ }
if (f->filename) gb_free(gb_heap_allocator(), cast(char *)f->filename);
#if defined(GB_SYSTEM_WINDOWS)
- if (f->fd.p == INVALID_HANDLE_VALUE)
+ if (f->fd.p == INVALID_HANDLE_VALUE) {
return gbFileError_Invalid;
+ }
#else
- if (f->fd.i < 0)
+ if (f->fd.i < 0) {
return gbFileError_Invalid;
+ }
#endif
if (!f->ops.read_at) f->ops = gbDefaultFileOperations;
@@ -7632,8 +7713,9 @@ gbFileError gb_file_truncate(gbFile *f, i64 size) {
gbFileError err = gbFileError_None;
i64 prev_offset = gb_file_tell(f);
gb_file_seek(f, size);
- if (!SetEndOfFile(f))
+ if (!SetEndOfFile(f)) {
err = gbFileError_TruncationFailure;
+ }
gb_file_seek(f, prev_offset);
return err;
}
@@ -7641,8 +7723,18 @@ gbFileError gb_file_truncate(gbFile *f, i64 size) {
b32 gb_file_exists(char const *name) {
WIN32_FIND_DATAW data;
- void *handle = FindFirstFileW(cast(wchar_t const *)gb_utf8_to_ucs2_buf(cast(u8 *)name), &data);
- b32 found = handle != INVALID_HANDLE_VALUE;
+ wchar_t *w_text;
+ void *handle;
+ b32 found = false;
+ gbAllocator a = gb_heap_allocator();
+
+ w_text = gb__alloc_utf8_to_ucs2(a, name, NULL);
+ if (w_text == NULL) {
+ return false;
+ }
+ handle = FindFirstFileW(w_text, &data);
+ gb_free(a, w_text);
+ found = handle != INVALID_HANDLE_VALUE;
if (found) FindClose(handle);
return found;
}
@@ -7686,14 +7778,20 @@ gb_inline b32 gb_file_exists(char const *name) {
#if defined(GB_SYSTEM_WINDOWS)
gbFileTime gb_file_last_write_time(char const *filepath) {
- u16 path[1024] = {0};
ULARGE_INTEGER li = {0};
FILETIME last_write_time = {0};
WIN32_FILE_ATTRIBUTE_DATA data = {0};
+ gbAllocator a = gb_heap_allocator();
- if (GetFileAttributesExW(cast(wchar_t const *)gb_utf8_to_ucs2(path, gb_count_of(path), cast(u8 *)filepath),
- GetFileExInfoStandard, &data))
+ wchar_t *w_text = gb__alloc_utf8_to_ucs2(a, filepath, NULL);
+ if (w_text == NULL) {
+ return 0;
+ }
+
+ if (GetFileAttributesExW(w_text, GetFileExInfoStandard, &data)) {
last_write_time = data.ftLastWriteTime;
+ }
+ gb_free(a, w_text);
li.LowPart = last_write_time.dwLowDateTime;
li.HighPart = last_write_time.dwHighDateTime;
@@ -7702,20 +7800,41 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filename, b32 fail_if_exists) {
- u16 old_f[300] = {0};
- u16 new_f[300] = {0};
+ wchar_t *w_old = NULL;
+ wchar_t *w_new = NULL;
+ gbAllocator a = gb_heap_allocator();
+ b32 result = false;
- return CopyFileW(cast(wchar_t const *)gb_utf8_to_ucs2(old_f, gb_count_of(old_f), cast(u8 *)existing_filename),
- cast(wchar_t const *)gb_utf8_to_ucs2(new_f, gb_count_of(new_f), cast(u8 *)new_filename),
- fail_if_exists);
+ w_old = gb__alloc_utf8_to_ucs2(a, existing_filename, NULL);
+ if (w_old == NULL) {
+ return false;
+ }
+ w_new = gb__alloc_utf8_to_ucs2(a, new_filename, NULL);
+ if (w_new != NULL) {
+ result = CopyFileW(w_old, w_new, fail_if_exists);
+ }
+ gb_free(a, w_new);
+ gb_free(a, w_old);
+ return result;
}
gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) {
- u16 old_f[300] = {0};
- u16 new_f[300] = {0};
+ wchar_t *w_old = NULL;
+ wchar_t *w_new = NULL;
+ gbAllocator a = gb_heap_allocator();
+ b32 result = false;
- return MoveFileW(cast(wchar_t const *)gb_utf8_to_ucs2(old_f, gb_count_of(old_f), cast(u8 *)existing_filename),
- cast(wchar_t const *)gb_utf8_to_ucs2(new_f, gb_count_of(new_f), cast(u8 *)new_filename));
+ w_old = gb__alloc_utf8_to_ucs2(a, existing_filename, NULL);
+ if (w_old == NULL) {
+ return false;
+ }
+ w_new = gb__alloc_utf8_to_ucs2(a, new_filename, NULL);
+ if (w_new != NULL) {
+ result = MoveFileW(w_old, w_new);
+ }
+ gb_free(a, w_new);
+ gb_free(a, w_old);
+ return result;
}
@@ -7726,8 +7845,9 @@ gbFileTime gb_file_last_write_time(char const *filepath) {
time_t result = 0;
struct stat file_stat;
- if (stat(filepath, &file_stat))
+ if (stat(filepath, &file_stat)) {
result = file_stat.st_mtime;
+ }
return cast(gbFileTime)result;
}
@@ -7755,8 +7875,9 @@ gb_inline b32 gb_file_copy(char const *existing_filename, char const *new_filena
gb_inline b32 gb_file_move(char const *existing_filename, char const *new_filename) {
if (link(existing_filename, new_filename) == 0) {
- if (unlink(existing_filename) != -1)
+ if (unlink(existing_filename) != -1) {
return true;
+ }
}
return false;
}
@@ -7844,14 +7965,45 @@ gb_inline char const *gb_path_extension(char const *path) {
#if !defined(_WINDOWS_) && defined(GB_SYSTEM_WINDOWS)
GB_DLL_IMPORT DWORD WINAPI GetFullPathNameA(char const *lpFileName, DWORD nBufferLength, char *lpBuffer, char **lpFilePart);
+GB_DLL_IMPORT DWORD WINAPI GetFullPathNameW(wchar_t const *lpFileName, DWORD nBufferLength, wchar_t *lpBuffer, wchar_t **lpFilePart);
#endif
char *gb_path_get_full_name(gbAllocator a, char const *path) {
#if defined(GB_SYSTEM_WINDOWS)
// TODO(bill): Make UTF-8
- char buf[300];
- isize len = GetFullPathNameA(path, gb_count_of(buf), buf, NULL);
- return gb_alloc_str_len(a, buf, len+1);
+ wchar_t *w_path = NULL;
+ wchar_t *w_fullpath = NULL;
+ isize w_len = 0;
+ isize new_len = 0;
+ isize new_len1 = 0;
+ char *new_path = 0;
+ w_path = gb__alloc_utf8_to_ucs2(gb_heap_allocator(), path, NULL);
+ if (w_path == NULL) {
+ return NULL;
+ }
+ w_len = GetFullPathNameW(w_path, 0, NULL, NULL);
+ if (w_len == 0) {
+ return NULL;
+ }
+ w_fullpath = gb_alloc_array(gb_heap_allocator(), wchar_t, w_len+1);
+ GetFullPathNameW(w_path, w_len, w_fullpath, NULL);
+ w_fullpath[w_len] = 0;
+ gb_free(gb_heap_allocator(), w_path);
+
+ new_len = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, NULL, 0, NULL, NULL);
+ if (new_len == 0) {
+ gb_free(gb_heap_allocator(), w_fullpath);
+ return NULL;
+ }
+ new_path = gb_alloc_array(a, char, new_len+1);
+ new_len1 = WideCharToMultiByte(CP_UTF8, WC_ERR_INVALID_CHARS, w_fullpath, w_len, new_path, new_len, NULL, NULL);
+ if (new_len1 == 0) {
+ gb_free(gb_heap_allocator(), w_fullpath);
+ gb_free(a, new_path);
+ return NULL;
+ }
+ new_path[new_len] = 0;
+ return new_path;
#else
// TODO(bill): Make work on *nix, etc.
char* p = realpath(path, 0);
@@ -7990,29 +8142,33 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
isize res = 0, len;
isize remaining = max_len;
- if (info && info->precision >= 0)
+ if (info && info->precision >= 0) {
len = gb_strnlen(str, info->precision);
- else
+ } else {
len = gb_strlen(str);
+ }
if (info && (info->width == 0 || info->flags & gbFmt_Minus)) {
- if (info->precision > 0)
+ if (info->precision > 0) {
len = info->precision < len ? info->precision : len;
+ }
res += gb_strlcpy(text, str, len);
if (info->width > res) {
isize padding = info->width - len;
char pad = (info->flags & gbFmt_Zero) ? '0' : ' ';
- while (padding --> 0 && remaining --> 0)
+ while (padding --> 0 && remaining --> 0) {
*text++ = pad, res++;
+ }
}
} else {
if (info && (info->width > res)) {
isize padding = info->width - len;
char pad = (info->flags & gbFmt_Zero) ? '0' : ' ';
- while (padding --> 0 && remaining --> 0)
+ while (padding --> 0 && remaining --> 0) {
*text++ = pad, res++;
+ }
}
res += gb_strlcpy(text, str, len);
@@ -8020,10 +8176,11 @@ gb_internal isize gb__print_string(char *text, isize max_len, gbprivFmtInfo *inf
if (info) {
- if (info->flags & gbFmt_Upper)
+ if (info->flags & gbFmt_Upper) {
gb_str_to_upper(text);
- else if (info->flags & gbFmt_Lower)
+ } else if (info->flags & gbFmt_Lower) {
gb_str_to_lower(text);
+ }
}
return res;
@@ -8057,13 +8214,15 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info,
if (arg) {
u64 value;
if (arg < 0) {
- if (remaining > 1)
+ if (remaining > 1) {
*text = '-', remaining--;
+ }
text++;
arg = -arg;
} else if (info->flags & gbFmt_Minus) {
- if (remaining > 1)
+ if (remaining > 1) {
*text = '+', remaining--;
+ }
text++;
}
@@ -8071,39 +8230,45 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info,
len = gb__print_u64(text, remaining, NULL, value);
text += len;
- if (len >= remaining)
+ if (len >= remaining) {
remaining = gb_min(remaining, 1);
- else
+ } else {
remaining -= len;
+ }
arg -= value;
- if (info->precision < 0)
+ if (info->precision < 0) {
info->precision = 6;
+ }
if ((info->flags & gbFmt_Alt) || info->precision > 0) {
i64 mult = 10;
- if (remaining > 1)
+ if (remaining > 1) {
*text = '.', remaining--;
+ }
text++;
while (info->precision-- > 0) {
value = cast(u64)(arg * mult);
len = gb__print_u64(text, remaining, NULL, value);
text += len;
- if (len >= remaining)
+ if (len >= remaining) {
remaining = gb_min(remaining, 1);
- else
+ } else {
remaining -= len;
+ }
arg -= cast(f64)value / mult;
mult *= 10;
}
}
} else {
- if (remaining > 1)
+ if (remaining > 1) {
*text = '0', remaining--;
+ }
text++;
if (info->flags & gbFmt_Alt) {
- if (remaining > 1)
+ if (remaining > 1) {
*text = '.', remaining--;
+ }
text++;
}
}
@@ -8115,20 +8280,23 @@ gb_internal isize gb__print_f64(char *text, isize max_len, gbprivFmtInfo *info,
len = (text - text_begin);
for (len = (text - text_begin); len--; ) {
- if ((text_begin+len+width) < end)
+ if ((text_begin+len+width) < end) {
*(text_begin+len+width) = *(text_begin+len);
+ }
}
len = width;
text += len;
- if (len >= remaining)
+ if (len >= remaining) {
remaining = gb_min(remaining, 1);
- else
+ } else {
remaining -= len;
+ }
while (len--) {
- if (text_begin+len < end)
+ if (text_begin+len < end) {
text_begin[len] = fill;
+ }
}
}
@@ -8146,8 +8314,9 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
isize len = 0;
info.precision = -1;
- while (*fmt && *fmt != '%' && remaining)
+ while (*fmt && *fmt != '%' && remaining) {
*text++ = *fmt++;
+ }
if (*fmt == '%') {
do {
@@ -8311,10 +8480,11 @@ gb_no_inline isize gb_snprintf_va(char *text, isize max_len, char const *fmt, va
text += len;
- if (len >= remaining)
+ if (len >= remaining) {
remaining = gb_min(remaining, 1);
- else
+ } else {
remaining -= len;
+ }
}
*text++ = '\0';
@@ -8512,10 +8682,11 @@ gb_internal gb_inline u32 gb__permute_qpr(u32 x) {
return x;
} else {
u32 residue = cast(u32)(cast(u64) x * x) % prime;
- if (x <= prime / 2)
+ if (x <= prime / 2) {
return residue;
- else
+ } else {
return prime - residue;
+ }
}
}
@@ -8742,10 +8913,11 @@ GB_XINPUT_SET_STATE(gbXInputSetState_Stub) {
gb_internal gb_inline f32 gb__process_xinput_stick_value(i16 value, i16 dead_zone_threshold) {
f32 result = 0;
- if (value < -dead_zone_threshold)
+ if (value < -dead_zone_threshold) {
result = cast(f32) (value + dead_zone_threshold) / (32768.0f - dead_zone_threshold);
- else if (value > dead_zone_threshold)
+ } else if (value > dead_zone_threshold) {
result = cast(f32) (value - dead_zone_threshold) / (32767.0f - dead_zone_threshold);
+ }
return result;
}
@@ -8755,8 +8927,9 @@ gb_internal void gb__platform_resize_dib_section(gbPlatform *p, i32 width, i32 h
!(p->window_width == width && p->window_height == height)) {
BITMAPINFO bmi = {0};
- if (width == 0 || height == 0)
+ if (width == 0 || height == 0) {
return;
+ }
p->window_width = width;
p->window_height = height;
@@ -8775,8 +8948,9 @@ gb_internal void gb__platform_resize_dib_section(gbPlatform *p, i32 width, i32 h
p->sw_framebuffer.win32_bmi = bmi;
- if (p->sw_framebuffer.memory)
+ if (p->sw_framebuffer.memory) {
gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size));
+ }
{
isize memory_size = p->sw_framebuffer.pitch * height;
@@ -8900,8 +9074,9 @@ LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, L
}
}
- if (!platform)
+ if (!platform) {
return DefWindowProcW(hWnd, msg, wParam, lParam);
+ }
switch (msg) {
case WM_CLOSE:
@@ -8915,8 +9090,9 @@ LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, L
case WM_UNICHAR: {
if (window_has_focus) {
- if (wParam == '\r')
+ if (wParam == '\r') {
wParam = '\n';
+ }
// TODO(bill): Does this need to be thread-safe?
platform->char_buffer[platform->char_buffer_count++] = cast(Rune)wParam;
}
@@ -8961,10 +9137,11 @@ LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, L
if (is_e1) {
// NOTE(bill): Escaped sequences, turn vk into the correct scan code
// except for VK_PAUSE (it's a bug)
- if (vk == VK_PAUSE)
+ if (vk == VK_PAUSE) {
scan_code = 0x45;
- else
+ } else {
scan_code = MapVirtualKeyW(vk, MAPVK_VK_TO_VSC);
+ }
}
switch (vk) {
@@ -9000,8 +9177,9 @@ LRESULT CALLBACK gb__win32_window_callback(HWND hWnd, UINT msg, WPARAM wParam, L
long dx = +raw_mouse->lLastX;
long dy = -raw_mouse->lLastY;
- if (flags & RI_MOUSE_WHEEL)
+ if (flags & RI_MOUSE_WHEEL) {
platform->mouse_wheel_delta = cast(i16)raw_mouse->usButtonData;
+ }
platform->mouse_raw_dx = dx;
platform->mouse_raw_dy = dy;
@@ -9285,8 +9463,9 @@ void gb_platform_update(gbPlatform *p) {
h = window_rect.bottom - window_rect.top;
if ((p->window_width != w) || (p->window_height != h)) {
- if (p->renderer_type == gbRenderer_Software)
+ if (p->renderer_type == gbRenderer_Software) {
gb__platform_resize_dib_section(p, w, h);
+ }
}
@@ -9311,8 +9490,9 @@ void gb_platform_update(gbPlatform *p) {
// NOTE(bill): This needs to be GetAsyncKeyState as RAWMOUSE doesn't aways work for some odd reason
// TODO(bill): Try and get RAWMOUSE to work for key presses
- for (i = 0; i < gbMouseButton_Count; i++)
+ for (i = 0; i < gbMouseButton_Count; i++) {
gb_key_state_update(p->mouse_buttons+i, GetAsyncKeyState(win_button_id[i]) < 0);
+ }
GetCursorPos(&mouse_pos);
ScreenToClient(cast(HWND)p->window_handle, &mouse_pos);
@@ -9345,8 +9525,9 @@ void gb_platform_update(gbPlatform *p) {
update = true;
}
- if (update)
+ if (update) {
gb_platform_set_mouse_position(p, x, y);
+ }
}
@@ -9371,8 +9552,9 @@ void gb_platform_update(gbPlatform *p) {
{ // NOTE(bill): Set Controller states
isize max_controller_count = XUSER_MAX_COUNT;
- if (max_controller_count > gb_count_of(p->game_controllers))
+ if (max_controller_count > gb_count_of(p->game_controllers)) {
max_controller_count = gb_count_of(p->game_controllers);
+ }
for (i = 0; i < max_controller_count; i++) {
gbGameController *controller = &p->game_controllers[i];
@@ -9468,10 +9650,11 @@ void gb_platform_display(gbPlatform *p) {
void gb_platform_destroy(gbPlatform *p) {
- if (p->renderer_type == gbRenderer_Opengl)
+ if (p->renderer_type == gbRenderer_Opengl) {
wglDeleteContext(cast(HGLRC)p->opengl.context);
- else if (p->renderer_type == gbRenderer_Software)
+ } else if (p->renderer_type == gbRenderer_Software) {
gb_vm_free(gb_virtual_memory(p->sw_framebuffer.memory, p->sw_framebuffer.memory_size));
+ }
DestroyWindow(cast(HWND)p->window_handle);
}
@@ -9525,8 +9708,9 @@ void gb_platform_set_window_title(gbPlatform *p, char const *title, ...) {
gb_snprintf_va(str, gb_size_of(str), title, va);
va_end(va);
- if (str[0] != '\0')
+ if (str[0] != '\0') {
SetWindowTextW(cast(HWND)p->window_handle, cast(wchar_t const *)gb_utf8_to_ucs2(buffer, gb_size_of(buffer), str));
+ }
}
void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) {
@@ -9551,10 +9735,11 @@ void gb_platform_toggle_fullscreen(gbPlatform *p, b32 fullscreen_desktop) {
monitor_info.rcMonitor.bottom - monitor_info.rcMonitor.top,
SWP_NOOWNERZORDER | SWP_FRAMECHANGED);
- if (fullscreen_desktop)
+ if (fullscreen_desktop) {
p->window_flags |= gbWindow_FullscreenDesktop;
- else
+ } else {
p->window_flags |= gbWindow_Fullscreen;
+ }
}
} else {
style &= ~WS_POPUP;
@@ -9629,8 +9814,9 @@ b32 gb_platform_has_clipboard_text(gbPlatform *p) {
HANDLE mem = GetClipboardData(1/*CF_TEXT*/);
if (mem) {
char *str = cast(char *)GlobalLock(mem);
- if (str && str[0] != '\0')
+ if (str && str[0] != '\0') {
result = true;
+ }
GlobalUnlock(mem);
} else {
return false;
@@ -9665,8 +9851,9 @@ void gb_platform_set_clipboard_text(gbPlatform *p, char const *str) {
}
EmptyClipboard();
- if (!SetClipboardData(1/*CF_TEXT*/, mem))
+ if (!SetClipboardData(1/*CF_TEXT*/, mem)) {
return;
+ }
CloseClipboard();
}
}
@@ -9759,8 +9946,9 @@ gb_internal void gb__osx_window_did_become_key(id self, SEL _sel, id notificatio
}
b32 gb__platform_init(gbPlatform *p, char const *window_title, gbVideoMode mode, gbRendererType type, u32 window_flags) {
- if (p->is_initialized)
+ if (p->is_initialized) {
return true;
+ }
// Init Platform
{ // Initial OSX State
Class appDelegateClass;
@@ -10243,8 +10431,9 @@ void gb_platform_update(gbPlatform *p) {
update = true;
}
- if (update)
+ if (update) {
gb_platform_set_mouse_position(p, x, y);
+ }
}
}
@@ -10449,8 +10638,9 @@ GB_COMPARE_PROC(gb_video_mode_cmp) {
gbVideoMode const *y = cast(gbVideoMode const *)b;
if (x->bits_per_pixel == y->bits_per_pixel) {
- if (x->width == y->width)
+ if (x->width == y->width) {
return x->height < y->height ? -1 : x->height > y->height;
+ }
return x->width < y->width ? -1 : x->width > y->width;
}
return x->bits_per_pixel < y->bits_per_pixel ? -1 : +1;
diff --git a/src/ir.c b/src/ir.c
index fdea85dfb..d28d93d07 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -91,7 +91,7 @@ typedef enum irDeferKind {
typedef struct irDefer {
irDeferKind kind;
- isize scope_index;
+ isize scope_index;
irBlock * block;
union {
AstNode *stmt;
@@ -100,32 +100,41 @@ typedef struct irDefer {
};
} irDefer;
+
+typedef struct irBranchBlocks {
+ AstNode *label;
+ irBlock *break_;
+ irBlock *continue_;
+} irBranchBlocks;
+
+
struct irProcedure {
- irProcedure * parent;
- Array(irProcedure *) children;
-
- Entity * entity;
- irModule * module;
- String name;
- Type * type;
- AstNode * type_expr;
- AstNode * body;
- u64 tags;
-
- irValueArray params;
- Array(irDefer) defer_stmts;
- Array(irBlock *) blocks;
- i32 scope_index;
- irBlock * decl_block;
- irBlock * entry_block;
- irBlock * curr_block;
- irTargetList * target_list;
- irValueArray referrers;
-
-
- i32 local_count;
- i32 instr_count;
- i32 block_count;
+ irProcedure * parent;
+ Array(irProcedure *) children;
+
+ Entity * entity;
+ irModule * module;
+ String name;
+ Type * type;
+ AstNode * type_expr;
+ AstNode * body;
+ u64 tags;
+
+ irValueArray params;
+ Array(irDefer) defer_stmts;
+ Array(irBlock *) blocks;
+ i32 scope_index;
+ irBlock * decl_block;
+ irBlock * entry_block;
+ irBlock * curr_block;
+ irTargetList * target_list;
+ irValueArray referrers;
+
+ Array(irBranchBlocks) branch_blocks;
+
+ i32 local_count;
+ i32 instr_count;
+ i32 block_count;
};
#define IR_STARTUP_RUNTIME_PROC_NAME "__$startup_runtime"
@@ -332,8 +341,8 @@ typedef struct irValueTypeName {
typedef struct irValueGlobal {
Entity * entity;
Type * type;
- irValue * value;
- irValueArray referrers;
+ irValue * value;
+ irValueArray referrers;
bool is_constant;
bool is_private;
bool is_thread_local;
@@ -350,7 +359,8 @@ typedef struct irValueParam {
typedef struct irValue {
irValueKind kind;
- i32 index;
+ i32 index;
+ bool index_set;
union {
irValueConstant Constant;
irValueConstantSlice ConstantSlice;
@@ -394,12 +404,12 @@ typedef struct irAddr {
// };
} irAddr;
-irAddr ir_make_addr(irValue *addr) {
+irAddr ir_addr(irValue *addr) {
irAddr v = {irAddr_Default, addr};
return v;
}
-irAddr ir_make_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) {
+irAddr ir_addr_map(irValue *addr, irValue *map_key, Type *map_type, Type *map_result) {
irAddr v = {irAddr_Map, addr};
v.map_key = map_key;
v.map_type = map_type;
@@ -727,14 +737,14 @@ irDebugInfo *ir_alloc_debug_info(gbAllocator a, irDebugInfoKind kind) {
-irValue *ir_make_value_type_name(gbAllocator a, String name, Type *type) {
+irValue *ir_value_type_name(gbAllocator a, String name, Type *type) {
irValue *v = ir_alloc_value(a, irValue_TypeName);
v->TypeName.name = name;
v->TypeName.type = type;
return v;
}
-irValue *ir_make_value_global(gbAllocator a, Entity *e, irValue *value) {
+irValue *ir_value_global(gbAllocator a, Entity *e, irValue *value) {
irValue *v = ir_alloc_value(a, irValue_Global);
v->Global.entity = e;
v->Global.type = make_type_pointer(a, e->type);
@@ -742,7 +752,7 @@ irValue *ir_make_value_global(gbAllocator a, Entity *e, irValue *value) {
array_init(&v->Global.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
return v;
}
-irValue *ir_make_value_param(gbAllocator a, irProcedure *parent, Entity *e) {
+irValue *ir_value_param(gbAllocator a, irProcedure *parent, Entity *e) {
irValue *v = ir_alloc_value(a, irValue_Param);
v->Param.parent = parent;
v->Param.entity = e;
@@ -750,7 +760,7 @@ irValue *ir_make_value_param(gbAllocator a, irProcedure *parent, Entity *e) {
array_init(&v->Param.referrers, heap_allocator()); // TODO(bill): Replace heap allocator here
return v;
}
-irValue *ir_make_value_nil(gbAllocator a, Type *type) {
+irValue *ir_value_nil(gbAllocator a, Type *type) {
irValue *v = ir_alloc_value(a, irValue_Nil);
v->Nil.type = type;
return v;
@@ -758,7 +768,7 @@ irValue *ir_make_value_nil(gbAllocator a, Type *type) {
-irValue *ir_make_instr_local(irProcedure *p, Entity *e, bool zero_initialized) {
+irValue *ir_instr_local(irProcedure *p, Entity *e, bool zero_initialized) {
irValue *v = ir_alloc_instr(p, irInstr_Local);
irInstr *i = &v->Instr;
i->Local.entity = e;
@@ -770,7 +780,7 @@ irValue *ir_make_instr_local(irProcedure *p, Entity *e, bool zero_initialized) {
}
-irValue *ir_make_instr_store(irProcedure *p, irValue *address, irValue *value) {
+irValue *ir_instr_store(irProcedure *p, irValue *address, irValue *value) {
irValue *v = ir_alloc_instr(p, irInstr_Store);
irInstr *i = &v->Instr;
i->Store.address = address;
@@ -778,14 +788,14 @@ irValue *ir_make_instr_store(irProcedure *p, irValue *address, irValue *value) {
return v;
}
-irValue *ir_make_instr_zero_init(irProcedure *p, irValue *address) {
+irValue *ir_instr_zero_init(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_ZeroInit);
irInstr *i = &v->Instr;
i->ZeroInit.address = address;
return v;
}
-irValue *ir_make_instr_load(irProcedure *p, irValue *address) {
+irValue *ir_instr_load(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_Load);
irInstr *i = &v->Instr;
i->Load.address = address;
@@ -793,7 +803,7 @@ irValue *ir_make_instr_load(irProcedure *p, irValue *address) {
return v;
}
-irValue *ir_make_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *elem_index) {
+irValue *ir_instr_array_element_ptr(irProcedure *p, irValue *address, irValue *elem_index) {
irValue *v = ir_alloc_instr(p, irInstr_ArrayElementPtr);
irInstr *i = &v->Instr;
Type *t = ir_type(address);
@@ -811,7 +821,7 @@ irValue *ir_make_instr_array_element_ptr(irProcedure *p, irValue *address, irVal
"%s", type_to_string(ir_type(address)));
return v;
}
-irValue *ir_make_instr_struct_element_ptr(irProcedure *p, irValue *address, i32 elem_index, Type *result_type) {
+irValue *ir_instr_struct_element_ptr(irProcedure *p, irValue *address, i32 elem_index, Type *result_type) {
irValue *v = ir_alloc_instr(p, irInstr_StructElementPtr);
irInstr *i = &v->Instr;
i->StructElementPtr.address = address;
@@ -822,7 +832,7 @@ irValue *ir_make_instr_struct_element_ptr(irProcedure *p, irValue *address, i32
"%s", type_to_string(ir_type(address)));
return v;
}
-irValue *ir_make_instr_ptr_offset(irProcedure *p, irValue *address, irValue *offset) {
+irValue *ir_instr_ptr_offset(irProcedure *p, irValue *address, irValue *offset) {
irValue *v = ir_alloc_instr(p, irInstr_PtrOffset);
irInstr *i = &v->Instr;
i->PtrOffset.address = address;
@@ -838,7 +848,7 @@ irValue *ir_make_instr_ptr_offset(irProcedure *p, irValue *address, irValue *off
-irValue *ir_make_instr_struct_extract_value(irProcedure *p, irValue *address, i32 index, Type *result_type) {
+irValue *ir_instr_struct_extract_value(irProcedure *p, irValue *address, i32 index, Type *result_type) {
irValue *v = ir_alloc_instr(p, irInstr_StructExtractValue);
irInstr *i = &v->Instr;
i->StructExtractValue.address = address;
@@ -847,7 +857,7 @@ irValue *ir_make_instr_struct_extract_value(irProcedure *p, irValue *address, i3
return v;
}
-irValue *ir_make_instr_union_tag_ptr(irProcedure *p, irValue *address) {
+irValue *ir_instr_union_tag_ptr(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_UnionTagPtr);
irInstr *i = &v->Instr;
i->UnionTagPtr.address = address;
@@ -855,7 +865,7 @@ irValue *ir_make_instr_union_tag_ptr(irProcedure *p, irValue *address) {
return v;
}
-irValue *ir_make_instr_union_tag_value(irProcedure *p, irValue *address) {
+irValue *ir_instr_union_tag_value(irProcedure *p, irValue *address) {
irValue *v = ir_alloc_instr(p, irInstr_UnionTagValue);
irInstr *i = &v->Instr;
i->UnionTagValue.address = address;
@@ -863,7 +873,7 @@ irValue *ir_make_instr_union_tag_value(irProcedure *p, irValue *address) {
return v;
}
-irValue *ir_make_instr_unary_op(irProcedure *p, TokenKind op, irValue *expr, Type *type) {
+irValue *ir_instr_unary_op(irProcedure *p, TokenKind op, irValue *expr, Type *type) {
irValue *v = ir_alloc_instr(p, irInstr_UnaryOp);
irInstr *i = &v->Instr;
i->UnaryOp.op = op;
@@ -873,7 +883,7 @@ irValue *ir_make_instr_unary_op(irProcedure *p, TokenKind op, irValue *expr, Typ
}
-irValue *ir_make_instr_binary_op(irProcedure *p, TokenKind op, irValue *left, irValue *right, Type *type) {
+irValue *ir_instr_binary_op(irProcedure *p, TokenKind op, irValue *left, irValue *right, Type *type) {
irValue *v = ir_alloc_instr(p, irInstr_BinaryOp);
irInstr *i = &v->Instr;
i->BinaryOp.op = op;
@@ -883,13 +893,13 @@ irValue *ir_make_instr_binary_op(irProcedure *p, TokenKind op, irValue *left, ir
return v;
}
-irValue *ir_make_instr_jump(irProcedure *p, irBlock *block) {
+irValue *ir_instr_jump(irProcedure *p, irBlock *block) {
irValue *v = ir_alloc_instr(p, irInstr_Jump);
irInstr *i = &v->Instr;
i->Jump.block = block;
return v;
}
-irValue *ir_make_instr_if(irProcedure *p, irValue *cond, irBlock *true_block, irBlock *false_block) {
+irValue *ir_instr_if(irProcedure *p, irValue *cond, irBlock *true_block, irBlock *false_block) {
irValue *v = ir_alloc_instr(p, irInstr_If);
irInstr *i = &v->Instr;
i->If.cond = cond;
@@ -899,7 +909,7 @@ irValue *ir_make_instr_if(irProcedure *p, irValue *cond, irBlock *true_block, ir
}
-irValue *ir_make_instr_phi(irProcedure *p, irValueArray edges, Type *type) {
+irValue *ir_instr_phi(irProcedure *p, irValueArray edges, Type *type) {
irValue *v = ir_alloc_instr(p, irInstr_Phi);
irInstr *i = &v->Instr;
i->Phi.edges = edges;
@@ -907,18 +917,18 @@ irValue *ir_make_instr_phi(irProcedure *p, irValueArray edges, Type *type) {
return v;
}
-irValue *ir_make_instr_unreachable(irProcedure *p) {
+irValue *ir_instr_unreachable(irProcedure *p) {
irValue *v = ir_alloc_instr(p, irInstr_Unreachable);
return v;
}
-irValue *ir_make_instr_return(irProcedure *p, irValue *value) {
+irValue *ir_instr_return(irProcedure *p, irValue *value) {
irValue *v = ir_alloc_instr(p, irInstr_Return);
v->Instr.Return.value = value;
return v;
}
-irValue *ir_make_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) {
+irValue *ir_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) {
irValue *v = ir_alloc_instr(p, irInstr_Select);
v->Instr.Select.cond = cond;
v->Instr.Select.true_value = t;
@@ -926,7 +936,7 @@ irValue *ir_make_instr_select(irProcedure *p, irValue *cond, irValue *t, irValue
return v;
}
-irValue *ir_make_instr_call(irProcedure *p, irValue *value, irValue **args, isize arg_count, Type *result_type) {
+irValue *ir_instr_call(irProcedure *p, irValue *value, irValue **args, isize arg_count, Type *result_type) {
irValue *v = ir_alloc_instr(p, irInstr_Call);
v->Instr.Call.value = value;
v->Instr.Call.args = args;
@@ -935,7 +945,7 @@ irValue *ir_make_instr_call(irProcedure *p, irValue *value, irValue **args, isiz
return v;
}
-irValue *ir_make_instr_conv(irProcedure *p, irConvKind kind, irValue *value, Type *from, Type *to) {
+irValue *ir_instr_conv(irProcedure *p, irConvKind kind, irValue *value, Type *from, Type *to) {
irValue *v = ir_alloc_instr(p, irInstr_Conv);
v->Instr.Conv.kind = kind;
v->Instr.Conv.value = value;
@@ -944,20 +954,20 @@ irValue *ir_make_instr_conv(irProcedure *p, irConvKind kind, irValue *value, Typ
return v;
}
-irValue *ir_make_instr_comment(irProcedure *p, String text) {
+irValue *ir_instr_comment(irProcedure *p, String text) {
irValue *v = ir_alloc_instr(p, irInstr_Comment);
v->Instr.Comment.text = text;
return v;
}
-irValue *ir_make_instr_bounds_check(irProcedure *p, TokenPos pos, irValue *index, irValue *len) {
+irValue *ir_instr_bounds_check(irProcedure *p, TokenPos pos, irValue *index, irValue *len) {
irValue *v = ir_alloc_instr(p, irInstr_BoundsCheck);
v->Instr.BoundsCheck.pos = pos;
v->Instr.BoundsCheck.index = index;
v->Instr.BoundsCheck.len = len;
return v;
}
-irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue *low, irValue *high, irValue *max, bool is_substring) {
+irValue *ir_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue *low, irValue *high, irValue *max, bool is_substring) {
irValue *v = ir_alloc_instr(p, irInstr_SliceBoundsCheck);
v->Instr.SliceBoundsCheck.pos = pos;
v->Instr.SliceBoundsCheck.low = low;
@@ -966,7 +976,7 @@ irValue *ir_make_instr_slice_bounds_check(irProcedure *p, TokenPos pos, irValue
v->Instr.SliceBoundsCheck.is_substring = is_substring;
return v;
}
-irValue *ir_make_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
+irValue *ir_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, AstNode *expr, Entity *entity, bool is_addr, irValue *value) {
irValue *v = ir_alloc_instr(p, irInstr_DebugDeclare);
v->Instr.DebugDeclare.debug_info = debug_info;
v->Instr.DebugDeclare.expr = expr;
@@ -979,7 +989,7 @@ irValue *ir_make_instr_debug_declare(irProcedure *p, irDebugInfo *debug_info, As
-irValue *ir_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
+irValue *ir_value_constant(gbAllocator a, Type *type, ExactValue value) {
irValue *v = ir_alloc_value(a, irValue_Constant);
v->Constant.type = type;
v->Constant.value = value;
@@ -987,7 +997,7 @@ irValue *ir_make_value_constant(gbAllocator a, Type *type, ExactValue value) {
}
-irValue *ir_make_value_constant_slice(gbAllocator a, Type *type, irValue *backing_array, i64 count) {
+irValue *ir_value_constant_slice(gbAllocator a, Type *type, irValue *backing_array, i64 count) {
irValue *v = ir_alloc_value(a, irValue_ConstantSlice);
v->ConstantSlice.type = type;
v->ConstantSlice.backing_array = backing_array;
@@ -1006,38 +1016,40 @@ irValue *ir_emit(irProcedure *proc, irValue *instr) {
if (!ir_is_instr_terminating(i)) {
array_add(&b->instrs, instr);
}
+ } else if (instr->Instr.kind != irInstr_Unreachable) {
+ GB_PANIC("ir_emit: Instruction missing parent block");
}
return instr;
}
-irValue *ir_make_const_int(gbAllocator a, i64 i) {
- return ir_make_value_constant(a, t_int, make_exact_value_integer(i));
+irValue *ir_const_int(gbAllocator a, i64 i) {
+ return ir_value_constant(a, t_int, exact_value_integer(i));
}
-irValue *ir_make_const_i32(gbAllocator a, i64 i) {
- return ir_make_value_constant(a, t_i32, make_exact_value_integer(i));
+irValue *ir_const_i32(gbAllocator a, i64 i) {
+ return ir_value_constant(a, t_i32, exact_value_integer(i));
}
-irValue *ir_make_const_i64(gbAllocator a, i64 i) {
- return ir_make_value_constant(a, t_i64, make_exact_value_integer(i));
+irValue *ir_const_i64(gbAllocator a, i64 i) {
+ return ir_value_constant(a, t_i64, exact_value_integer(i));
}
-irValue *ir_make_const_u64(gbAllocator a, u64 i) {
- return ir_make_value_constant(a, t_u64, make_exact_value_integer(i));
+irValue *ir_const_u64(gbAllocator a, u64 i) {
+ return ir_value_constant(a, t_u64, exact_value_integer(i));
}
-irValue *ir_make_const_f32(gbAllocator a, f32 f) {
- return ir_make_value_constant(a, t_f32, make_exact_value_float(f));
+irValue *ir_const_f32(gbAllocator a, f32 f) {
+ return ir_value_constant(a, t_f32, exact_value_float(f));
}
-irValue *ir_make_const_f64(gbAllocator a, f64 f) {
- return ir_make_value_constant(a, t_f64, make_exact_value_float(f));
+irValue *ir_const_f64(gbAllocator a, f64 f) {
+ return ir_value_constant(a, t_f64, exact_value_float(f));
}
-irValue *ir_make_const_bool(gbAllocator a, bool b) {
- return ir_make_value_constant(a, t_bool, make_exact_value_bool(b != 0));
+irValue *ir_const_bool(gbAllocator a, bool b) {
+ return ir_value_constant(a, t_bool, exact_value_bool(b != 0));
}
-irValue *ir_make_const_string(gbAllocator a, String s) {
- return ir_make_value_constant(a, t_string, make_exact_value_string(s));
+irValue *ir_const_string(gbAllocator a, String s) {
+ return ir_value_constant(a, t_string, exact_value_string(s));
}
-irValue *ir_make_value_procedure(gbAllocator a, irModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) {
+irValue *ir_value_procedure(gbAllocator a, irModule *m, Entity *entity, Type *type, AstNode *type_expr, AstNode *body, String name) {
irValue *v = ir_alloc_value(a, irValue_Proc);
v->Proc.module = m;
v->Proc.entity = entity;
@@ -1063,7 +1075,7 @@ irValue *ir_generate_array(irModule *m, Type *elem_type, i64 count, String prefi
token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
"%.*s-%llx", LIT(prefix), id)-1;
Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, elem_type, count), false);
- irValue *value = ir_make_value_global(a, e, NULL);
+ irValue *value = ir_value_global(a, e, NULL);
value->Global.is_private = true;
ir_module_add_value(m, e, value);
map_ir_value_set(&m->members, hash_string(token.string), value);
@@ -1099,7 +1111,9 @@ irBlock *ir_new_block(irProcedure *proc, AstNode *node, char *label) {
void ir_add_block_to_proc(irProcedure *proc, irBlock *b) {
for_array(i, proc->blocks) {
- GB_ASSERT(proc->blocks.e[i] != b);
+ if (proc->blocks.e[i] == b) {
+ return;
+ }
}
array_add(&proc->blocks, b);
b->index = proc->block_count++;
@@ -1148,7 +1162,7 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
isize count = cl->elems.count;
if (count == 0) {
- return ir_make_value_nil(a, type);
+ return ir_value_nil(a, type);
}
Type *elem = base_type(type)->Slice.elem;
Type *t = make_type_array(a, elem, count);
@@ -1163,14 +1177,14 @@ irValue *ir_add_module_constant(irModule *m, Type *type, ExactValue value) {
String name = make_string(str, len-1);
Entity *e = make_entity_constant(a, NULL, make_token_ident(name), t, value);
- irValue *g = ir_make_value_global(a, e, backing_array);
+ irValue *g = ir_value_global(a, e, backing_array);
ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g);
- return ir_make_value_constant_slice(a, type, g, count);
+ return ir_value_constant_slice(a, type, g, count);
}
- return ir_make_value_constant(a, type, value);
+ return ir_value_constant(a, type, value);
}
irValue *ir_add_global_string_array(irModule *m, String string) {
@@ -1188,9 +1202,9 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
Token token = {Token_String};
token.string = name;
Type *type = make_type_array(a, t_u8, string.len);
- ExactValue ev = make_exact_value_string(string);
+ ExactValue ev = exact_value_string(string);
Entity *entity = make_entity_constant(a, NULL, token, type, ev);
- irValue *g = ir_make_value_global(a, entity, ir_add_module_constant(m, type, ev));
+ irValue *g = ir_value_global(a, entity, ir_add_module_constant(m, type, ev));
g->Global.is_private = true;
// g->Global.is_unnamed_addr = true;
// g->Global.is_constant = true;
@@ -1206,7 +1220,7 @@ irValue *ir_add_global_string_array(irModule *m, String string) {
irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) {
irBlock *b = proc->decl_block; // all variables must be in the first block
- irValue *instr = ir_make_instr_local(proc, e, true);
+ irValue *instr = ir_instr_local(proc, e, true);
instr->Instr.parent = b;
array_add(&b->instrs, instr);
array_add(&b->locals, instr);
@@ -1218,7 +1232,7 @@ irValue *ir_add_local(irProcedure *proc, Entity *e, AstNode *expr) {
if (expr != NULL) {
irDebugInfo *di = *map_ir_debug_info_get(&proc->module->debug_info, hash_pointer(proc->entity));
- ir_emit(proc, ir_make_instr_debug_declare(proc, di, expr, e, true, instr));
+ ir_emit(proc, ir_instr_debug_declare(proc, di, expr, e, true, instr));
}
return instr;
@@ -1250,7 +1264,7 @@ irValue *ir_add_local_generated(irProcedure *proc, Type *type) {
irValue *ir_add_param(irProcedure *proc, Entity *e, AstNode *expr) {
- irValue *v = ir_make_value_param(proc->module->allocator, proc, e);
+ irValue *v = ir_value_param(proc->module->allocator, proc, e);
#if 1
irValue *l = ir_add_local(proc, e, expr);
ir_emit_store(proc, l, v);
@@ -1328,27 +1342,27 @@ irDebugInfo *ir_add_debug_info_proc(irProcedure *proc, Entity *entity, String na
irValue *ir_emit_store(irProcedure *p, irValue *address, irValue *value) {
#if 1
// NOTE(bill): Sanity check
- Type *a = base_type(base_enum_type(type_deref(ir_type(address))));
- Type *b = base_type(base_enum_type(ir_type(value)));
+ Type *a = type_deref(ir_type(address));
+ Type *b = ir_type(value);
if (!is_type_untyped(b)) {
- GB_ASSERT_MSG(are_types_identical(a, b), "%s %s", type_to_string(a), type_to_string(b));
+ GB_ASSERT_MSG(are_types_identical(core_type(a), core_type(b)), "%s %s", type_to_string(a), type_to_string(b));
}
#endif
- return ir_emit(p, ir_make_instr_store(p, address, value));
+ return ir_emit(p, ir_instr_store(p, address, value));
}
irValue *ir_emit_load(irProcedure *p, irValue *address) {
- return ir_emit(p, ir_make_instr_load(p, address));
+ return ir_emit(p, ir_instr_load(p, address));
}
irValue *ir_emit_select(irProcedure *p, irValue *cond, irValue *t, irValue *f) {
- return ir_emit(p, ir_make_instr_select(p, cond, t, f));
+ return ir_emit(p, ir_instr_select(p, cond, t, f));
}
irValue *ir_emit_zero_init(irProcedure *p, irValue *address) {
- return ir_emit(p, ir_make_instr_zero_init(p, address));
+ return ir_emit(p, ir_instr_zero_init(p, address));
}
irValue *ir_emit_comment(irProcedure *p, String text) {
- return ir_emit(p, ir_make_instr_comment(p, text));
+ return ir_emit(p, ir_instr_comment(p, text));
}
@@ -1356,7 +1370,7 @@ irValue *ir_emit_call(irProcedure *p, irValue *value, irValue **args, isize arg_
Type *pt = base_type(ir_type(value));
GB_ASSERT(pt->kind == Type_Proc);
Type *results = pt->Proc.results;
- return ir_emit(p, ir_make_instr_call(p, value, args, arg_count, results));
+ return ir_emit(p, ir_instr_call(p, value, args, arg_count, results));
}
irValue *ir_emit_global_call(irProcedure *proc, char *name_, irValue **args, isize arg_count) {
@@ -1409,12 +1423,12 @@ void ir_close_scope(irProcedure *proc, irDeferExitKind kind, irBlock *block) {
void ir_emit_unreachable(irProcedure *proc) {
- ir_emit(proc, ir_make_instr_unreachable(proc));
+ ir_emit(proc, ir_instr_unreachable(proc));
}
void ir_emit_return(irProcedure *proc, irValue *v) {
ir_emit_defer_stmts(proc, irDeferExit_Return, NULL);
- ir_emit(proc, ir_make_instr_return(proc, v));
+ ir_emit(proc, ir_instr_return(proc, v));
}
void ir_emit_jump(irProcedure *proc, irBlock *target_block) {
@@ -1422,7 +1436,7 @@ void ir_emit_jump(irProcedure *proc, irBlock *target_block) {
if (b == NULL) {
return;
}
- ir_emit(proc, ir_make_instr_jump(proc, target_block));
+ ir_emit(proc, ir_instr_jump(proc, target_block));
ir_add_edge(b, target_block);
ir_start_block(proc, NULL);
}
@@ -1432,7 +1446,7 @@ void ir_emit_if(irProcedure *proc, irValue *cond, irBlock *true_block, irBlock *
if (b == NULL) {
return;
}
- ir_emit(proc, ir_make_instr_if(proc, cond, true_block, false_block));
+ ir_emit(proc, ir_instr_if(proc, cond, true_block, false_block));
ir_add_edge(b, true_block);
ir_add_edge(b, false_block);
ir_start_block(proc, NULL);
@@ -1444,7 +1458,7 @@ void ir_emit_startup_runtime(irProcedure *proc) {
}
irValue *ir_emit_bitcast(irProcedure *proc, irValue *data, Type *type) {
- return ir_emit(proc, ir_make_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
+ return ir_emit(proc, ir_instr_conv(proc, irConv_bitcast, data, ir_type(data), type));
}
@@ -1472,9 +1486,9 @@ irValue *ir_gen_map_header(irProcedure *proc, irValue *map_val, Type *map_type)
i64 entry_size = type_size_of(a, map_type->Map.entry_type);
i64 entry_align = type_align_of(a, map_type->Map.entry_type);
i64 value_offset = type_offset_of(a, map_type->Map.entry_type, 2);
- ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_make_const_int(a, entry_size));
- ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_make_const_int(a, entry_align));
- ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_make_const_int(a, value_offset));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, h, 2), ir_const_int(a, entry_size));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, h, 3), ir_const_int(a, entry_align));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, h, 4), ir_const_int(a, value_offset));
return ir_emit_load(proc, h);
@@ -1507,7 +1521,7 @@ irValue *ir_gen_map_key(irProcedure *proc, irValue *key, Type *key_type) {
ExactValue ev = str->Constant.value;
GB_ASSERT(ev.kind == ExactValue_String);
u64 hs = gb_fnv64a(ev.value_string.text, ev.value_string.len);
- hashed_str = ir_make_const_u64(proc->module->allocator, hs);
+ hashed_str = ir_const_u64(proc->module->allocator, hs);
} else {
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 1);
args[0] = str;
@@ -1628,7 +1642,7 @@ irValue *ir_addr_load(irProcedure *proc, irAddr addr) {
// if (addr.kind == irAddr_Vector) {
// irValue *v = ir_emit_load(proc, addr.addr);
- // return ir_emit(proc, ir_make_instr_extract_element(proc, v, addr.Vector.index));
+ // return ir_emit(proc, ir_instr_extract_element(proc, v, addr.Vector.index));
// }
Type *t = base_type(ir_type(addr.addr));
if (t->kind == Type_Proc) {
@@ -1642,7 +1656,7 @@ irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index);
irValue *ir_emit_ptr_offset(irProcedure *proc, irValue *ptr, irValue *offset) {
offset = ir_emit_conv(proc, offset, t_int);
- return ir_emit(proc, ir_make_instr_ptr_offset(proc, ptr, offset));
+ return ir_emit(proc, ir_instr_ptr_offset(proc, ptr, offset));
}
irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *right, Type *type) {
@@ -1691,7 +1705,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
irModule *m = proc->module;
Type *ptr_type = base_type(t_left);
GB_ASSERT(!is_type_rawptr(ptr_type));
- irValue *elem_size = ir_make_const_int(m->allocator, type_size_of(m->allocator, ptr_type->Pointer.elem));
+ irValue *elem_size = ir_const_int(m->allocator, type_size_of(m->allocator, ptr_type->Pointer.elem));
irValue *x = ir_emit_conv(proc, left, type);
irValue *y = ir_emit_conv(proc, right, type);
irValue *diff = ir_emit_arith(proc, op, x, y, type);
@@ -1716,7 +1730,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
case Token_AndNot: {
// NOTE(bill): x &~ y == x & (~y) == x & (y ~ -1)
// NOTE(bill): "not" `x` == `x` "xor" `-1`
- irValue *neg = ir_add_module_constant(proc->module, type, make_exact_value_integer(-1));
+ irValue *neg = ir_add_module_constant(proc->module, type, exact_value_integer(-1));
op = Token_Xor;
right = ir_emit_arith(proc, op, right, neg, type);
GB_ASSERT(right->Instr.kind == irInstr_BinaryOp);
@@ -1736,7 +1750,7 @@ irValue *ir_emit_arith(irProcedure *proc, TokenKind op, irValue *left, irValue *
break;
}
- return ir_emit(proc, ir_make_instr_binary_op(proc, op, left, right, type));
+ return ir_emit(proc, ir_instr_binary_op(proc, op, left, right, type));
}
irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irValue *right) {
@@ -1780,7 +1794,7 @@ irValue *ir_emit_comp(irProcedure *proc, TokenKind op_kind, irValue *left, irVal
}
- return ir_emit(proc, ir_make_instr_binary_op(proc, op_kind, left, right, result));
+ return ir_emit(proc, ir_instr_binary_op(proc, op_kind, left, right, result));
}
irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index) {
@@ -1792,18 +1806,18 @@ irValue *ir_emit_array_ep(irProcedure *proc, irValue *s, irValue *index) {
// NOTE(bill): For some weird legacy reason in LLVM, structure elements must be accessed as an i32
index = ir_emit_conv(proc, index, t_i32);
- return ir_emit(proc, ir_make_instr_array_element_ptr(proc, s, index));
+ return ir_emit(proc, ir_instr_array_element_ptr(proc, s, index));
}
irValue *ir_emit_array_epi(irProcedure *proc, irValue *s, i32 index) {
- return ir_emit_array_ep(proc, s, ir_make_const_i32(proc->module->allocator, index));
+ return ir_emit_array_ep(proc, s, ir_const_i32(proc->module->allocator, index));
}
irValue *ir_emit_union_tag_ptr(irProcedure *proc, irValue *u) {
Type *t = ir_type(u);
- GB_ASSERT(is_type_pointer(t) &&
- is_type_union(type_deref(t)));
- irValue *tag_ptr = ir_emit(proc, ir_make_instr_union_tag_ptr(proc, u));
+ GB_ASSERT_MSG(is_type_pointer(t) &&
+ is_type_union(type_deref(t)), "%s", type_to_string(t));
+ irValue *tag_ptr = ir_emit(proc, ir_instr_union_tag_ptr(proc, u));
Type *tpt = ir_type(tag_ptr);
GB_ASSERT(is_type_pointer(tpt));
tpt = base_type(type_deref(tpt));
@@ -1815,7 +1829,7 @@ irValue *ir_emit_union_tag_value(irProcedure *proc, irValue *u) {
Type *t = ir_type(u);
GB_ASSERT(is_type_union(t));
GB_ASSERT(are_types_identical(t, ir_type(u)));
- return ir_emit(proc, ir_make_instr_union_tag_value(proc, u));
+ return ir_emit(proc, ir_instr_union_tag_value(proc, u));
}
@@ -1837,7 +1851,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
result_type = make_type_pointer(a, t->Record.fields[index]->type);
i64 offset = t->Record.offsets[index];
irValue *ptr = ir_emit_conv(proc, s, t_u8_ptr);
- ptr = ir_emit_ptr_offset(proc, ptr, ir_make_const_int(a, offset));
+ ptr = ir_emit_ptr_offset(proc, ptr, ir_const_int(a, offset));
return ir_emit_conv(proc, ptr, result_type);
} else if (is_type_tuple(t)) {
GB_ASSERT(t->Tuple.variable_count > 0);
@@ -1878,7 +1892,7 @@ irValue *ir_emit_struct_ep(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT(result_type != NULL);
- gep = ir_make_instr_struct_element_ptr(proc, s, index, result_type);
+ gep = ir_instr_struct_element_ptr(proc, s, index, result_type);
return ir_emit(proc, gep);
}
@@ -1902,7 +1916,7 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
i64 offset = t->Record.offsets[index];
irValue *ptr = ir_address_from_load_or_generate_local(proc, s);
ptr = ir_emit_conv(proc, s, t_u8_ptr);
- ptr = ir_emit_ptr_offset(proc, ptr, ir_make_const_int(a, offset));
+ ptr = ir_emit_ptr_offset(proc, ptr, ir_const_int(a, offset));
ptr = ir_emit_conv(proc, ptr, ptr_type);
return ir_emit_load(proc, ptr);
} else if (is_type_tuple(t)) {
@@ -1944,12 +1958,13 @@ irValue *ir_emit_struct_ev(irProcedure *proc, irValue *s, i32 index) {
GB_ASSERT(result_type != NULL);
- return ir_emit(proc, ir_make_instr_struct_extract_value(proc, s, index, result_type));
+ return ir_emit(proc, ir_instr_struct_extract_value(proc, s, index, result_type));
}
-irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selection sel) {
+irValue *ir_emit_deep_field_gep(irProcedure *proc, irValue *e, Selection sel) {
GB_ASSERT(sel.index.count > 0);
+ Type *type = type_deref(ir_type(e));
for_array(i, sel.index) {
i32 index = cast(i32)sel.index.e[i];
@@ -1958,7 +1973,7 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec
e = ir_emit_load(proc, e);
e = ir_emit_ptr_offset(proc, e, v_zero); // TODO(bill): Do I need these copies?
}
- type = base_type(type);
+ type = core_type(type);
if (is_type_raw_union(type)) {
@@ -2005,7 +2020,7 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec
case 2: e = ir_emit_struct_ep(proc, e, 3); break; // allocator
}
} else {
- GB_PANIC("un-gep-able type");
+ GB_PANIC("un-gep-able type %s", type_to_string(type));
}
}
@@ -2013,8 +2028,9 @@ irValue *ir_emit_deep_field_gep(irProcedure *proc, Type *type, irValue *e, Selec
}
-irValue *ir_emit_deep_field_ev(irProcedure *proc, Type *type, irValue *e, Selection sel) {
+irValue *ir_emit_deep_field_ev(irProcedure *proc, irValue *e, Selection sel) {
GB_ASSERT(sel.index.count > 0);
+ Type *type = ir_type(e);
for_array(i, sel.index) {
i32 index = cast(i32)sel.index.e[i];
@@ -2055,7 +2071,7 @@ irValue *ir_array_elem(irProcedure *proc, irValue *array) {
irValue *ir_array_len(irProcedure *proc, irValue *array) {
Type *t = base_type(ir_type(array));
GB_ASSERT(t->kind == Type_Array);
- return ir_make_const_int(proc->module->allocator, t->Array.count);
+ return ir_const_int(proc->module->allocator, t->Array.count);
}
irValue *ir_vector_elem(irProcedure *proc, irValue *vector) {
@@ -2218,13 +2234,13 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
return value;
}
- Type *src = base_type(base_enum_type(src_type));
- Type *dst = base_type(base_enum_type(t));
+ Type *src = core_type(src_type);
+ Type *dst = core_type(t);
// if (is_type_untyped_nil(src) && type_has_nil(dst)) {
if (is_type_untyped_nil(src)) {
- return ir_make_value_nil(proc->module->allocator, t);
+ return ir_value_nil(proc->module->allocator, t);
}
if (value->kind == irValue_Constant) {
@@ -2244,7 +2260,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
} else if (is_type_pointer(dst)) {
// IMPORTANT NOTE(bill): LLVM doesn't support pointer constants expect `null`
irValue *i = ir_add_module_constant(proc->module, t_uint, ev);
- return ir_emit(proc, ir_make_instr_conv(proc, irConv_inttoptr, i, t_uint, dst));
+ return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, i, t_uint, dst));
}
return ir_add_module_constant(proc->module, t, ev);
}
@@ -2261,31 +2277,27 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
i64 sz = type_size_of(proc->module->allocator, src);
i64 dz = type_size_of(proc->module->allocator, dst);
irConvKind kind = irConv_trunc;
- if (dz == sz) {
+
+ if (dz < sz) {
+ kind = irConv_trunc;
+ } else if (dz == sz) {
// NOTE(bill): In LLVM, all integers are signed and rely upon 2's compliment
// NOTE(bill): Copy the value just for type correctness
kind = irConv_bitcast;
} else if (dz > sz) {
- kind = irConv_zext;
-
- // TODO(bill): figure out the rules completely
- bool ss = !is_type_unsigned(src);
- bool ds = !is_type_unsigned(dst);
- if (ss && ds) {
- kind = irConv_sext;
- } else if (ss) {
- kind = irConv_sext;
+ if (is_type_unsigned(src)) {
+ kind = irConv_zext; // zero extent
} else {
- kind = irConv_zext;
+ kind = irConv_sext; // sign extent
}
}
- return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, kind, value, src, dst));
}
// boolean -> integer
if (is_type_boolean(src) && is_type_integer(dst)) {
- return ir_emit(proc, ir_make_instr_conv(proc, irConv_zext, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, irConv_zext, value, src, dst));
}
// integer -> boolean
@@ -2302,7 +2314,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
if (dz >= sz) {
kind = irConv_fpext;
}
- return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, kind, value, src, dst));
}
// float <-> integer
@@ -2311,22 +2323,22 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
if (is_type_unsigned(dst)) {
kind = irConv_fptoui;
}
- return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, kind, value, src, dst));
}
if (is_type_integer(src) && is_type_float(dst)) {
irConvKind kind = irConv_sitofp;
if (is_type_unsigned(src)) {
kind = irConv_uitofp;
}
- return ir_emit(proc, ir_make_instr_conv(proc, kind, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, kind, value, src, dst));
}
// Pointer <-> int
if (is_type_pointer(src) && is_type_int_or_uint(dst)) {
- return ir_emit(proc, ir_make_instr_conv(proc, irConv_ptrtoint, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, irConv_ptrtoint, value, src, dst));
}
if (is_type_int_or_uint(src) && is_type_pointer(dst)) {
- return ir_emit(proc, ir_make_instr_conv(proc, irConv_inttoptr, value, src, dst));
+ return ir_emit(proc, ir_instr_conv(proc, irConv_inttoptr, value, src, dst));
}
if (is_type_union(dst)) {
@@ -2337,7 +2349,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
gbAllocator allocator = proc->module->allocator;
irValue *parent = ir_add_local_generated(proc, t);
irValue *tag_ptr = ir_emit_union_tag_ptr(proc, parent);
- ir_emit_store(proc, tag_ptr, ir_make_const_int(allocator, i));
+ ir_emit_store(proc, tag_ptr, ir_const_int(allocator, i));
irValue *underlying = ir_emit_conv(proc, parent, make_type_pointer(allocator, src_type));
ir_emit_store(proc, underlying, value);
@@ -2363,7 +2375,7 @@ irValue *ir_emit_conv(irProcedure *proc, irValue *value, Type *t) {
if (src_is_ptr) {
value = ir_emit_load(proc, value);
}
- return ir_emit_deep_field_ev(proc, sb, value, sel);
+ return ir_emit_deep_field_ev(proc, value, sel);
}
}
}
@@ -2535,7 +2547,7 @@ irValue *ir_emit_down_cast(irProcedure *proc, irValue *value, Type *t) {
irValue *bytes = ir_emit_conv(proc, value, t_u8_ptr);
i64 offset_ = type_offset_of_from_selection(allocator, type_deref(t), sel);
- irValue *offset = ir_make_const_int(allocator, -offset_);
+ irValue *offset = ir_const_int(allocator, -offset_);
irValue *head = ir_emit_ptr_offset(proc, bytes, offset);
return ir_emit_conv(proc, head, t);
}
@@ -2567,7 +2579,7 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
for (isize i = 1; i < src->Record.variant_count; i++) {
Entity *f = src->Record.variants[i];
if (are_types_identical(f->type, dst)) {
- dst_tag = ir_make_const_int(a, i);
+ dst_tag = ir_const_int(a, i);
break;
}
}
@@ -2602,7 +2614,7 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
for (isize i = 1; i < src->Record.variant_count; i++) {
Entity *f = src->Record.variants[i];
if (are_types_identical(f->type, dst)) {
- dst_tag = ir_make_const_int(a, i);
+ dst_tag = ir_const_int(a, i);
break;
}
}
@@ -2633,9 +2645,9 @@ irValue *ir_emit_union_cast(irProcedure *proc, irValue *value, Type *type, Token
irValue **args = gb_alloc_array(a, irValue *, 6);
args[0] = ok;
- args[1] = ir_make_const_string(a, pos.file);
- args[2] = ir_make_const_int(a, pos.line);
- args[3] = ir_make_const_int(a, pos.column);
+ args[1] = ir_const_string(a, pos.file);
+ args[2] = ir_const_int(a, pos.line);
+ args[3] = ir_const_int(a, pos.column);
args[4] = ir_type_info(proc, src_type);
args[5] = ir_type_info(proc, dst_type);
@@ -2699,7 +2711,7 @@ irValue *ir_type_info(irProcedure *proc, Type *type) {
// gb_printf_err("%d %s\n", entry_index, type_to_string(type));
- return ir_emit_array_ep(proc, ir_global_type_info_data, ir_make_const_i32(proc->module->allocator, entry_index));
+ return ir_emit_array_ep(proc, ir_global_type_info_data, ir_const_i32(proc->module->allocator, entry_index));
}
@@ -2762,7 +2774,7 @@ irValue *ir_emit_logical_binary_expr(irProcedure *proc, AstNode *expr) {
ir_emit_jump(proc, done);
ir_start_block(proc, done);
- return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
+ return ir_emit(proc, ir_instr_phi(proc, edges, type));
#endif
}
@@ -2775,7 +2787,7 @@ void ir_emit_bounds_check(irProcedure *proc, Token token, irValue *index, irValu
index = ir_emit_conv(proc, index, t_int);
len = ir_emit_conv(proc, len, t_int);
- ir_emit(proc, ir_make_instr_bounds_check(proc, token.pos, index, len));
+ ir_emit(proc, ir_instr_bounds_check(proc, token.pos, index, len));
}
void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, irValue *high, irValue *max, bool is_substring) {
@@ -2786,7 +2798,7 @@ void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, ir
low = ir_emit_conv(proc, low, t_int);
high = ir_emit_conv(proc, high, t_int);
- ir_emit(proc, ir_make_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring));
+ ir_emit(proc, ir_instr_slice_bounds_check(proc, token.pos, low, high, max, is_substring));
}
@@ -2797,43 +2809,120 @@ void ir_emit_slice_bounds_check(irProcedure *proc, Token token, irValue *low, ir
//
////////////////////////////////////////////////////////////////
+String ir_mangle_name(irGen *s, String path, Entity *e) {
+ // NOTE(bill): prefix names not in the init scope
+ // TODO(bill): make robust and not just rely on the file's name
+ String name = e->token.string;
+ irModule *m = &s->module;
+ CheckerInfo *info = m->info;
+ gbAllocator a = m->allocator;
+ AstFile *file = *map_ast_file_get(&info->files, hash_string(path));
-void ir_push_target_list(irProcedure *proc, irBlock *break_, irBlock *continue_, irBlock *fallthrough_) {
- irTargetList *tl = gb_alloc_item(proc->module->allocator, irTargetList);
- tl->prev = proc->target_list;
- tl->break_ = break_;
- tl->continue_ = continue_;
- tl->fallthrough_ = fallthrough_;
- proc->target_list = tl;
-}
+ char *str = gb_alloc_array(a, char, path.len+1);
+ gb_memmove(str, path.text, path.len);
+ str[path.len] = 0;
+ for (isize i = 0; i < path.len; i++) {
+ if (str[i] == '\\') {
+ str[i] = '/';
+ }
+ }
-void ir_pop_target_list(irProcedure *proc) {
- proc->target_list = proc->target_list->prev;
+ char const *base = gb_path_base_name(str);
+ char const *ext = gb_path_extension(base);
+ isize base_len = ext-1-base;
+
+ isize max_len = base_len + 1 + 10 + 1 + name.len;
+ bool is_overloaded = check_is_entity_overloaded(e);
+ if (is_overloaded) {
+ max_len += 21;
+ }
+
+ u8 *new_name = gb_alloc_array(a, u8, max_len);
+ isize new_name_len = gb_snprintf(
+ cast(char *)new_name, max_len,
+ "%.*s-%u.%.*s",
+ cast(int)base_len, base,
+ file->id,
+ LIT(name));
+ if (is_overloaded) {
+ char *str = cast(char *)new_name + new_name_len-1;
+ isize len = max_len-new_name_len;
+ isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e);
+ new_name_len += extra-1;
+ }
+
+ return make_string(new_name, new_name_len-1);
}
-void ir_mangle_sub_type_name(irModule *m, Entity *field, String parent) {
+void ir_mangle_add_sub_type_name(irModule *m, Entity *field, String parent) {
if (field->kind != Entity_TypeName) {
return;
}
- String cn = field->token.string;
-
- isize len = parent.len + 1 + cn.len;
- String child = {NULL, len};
- child.text = gb_alloc_array(m->allocator, u8, len);
- isize i = 0;
- gb_memmove(child.text+i, parent.text, parent.len);
- i += parent.len;
- child.text[i++] = '.';
- gb_memmove(child.text+i, cn.text, cn.len);
+ String cn = field->token.string;
+ isize len = parent.len + 1 + 16 + 1 + cn.len;
+ u8 *text = gb_alloc_array(m->allocator, u8, len);
+ isize new_name_len = gb_snprintf(cast(char *)text, len,
+ "%.*s.%.*s", LIT(parent), LIT(cn));
+ String child = {text, new_name_len-1};
map_string_set(&m->type_names, hash_pointer(field->type), child);
ir_gen_global_type_name(m, field, child);
}
+
+irBranchBlocks ir_lookup_branch_blocks(irProcedure *proc, AstNode *ident) {
+ GB_ASSERT(ident->kind == AstNode_Ident);
+ Entity **found = map_entity_get(&proc->module->info->uses, hash_pointer(ident));
+ GB_ASSERT(found != NULL);
+ Entity *e = *found;
+ GB_ASSERT(e->kind == Entity_Label);
+ for_array(i, proc->branch_blocks) {
+ irBranchBlocks *b = &proc->branch_blocks.e[i];
+ if (b->label == e->Label.node) {
+ return *b;
+ }
+ }
+
+ GB_PANIC("Unreachable");
+ return (irBranchBlocks){0};
+}
+
+
+void ir_push_target_list(irProcedure *proc, AstNode *label, irBlock *break_, irBlock *continue_, irBlock *fallthrough_) {
+ irTargetList *tl = gb_alloc_item(proc->module->allocator, irTargetList);
+ tl->prev = proc->target_list;
+ tl->break_ = break_;
+ tl->continue_ = continue_;
+ tl->fallthrough_ = fallthrough_;
+ proc->target_list = tl;
+
+ if (label != NULL) { // Set label blocks
+ GB_ASSERT(label->kind == AstNode_Label);
+
+ for_array(i, proc->branch_blocks) {
+ irBranchBlocks *b = &proc->branch_blocks.e[i];
+ GB_ASSERT(b->label != NULL && label != NULL);
+ GB_ASSERT(b->label->kind == AstNode_Label);
+ if (b->label == label) {
+ b->break_ = break_;
+ b->continue_ = continue_;
+ return;
+ }
+ }
+
+ GB_PANIC("ir_set_label_blocks: Unreachable");
+ }
+}
+
+void ir_pop_target_list(irProcedure *proc) {
+ proc->target_list = proc->target_list->prev;
+}
+
+
void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
- irValue *t = ir_make_value_type_name(m->allocator, name, e->type);
+ irValue *t = ir_value_type_name(m->allocator, name, e->type);
ir_module_add_value(m, e, t);
map_ir_value_set(&m->members, hash_string(name), t);
@@ -2841,7 +2930,7 @@ void ir_gen_global_type_name(irModule *m, Entity *e, String name) {
Type *bt = base_type(e->type);
// NOTE(bill): Zeroth entry is null (for `match type` stmts)
for (isize j = 1; j < bt->Record.variant_count; j++) {
- ir_mangle_sub_type_name(m, bt->Record.variants[j], name);
+ ir_mangle_add_sub_type_name(m, bt->Record.variants[j], name);
}
}
}
@@ -2877,8 +2966,21 @@ irValue *ir_find_global_variable(irProcedure *proc, String name) {
void ir_build_stmt_list(irProcedure *proc, AstNodeArray stmts);
-irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv) {
+
+irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
expr = unparen_expr(expr);
+
+ TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr));
+ GB_ASSERT_NOT_NULL(tv);
+
+ if (tv->value.kind != ExactValue_Invalid) {
+ return ir_add_module_constant(proc->module, tv->type, tv->value);
+ }
+
+ if (tv->mode == Addressing_Variable) {
+ return ir_addr_load(proc, ir_build_addr(proc, expr));
+ }
+
switch (expr->kind) {
case_ast_node(bl, BasicLit, expr);
TokenPos pos = bl->pos;
@@ -2903,7 +3005,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
LIT(token.pos.file), token.pos.line, token.pos.column);
return NULL;
} else if (e->kind == Entity_Nil) {
- return ir_make_value_nil(proc->module->allocator, tv->type);
+ return ir_value_nil(proc->module->allocator, tv->type);
}
irValue **found = map_ir_value_get(&proc->module->values, hash_pointer(e));
@@ -2968,7 +3070,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
Type *type = type_of_expr(proc->module->info, expr);
- return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
+ return ir_emit(proc, ir_instr_phi(proc, edges, type));
case_end;
#if 0
@@ -3008,7 +3110,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
Type *type = type_of_expr(proc->module->info, expr);
- return ir_emit(proc, ir_make_instr_phi(proc, edges, type));
+ return ir_emit(proc, ir_instr_phi(proc, edges, type));
case_end;
#endif
@@ -3051,7 +3153,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
case Token_Not: // Boolean not
case Token_Xor: // Bitwise not
case Token_Sub: // Bitwise not
- return ir_emit(proc, ir_make_instr_unary_op(proc, ue->op.kind, ir_build_expr(proc, ue->expr), tv->type));
+ return ir_emit(proc, ir_instr_unary_op(proc, ue->op.kind, ir_build_expr(proc, ue->expr), tv->type));
}
case_end;
@@ -3106,7 +3208,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
String name = make_string(name_text, name_len-1);
Type *type = type_of_expr(proc->module->info, expr);
- irValue *value = ir_make_value_procedure(proc->module->allocator,
+ irValue *value = ir_value_procedure(proc->module->allocator,
proc->module, NULL, type, pl->type, pl->body, name);
value->Proc.tags = pl->tags;
@@ -3159,8 +3261,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
i64 a = type_align_of(allocator, type);
irValue **args = gb_alloc_array(allocator, irValue *, 2);
- args[0] = ir_make_const_int(allocator, s);
- args[1] = ir_make_const_int(allocator, a);
+ args[0] = ir_const_int(allocator, s);
+ args[1] = ir_const_int(allocator, a);
irValue *call = ir_emit_global_call(proc, "alloc_align", args, 2);
irValue *v = ir_emit_conv(proc, call, ptr_type);
return v;
@@ -3179,8 +3281,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
i64 s = type_size_of(allocator, type);
i64 a = type_align_of(allocator, type);
- irValue *elem_size = ir_make_const_int(allocator, s);
- irValue *elem_align = ir_make_const_int(allocator, a);
+ irValue *elem_size = ir_const_int(allocator, s);
+ irValue *elem_align = ir_const_int(allocator, a);
irValue *count = ir_emit_conv(proc, ir_build_expr(proc, ce->args.e[1]), t_int);
irValue *capacity = count;
@@ -3293,8 +3395,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
if (is_type_dynamic_array(type)) {
Type *elem = type->DynamicArray.elem;
- irValue *elem_size = ir_make_const_int(a, type_size_of(a, elem));
- irValue *elem_align = ir_make_const_int(a, type_align_of(a, elem));
+ irValue *elem_size = ir_const_int(a, type_size_of(a, elem));
+ irValue *elem_align = ir_const_int(a, type_align_of(a, elem));
ptr = ir_emit_conv(proc, ptr, t_rawptr);
@@ -3316,8 +3418,13 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
case BuiltinProc_clear: {
ir_emit_comment(proc, str_lit("clear"));
- irValue *ptr = ir_build_addr(proc, ce->args.e[0]).addr;
- Type *t = base_type(type_deref(ir_type(ptr)));
+ Type *original_type = type_of_expr(proc->module->info, ce->args.e[0]);
+ irAddr addr = ir_build_addr(proc, ce->args.e[0]);
+ irValue *ptr = addr.addr;
+ if (is_type_pointer(original_type)) {
+ ptr = ir_addr_load(proc, addr);
+ }
+ Type *t = base_type(type_deref(original_type));
if (is_type_dynamic_array(t)) {
irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
ir_emit_store(proc, count_ptr, v_zero);
@@ -3326,6 +3433,9 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *ea = ir_emit_struct_ep(proc, ptr, 1);
ir_emit_store(proc, ir_emit_struct_ep(proc, ha, 1), v_zero);
ir_emit_store(proc, ir_emit_struct_ep(proc, ea, 1), v_zero);
+ } else if (is_type_slice(t)) {
+ irValue *count_ptr = ir_emit_struct_ep(proc, ptr, 1);
+ ir_emit_store(proc, count_ptr, v_zero);
} else {
GB_PANIC("TODO(bill): ir clear for `%s`", type_to_string(t));
}
@@ -3356,8 +3466,8 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
GB_PANIC("Invalid type to append");
}
- irValue *elem_size = ir_make_const_int(a, type_size_of(a, elem_type));
- irValue *elem_align = ir_make_const_int(a, type_align_of(a, elem_type));
+ irValue *elem_size = ir_const_int(a, type_size_of(a, elem_type));
+ irValue *elem_align = ir_const_int(a, type_align_of(a, elem_type));
array_ptr = ir_emit_conv(proc, array_ptr, t_rawptr);
@@ -3411,7 +3521,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
}
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
- irValue *len = ir_make_const_int(a, slice_len);
+ irValue *len = ir_const_int(a, slice_len);
ir_fill_slice(proc, slice, base_elem, len, len);
}
@@ -3478,10 +3588,10 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
- args[0] = ir_make_const_string(proc->module->allocator, pos.file);
- args[1] = ir_make_const_int(proc->module->allocator, pos.line);
- args[2] = ir_make_const_int(proc->module->allocator, pos.column);
- args[3] = ir_make_const_string(proc->module->allocator, expr_str);
+ args[0] = ir_const_string(proc->module->allocator, pos.file);
+ args[1] = ir_const_int(proc->module->allocator, pos.line);
+ args[2] = ir_const_int(proc->module->allocator, pos.column);
+ args[3] = ir_const_string(proc->module->allocator, expr_str);
ir_emit_global_call(proc, "__assert", args, 4);
ir_emit_jump(proc, done);
@@ -3499,9 +3609,9 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
TokenPos pos = token.pos;
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 4);
- args[0] = ir_make_const_string(proc->module->allocator, pos.file);
- args[1] = ir_make_const_int(proc->module->allocator, pos.line);
- args[2] = ir_make_const_int(proc->module->allocator, pos.column);
+ args[0] = ir_const_string(proc->module->allocator, pos.file);
+ args[1] = ir_const_int(proc->module->allocator, pos.line);
+ args[2] = ir_const_int(proc->module->allocator, pos.column);
args[3] = msg;
ir_emit_global_call(proc, "__panic", args, 4);
@@ -3530,7 +3640,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *cond = ir_emit_comp(proc, Token_Lt, len_dst, len_src);
irValue *len = ir_emit_select(proc, cond, len_dst, len_src);
- irValue *elem_size = ir_make_const_int(proc->module->allocator, size_of_elem);
+ irValue *elem_size = ir_const_int(proc->module->allocator, size_of_elem);
irValue *byte_count = ir_emit_arith(proc, Token_Mul, len, elem_size, t_int);
irValue **args = gb_alloc_array(proc->module->allocator, irValue *, 3);
@@ -3567,7 +3677,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
}
ir_emit_comment(proc, str_lit("swizzle.end"));
return ir_emit_load(proc, dst);
- // return ir_emit(proc, ir_make_instr_vector_shuffle(proc, vector, indices, index_count));
+ // return ir_emit(proc, ir_instr_vector_shuffle(proc, vector, indices, index_count));
} break;
case BuiltinProc_slice_ptr: {
@@ -3575,10 +3685,15 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *ptr = ir_build_expr(proc, ce->args.e[0]);
irValue *count = ir_build_expr(proc, ce->args.e[1]);
count = ir_emit_conv(proc, count, t_int);
+ irValue *capacity = count;
+ if (ce->args.count > 2) {
+ capacity = ir_build_expr(proc, ce->args.e[2]);
+ capacity = ir_emit_conv(proc, capacity, t_int);
+ }
Type *slice_type = make_type_slice(proc->module->allocator, type_deref(ir_type(ptr)));
irValue *slice = ir_add_local_generated(proc, slice_type);
- ir_fill_slice(proc, slice, ptr, count, count);
+ ir_fill_slice(proc, slice, ptr, count, capacity);
return ir_emit_load(proc, slice);
} break;
@@ -3594,7 +3709,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
irValue *ptr = ir_emit_conv(proc, ir_slice_elem(proc, s), t_u8_ptr);
irValue *count = ir_slice_count(proc, s);
- count = ir_emit_arith(proc, Token_Mul, count, ir_make_const_int(proc->module->allocator, elem_size), t_int);
+ count = ir_emit_arith(proc, Token_Mul, count, ir_const_int(proc->module->allocator, elem_size), t_int);
ir_fill_slice(proc, slice, ptr, count, count);
return ir_emit_load(proc, slice);
} break;
@@ -3623,7 +3738,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
Type *t = ir_type(x);
irValue *zero = ir_emit_conv(proc, v_zero, t);
irValue *cond = ir_emit_comp(proc, Token_Lt, x, zero);
- irValue *neg = ir_emit(proc, ir_make_instr_unary_op(proc, Token_Sub, x, t));
+ irValue *neg = ir_emit(proc, ir_instr_unary_op(proc, Token_Sub, x, t));
return ir_emit_select(proc, cond, neg, x);
} break;
@@ -3719,7 +3834,7 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
}
irValue *base_elem = ir_emit_array_epi(proc, base_array, 0);
- irValue *len = ir_make_const_int(allocator, slice_len);
+ irValue *len = ir_const_int(allocator, slice_len);
ir_fill_slice(proc, slice, base_elem, len, len);
}
@@ -3743,27 +3858,6 @@ irValue *ir_build_single_expr(irProcedure *proc, AstNode *expr, TypeAndValue *tv
return NULL;
}
-
-irValue *ir_build_expr(irProcedure *proc, AstNode *expr) {
- expr = unparen_expr(expr);
-
- TypeAndValue *tv = map_tav_get(&proc->module->info->types, hash_pointer(expr));
- GB_ASSERT_NOT_NULL(tv);
-
- if (tv->value.kind != ExactValue_Invalid) {
- return ir_add_module_constant(proc->module, tv->type, tv->value);
- }
-
- irValue *value = NULL;
- if (tv->mode == Addressing_Variable) {
- value = ir_addr_load(proc, ir_build_addr(proc, expr));
- } else {
- value = ir_build_single_expr(proc, expr, tv);
- }
-
- return value;
-}
-
irValue *ir_get_using_variable(irProcedure *proc, Entity *e) {
GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous);
String name = e->token.string;
@@ -3778,7 +3872,8 @@ irValue *ir_get_using_variable(irProcedure *proc, Entity *e) {
v = ir_build_addr(proc, e->using_expr).addr;
}
GB_ASSERT(v != NULL);
- return ir_emit_deep_field_gep(proc, parent->type, v, sel);
+ GB_ASSERT(parent->type == type_deref(ir_type(v)));
+ return ir_emit_deep_field_gep(proc, v, sel);
}
// irValue *ir_add_using_variable(irProcedure *proc, Entity *e) {
@@ -3817,7 +3912,7 @@ irAddr ir_build_addr_from_entity(irProcedure *proc, Entity *e, AstNode *expr) {
GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
}
- return ir_make_addr(v);
+ return ir_addr(v);
}
irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
@@ -3831,7 +3926,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
GB_ASSERT(v != NULL);
- return ir_make_addr(v);
+ return ir_addr(v);
case_end;
case_ast_node(i, Ident, expr);
@@ -3883,7 +3978,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *record_info = ir_emit_conv(proc, ti_ptr, t_type_info_record_ptr);
names_ptr = ir_emit_struct_ep(proc, record_info, 1);
}
- return ir_make_addr(names_ptr);
+ return ir_addr(names_ptr);
} else {
GB_PANIC("Unhandled TypeField %.*s", LIT(name));
}
@@ -3894,8 +3989,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
GB_ASSERT(sel.entity != NULL);
irValue *a = ir_build_addr(proc, se->expr).addr;
- a = ir_emit_deep_field_gep(proc, type, a, sel);
- return ir_make_addr(a);
+ a = ir_emit_deep_field_gep(proc, a, sel);
+ return ir_addr(a);
} else {
Type *type = base_type(type_of_expr(proc->module->info, se->expr));
GB_ASSERT(is_type_integer(type));
@@ -3906,8 +4001,8 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
GB_ASSERT(sel.entity != NULL);
irValue *a = ir_build_addr(proc, se->expr).addr;
- a = ir_emit_deep_field_gep(proc, type, a, sel);
- return ir_make_addr(a);
+ a = ir_emit_deep_field_gep(proc, a, sel);
+ return ir_addr(a);
}
case_end;
@@ -3919,7 +4014,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
Type *type = type_of_expr(proc->module->info, expr);
irValue *v = ir_add_local_generated(proc, type);
ir_emit_store(proc, v, ir_emit_conv(proc, ir_build_expr(proc, ce->expr), type));
- return ir_make_addr(v);
+ return ir_addr(v);
}
case Token_transmute: {
ir_emit_comment(proc, str_lit("Cast - transmute"));
@@ -3927,7 +4022,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
Type *type = type_of_expr(proc->module->info, expr);
irValue *v = ir_add_local_generated(proc, type);
ir_emit_store(proc, v, ir_emit_transmute(proc, ir_build_expr(proc, ce->expr), type));
- return ir_make_addr(v);
+ return ir_addr(v);
}
case Token_down_cast: {
ir_emit_comment(proc, str_lit("Cast - down_cast"));
@@ -3935,7 +4030,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
Type *type = type_of_expr(proc->module->info, expr);
irValue *v = ir_add_local_generated(proc, type);
ir_emit_store(proc, v, ir_emit_down_cast(proc, ir_build_expr(proc, ce->expr), type));
- return ir_make_addr(v);
+ return ir_addr(v);
}
default:
GB_PANIC("Unknown cast expression");
@@ -3960,7 +4055,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
// Type *type = type_of_expr(proc->module->info, expr);
// irValue *v = ir_add_local_generated(proc, type);
// ir_emit_store(proc, v, ir_emit_conv(proc, ir_build_expr(proc, be->left), type));
- // return ir_make_addr(v);
+ // return ir_addr(v);
// }
// case Token_transmute: {
// ir_emit_comment(proc, str_lit("Cast - transmute"));
@@ -3968,7 +4063,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
// Type *type = type_of_expr(proc->module->info, expr);
// irValue *v = ir_add_local_generated(proc, type);
// ir_emit_store(proc, v, ir_emit_transmute(proc, ir_build_expr(proc, be->left), type));
- // return ir_make_addr(v);
+ // return ir_addr(v);
// }
default:
GB_PANIC("Invalid binary expression for ir_build_addr: %.*s\n", LIT(be->op.string));
@@ -3991,7 +4086,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
key = ir_emit_conv(proc, key, t->Map.key);
Type *result_type = type_of_expr(proc->module->info, expr);
- return ir_make_addr_map(map_val, key, t, result_type);
+ return ir_addr_map(map_val, key, t, result_type);
}
irValue *using_addr = NULL;
@@ -4001,7 +4096,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
if (using_field != NULL) {
Selection sel = lookup_field(a, t, using_field->token.string, false);
irValue *e = ir_build_addr(proc, ie->expr).addr;
- using_addr = ir_emit_deep_field_gep(proc, t, e, sel);
+ using_addr = ir_emit_deep_field_gep(proc, e, sel);
t = using_field->type;
}
@@ -4021,9 +4116,9 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
irValue *elem = ir_emit_array_ep(proc, vector, index);
- irValue *len = ir_make_const_int(a, t->Vector.count);
+ irValue *len = ir_const_int(a, t->Vector.count);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
- return ir_make_addr(elem);
+ return ir_addr(elem);
} break;
case Type_Array: {
@@ -4038,9 +4133,9 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
irValue *elem = ir_emit_array_ep(proc, array, index);
- irValue *len = ir_make_const_int(a, t->Vector.count);
+ irValue *len = ir_const_int(a, t->Vector.count);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
- return ir_make_addr(elem);
+ return ir_addr(elem);
} break;
case Type_Slice: {
@@ -4058,7 +4153,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
- return ir_make_addr(v);
+ return ir_addr(v);
} break;
case Type_DynamicArray: {
@@ -4076,7 +4171,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
irValue *v = ir_emit_ptr_offset(proc, elem, index);
- return ir_make_addr(v);
+ return ir_addr(v);
} break;
@@ -4101,7 +4196,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
index = ir_emit_conv(proc, ir_build_expr(proc, ie->index), t_int);
ir_emit_bounds_check(proc, ast_node_token(ie->index), index, len);
- return ir_make_addr(ir_emit_ptr_offset(proc, elem, index));
+ return ir_addr(ir_emit_ptr_offset(proc, elem, index));
} break;
}
case_end;
@@ -4142,7 +4237,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
irValue *slice = ir_add_local_generated(proc, slice_type);
ir_fill_slice(proc, slice, elem, len, cap);
- return ir_make_addr(slice);
+ return ir_addr(slice);
}
case Type_DynamicArray: {
@@ -4158,7 +4253,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
irValue *slice = ir_add_local_generated(proc, dynamic_array);
ir_fill_slice(proc, slice, elem, len, cap);
- return ir_make_addr(slice);
+ return ir_addr(slice);
}
@@ -4175,7 +4270,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *cap = ir_emit_arith(proc, Token_Sub, max, low, t_int);
irValue *slice = ir_add_local_generated(proc, slice_type);
ir_fill_slice(proc, slice, elem, len, cap);
- return ir_make_addr(slice);
+ return ir_addr(slice);
}
case Type_Basic: {
@@ -4192,7 +4287,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
ir_emit_store(proc, ir_emit_struct_ep(proc, str, 0), elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, str, 1), len);
- return ir_make_addr(str);
+ return ir_addr(str);
} break;
}
@@ -4203,7 +4298,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
// TODO(bill): Is a ptr copy needed?
irValue *addr = ir_build_expr(proc, de->expr);
addr = ir_emit_ptr_offset(proc, addr, v_zero);
- return ir_make_addr(addr);
+ return ir_addr(addr);
case_end;
case_ast_node(ce, CallExpr, expr);
@@ -4211,7 +4306,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
irValue *e = ir_build_expr(proc, expr);
irValue *v = ir_add_local_generated(proc, ir_type(e));
ir_emit_store(proc, v, e);
- return ir_make_addr(v);
+ return ir_addr(v);
case_end;
case_ast_node(cl, CompoundLit, expr);
@@ -4238,7 +4333,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
ir_emit_store(proc, ir_emit_array_epi(proc, v, i), elem_val);
}
} else if (cl->elems.count > 0) {
- ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
for_array(i, cl->elems) {
AstNode *elem = cl->elems.e[i];
if (ir_is_elem_const(proc->module, elem, et)) {
@@ -4261,7 +4356,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
GB_ASSERT(is_type_struct(bt) || is_type_union(bt));
TypeRecord *st = &bt->Record;
if (cl->elems.count > 0) {
- ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
for_array(field_index, cl->elems) {
AstNode *elem = cl->elems.e[field_index];
@@ -4303,14 +4398,14 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
Type *elem = bt->DynamicArray.elem;
gbAllocator a = proc->module->allocator;
- irValue *size = ir_make_const_int(a, type_size_of(a, elem));
- irValue *align = ir_make_const_int(a, type_align_of(a, elem));
+ irValue *size = ir_const_int(a, type_size_of(a, elem));
+ irValue *align = ir_const_int(a, type_align_of(a, elem));
{
irValue **args = gb_alloc_array(a, irValue *, 4);
args[0] = ir_emit_conv(proc, v, t_rawptr);
args[1] = size;
args[2] = align;
- args[3] = ir_make_const_int(a, 2*cl->elems.count);
+ args[3] = ir_const_int(a, 2*cl->elems.count);
ir_emit_global_call(proc, "__dynamic_array_reserve", args, 4);
}
@@ -4330,7 +4425,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
args[1] = size;
args[2] = align;
args[3] = ir_emit_conv(proc, items, t_rawptr);
- args[4] = ir_make_const_int(a, item_count);
+ args[4] = ir_const_int(a, item_count);
ir_emit_global_call(proc, "__dynamic_array_append", args, 5);
}
} break;
@@ -4343,7 +4438,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
{
irValue **args = gb_alloc_array(a, irValue *, 2);
args[0] = ir_gen_map_header(proc, v, type);
- args[1] = ir_make_const_int(a, 2*cl->elems.count);
+ args[1] = ir_const_int(a, 2*cl->elems.count);
ir_emit_global_call(proc, "__dynamic_map_reserve", args, 2);
}
for_array(field_index, cl->elems) {
@@ -4358,7 +4453,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
case Type_Array: {
if (cl->elems.count > 0) {
- ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
for_array(i, cl->elems) {
AstNode *elem = cl->elems.e[i];
if (ir_is_elem_const(proc->module, elem, et)) {
@@ -4378,7 +4473,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
Type *elem_type = bt->Slice.elem;
Type *elem_ptr_type = make_type_pointer(proc->module->allocator, elem_type);
Type *elem_ptr_ptr_type = make_type_pointer(proc->module->allocator, elem_ptr_type);
- irValue *slice = ir_add_module_constant(proc->module, type, make_exact_value_compound(expr));
+ irValue *slice = ir_add_module_constant(proc->module, type, exact_value_compound(expr));
GB_ASSERT(slice->kind == irValue_ConstantSlice);
irValue *data = ir_emit_array_ep(proc, slice->ConstantSlice.backing_array, v_zero32);
@@ -4393,11 +4488,11 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
Type *t = ir_type(field_expr);
GB_ASSERT(t->kind != Type_Tuple);
irValue *ev = ir_emit_conv(proc, field_expr, elem_type);
- irValue *offset = ir_emit_ptr_offset(proc, data, ir_make_const_int(proc->module->allocator, i));
+ irValue *offset = ir_emit_ptr_offset(proc, data, ir_const_int(proc->module->allocator, i));
ir_emit_store(proc, offset, ev);
}
- irValue *count = ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count);
+ irValue *count = ir_const_int(proc->module->allocator, slice->ConstantSlice.count);
ir_fill_slice(proc, v, data, count, count);
}
} break;
@@ -4405,7 +4500,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
case Type_Basic: {
GB_ASSERT(is_type_any(bt));
if (cl->elems.count > 0) {
- ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, exact_value_compound(expr)));
String field_names[2] = {
str_lit("type_info"),
str_lit("data"),
@@ -4445,7 +4540,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
}
}
- return ir_make_addr(v);
+ return ir_addr(v);
case_end;
}
@@ -4457,7 +4552,7 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
LIT(token_pos.file), token_pos.line, token_pos.column);
- return ir_make_addr(NULL);
+ return ir_addr(NULL);
}
void ir_build_assign_op(irProcedure *proc, irAddr lhs, irValue *value, TokenKind op) {
@@ -4577,10 +4672,10 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
Type *expr_type = base_type(type_deref(ir_type(expr)));
switch (expr_type->kind) {
case Type_Array:
- count = ir_make_const_int(proc->module->allocator, expr_type->Array.count);
+ count = ir_const_int(proc->module->allocator, expr_type->Array.count);
break;
case Type_Vector:
- count = ir_make_const_int(proc->module->allocator, expr_type->Vector.count);
+ count = ir_const_int(proc->module->allocator, expr_type->Vector.count);
break;
}
@@ -4596,7 +4691,7 @@ void ir_build_range_indexed(irProcedure *proc, irValue *expr, Type *val_type, ir
}
irValue *index = ir_add_local_generated(proc, t_int);
- ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, -1));
+ ir_emit_store(proc, index, ir_const_int(proc->module->allocator, -1));
loop = ir_new_block(proc, NULL, "for.index.loop");
ir_emit_jump(proc, loop);
@@ -4752,7 +4847,7 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type
ir_emit_store(proc, value, lower);
irValue *index = ir_add_local_generated(proc, t_int);
- ir_emit_store(proc, index, ir_make_const_int(proc->module->allocator, 0));
+ ir_emit_store(proc, index, ir_const_int(proc->module->allocator, 0));
loop = ir_new_block(proc, NULL, "for.interval.loop");
ir_emit_jump(proc, loop);
@@ -4786,6 +4881,26 @@ void ir_build_range_interval(irProcedure *proc, AstNodeIntervalExpr *node, Type
if (done_) *done_ = done;
}
+void ir_store_type_case_implicit(irProcedure *proc, AstNode *clause, irValue *value) {
+ Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause));
+ GB_ASSERT(found != NULL);
+ Entity *e = *found; GB_ASSERT(e != NULL);
+ irValue *x = ir_add_local(proc, e, NULL);
+ ir_emit_store(proc, x, value);
+}
+
+void ir_type_case_body(irProcedure *proc, AstNode *label, AstNode *clause, irBlock *body, irBlock *done) {
+ ast_node(cc, CaseClause, clause);
+
+ ir_push_target_list(proc, label, done, NULL, NULL);
+ ir_open_scope(proc);
+ ir_build_stmt_list(proc, cc->stmts);
+ ir_close_scope(proc, irDeferExit_Default, body);
+ ir_pop_target_list(proc);
+
+ ir_emit_jump(proc, done);
+}
+
void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
switch (node->kind) {
@@ -4793,9 +4908,11 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
case_end;
case_ast_node(us, UsingStmt, node);
- AstNode *decl = unparen_expr(us->node);
- if (decl->kind == AstNode_ValueDecl) {
- ir_build_stmt(proc, decl);
+ for_array(i, us->list) {
+ AstNode *decl = unparen_expr(us->list.e[i]);
+ if (decl->kind == AstNode_ValueDecl) {
+ ir_build_stmt(proc, decl);
+ }
}
case_end;
@@ -4825,14 +4942,14 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
}
}
} else { // Tuple(s)
- Array(irAddr) lvals;
- irValueArray inits;
+ Array(irAddr) lvals = {0};
+ irValueArray inits = {0};
array_init_reserve(&lvals, m->tmp_allocator, vd->names.count);
array_init_reserve(&inits, m->tmp_allocator, vd->names.count);
for_array(i, vd->names) {
AstNode *name = vd->names.e[i];
- irAddr lval = ir_make_addr(NULL);
+ irAddr lval = ir_addr(NULL);
if (!ir_is_blank_ident(name)) {
ir_add_local_for_identifier(proc, name, false);
lval = ir_build_addr(proc, name);
@@ -4857,9 +4974,6 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
for_array(i, inits) {
- if (lvals.e[i].addr == NULL) {
- continue;
- }
ir_addr_store(proc, lvals.e[i], inits.e[i]);
}
}
@@ -4882,7 +4996,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
name_len = gb_snprintf(cast(char *)name_text, name_len, "%.*s.%.*s-%d", LIT(proc->name), LIT(ts_name), guid);
String name = make_string(name_text, name_len-1);
- irValue *value = ir_make_value_type_name(proc->module->allocator,
+ irValue *value = ir_value_type_name(proc->module->allocator,
name, e->type);
map_string_set(&proc->module->type_names, hash_pointer(e->type), name);
ir_gen_global_type_name(proc->module, e, name);
@@ -4915,8 +5029,8 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
String name = make_string(name_text, name_len-1);
- irValue *value = ir_make_value_procedure(proc->module->allocator,
- proc->module, e, e->type, pd->type, pd->body, name);
+ irValue *value = ir_value_procedure(proc->module->allocator,
+ proc->module, e, e->type, pd->type, pd->body, name);
value->Proc.tags = pd->tags;
value->Proc.parent = proc;
@@ -4934,7 +5048,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
name = pd->foreign_name;
}
- irValue *value = ir_make_value_procedure(proc->module->allocator,
+ irValue *value = ir_value_procedure(proc->module->allocator,
proc->module, e, e->type, pd->type, pd->body, name);
value->Proc.tags = pd->tags;
@@ -5144,6 +5258,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
case_ast_node(fs, ForStmt, node);
ir_emit_comment(proc, str_lit("ForStmt"));
+
if (fs->init != NULL) {
irBlock *init = ir_new_block(proc, node, "for.init");
ir_emit_jump(proc, init);
@@ -5156,10 +5271,12 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
if (fs->cond != NULL) {
loop = ir_new_block(proc, node, "for.loop");
}
- irBlock *cont = loop;
+ irBlock *post = loop;
if (fs->post != NULL) {
- cont = ir_new_block(proc, node, "for.post");
+ post = ir_new_block(proc, node, "for.post");
}
+
+
ir_emit_jump(proc, loop);
ir_start_block(proc, loop);
@@ -5168,7 +5285,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_start_block(proc, body);
}
- ir_push_target_list(proc, done, cont, NULL);
+ ir_push_target_list(proc, fs->label, done, post, NULL);
ir_open_scope(proc);
ir_build_stmt(proc, fs->body);
@@ -5176,10 +5293,10 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_pop_target_list(proc);
- ir_emit_jump(proc, cont);
+ ir_emit_jump(proc, post);
if (fs->post != NULL) {
- ir_start_block(proc, cont);
+ ir_start_block(proc, post);
ir_build_stmt(proc, fs->post);
ir_emit_jump(proc, loop);
}
@@ -5235,7 +5352,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
array = ir_emit_load(proc, array);
}
count_ptr = ir_add_local_generated(proc, t_int);
- ir_emit_store(proc, count_ptr, ir_make_const_int(proc->module->allocator, et->Array.count));
+ ir_emit_store(proc, count_ptr, ir_const_int(proc->module->allocator, et->Array.count));
ir_build_range_indexed(proc, array, val_type, count_ptr, &val, &index, &loop, &done);
} break;
case Type_Vector: {
@@ -5245,7 +5362,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
vector = ir_emit_load(proc, vector);
}
count_ptr = ir_add_local_generated(proc, t_int);
- ir_emit_store(proc, count_ptr, ir_make_const_int(proc->module->allocator, et->Vector.count));
+ ir_emit_store(proc, count_ptr, ir_const_int(proc->module->allocator, et->Vector.count));
ir_build_range_indexed(proc, vector, val_type, count_ptr, &val, &index, &loop, &done);
} break;
case Type_DynamicArray: {
@@ -5302,7 +5419,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_addr_store(proc, idx_addr, index);
}
- ir_push_target_list(proc, done, loop, NULL);
+ ir_push_target_list(proc, rs->label, done, loop, NULL);
ir_open_scope(proc);
ir_build_stmt(proc, rs->body);
@@ -5376,7 +5493,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
}
ir_start_block(proc, body);
- ir_push_target_list(proc, done, NULL, fall);
+ ir_push_target_list(proc, ms->label, done, NULL, fall);
ir_open_scope(proc);
ir_build_stmt_list(proc, cc->stmts);
ir_close_scope(proc, irDeferExit_Default, body);
@@ -5391,7 +5508,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ir_emit_jump(proc, default_block);
ir_start_block(proc, default_block);
- ir_push_target_list(proc, done, NULL, default_fall);
+ ir_push_target_list(proc, ms->label, done, NULL, default_fall);
ir_open_scope(proc);
ir_build_stmt_list(proc, default_stmts);
ir_close_scope(proc, irDeferExit_Default, default_block);
@@ -5410,172 +5527,149 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
ast_node(as, AssignStmt, ms->tag);
GB_ASSERT(as->lhs.count == 1);
GB_ASSERT(as->rhs.count == 1);
- AstNode *lhs = as->lhs.e[0];
- AstNode *rhs = as->rhs.e[0];
- irValue *parent = ir_build_expr(proc, rhs);
- bool is_union_ptr = false;
- bool is_any = false;
- GB_ASSERT(check_valid_type_match_type(ir_type(parent), &is_union_ptr, &is_any));
+ irValue *parent = ir_build_expr(proc, as->rhs.e[0]);
+ Type *parent_type = ir_type(parent);
+ bool is_parent_ptr = is_type_pointer(ir_type(parent));
+
+ MatchTypeKind match_type_kind = check_valid_type_match_type(ir_type(parent));
+ GB_ASSERT(match_type_kind != MatchType_Invalid);
+
+ irValue *parent_value = parent;
+
+ irValue *parent_ptr = parent;
+ if (!is_parent_ptr) {
+ parent_ptr = ir_address_from_load_or_generate_local(proc, parent_ptr);
+ }
irValue *tag_index = NULL;
irValue *union_data = NULL;
- if (is_union_ptr) {
+ if (match_type_kind == MatchType_Union) {
ir_emit_comment(proc, str_lit("get union's tag"));
- tag_index = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, parent));
- union_data = ir_emit_conv(proc, parent, t_rawptr);
+ tag_index = ir_emit_load(proc, ir_emit_union_tag_ptr(proc, parent_ptr));
+ union_data = ir_emit_conv(proc, parent_ptr, t_rawptr);
}
- irBlock *start_block = ir_new_block(proc, node, "type-match.case.first");
+ irBlock *start_block = ir_new_block(proc, node, "typematch.case.first");
ir_emit_jump(proc, start_block);
ir_start_block(proc, start_block);
- irBlock *done = ir_new_block(proc, node, "type-match.done"); // NOTE(bill): Append later
+ // NOTE(bill): Append this later
+ irBlock *done = ir_new_block(proc, node, "typematch.done");
+ AstNode *default_ = NULL;
ast_node(body, BlockStmt, ms->body);
- String tag_var_name = lhs->Ident.string;
-
-
- AstNodeArray default_stmts = {0};
- irBlock *default_block = NULL;
+ gb_local_persist i32 weird_count = 0;
-
- isize case_count = body->stmts.count;
for_array(i, body->stmts) {
AstNode *clause = body->stmts.e[i];
ast_node(cc, CaseClause, clause);
-
- Entity *tag_var_entity = NULL;
- Type *tag_var_type = NULL;
- if (str_eq(tag_var_name, str_lit("_"))) {
- Type *t = type_of_expr(proc->module->info, cc->list.e[0]);
- if (is_union_ptr) {
- t = make_type_pointer(proc->module->allocator, t);
- }
- tag_var_type = t;
- } else {
- Scope *scope = *map_scope_get(&proc->module->info->scopes, hash_pointer(clause));
- tag_var_entity = current_scope_lookup_entity(scope, tag_var_name);
- GB_ASSERT_MSG(tag_var_entity != NULL, "%.*s", LIT(tag_var_name));
- tag_var_type = tag_var_entity->type;
- }
- GB_ASSERT(tag_var_type != NULL);
-
- irBlock *next_cond = NULL;
- irValue *cond = NULL;
-
if (cc->list.count == 0) {
- // default case
- default_stmts = cc->stmts;
- default_block = ir_new_block(proc, clause, "type-match.dflt.body");
-
-
- irValue *tag_var = NULL;
- if (tag_var_entity != NULL) {
- tag_var = ir_add_local(proc, tag_var_entity, NULL);
- } else {
- tag_var = ir_add_local_generated(proc, tag_var_type);
- }
- ir_emit_store(proc, tag_var, parent);
+ default_ = clause;
continue;
}
- GB_ASSERT(cc->list.count == 1);
-
- irBlock *body = ir_new_block(proc, clause, "type-match.case.body");
-
- if (is_union_ptr) {
- Type *bt = type_deref(tag_var_type);
- irValue *index = NULL;
- Type *ut = base_type(type_deref(ir_type(parent)));
- GB_ASSERT(ut->Record.kind == TypeRecord_Union);
- for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
- Entity *f = ut->Record.variants[variant_index];
- if (are_types_identical(f->type, bt)) {
- index = ir_make_const_int(allocator, variant_index);
- break;
+ irBlock *body = ir_new_block(proc, clause, "typematch.body");
+ irBlock *next = NULL;
+ Type *case_type = NULL;
+ for_array(type_index, cc->list) {
+ next = ir_new_block(proc, NULL, "typematch.next");
+ case_type = type_of_expr(proc->module->info, cc->list.e[type_index]);
+ irValue *cond = NULL;
+ if (match_type_kind == MatchType_Union) {
+ Type *bt = type_deref(case_type);
+ irValue *index = NULL;
+ Type *ut = base_type(type_deref(parent_type));
+ GB_ASSERT(ut->Record.kind == TypeRecord_Union);
+ for (isize variant_index = 1; variant_index < ut->Record.variant_count; variant_index++) {
+ Entity *f = ut->Record.variants[variant_index];
+ if (are_types_identical(f->type, bt)) {
+ index = ir_const_int(allocator, variant_index);
+ break;
+ }
}
+ GB_ASSERT(index != NULL);
+ cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
+ } else if (match_type_kind == MatchType_Any) {
+ irValue *any_ti = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 0));
+ irValue *case_ti = ir_type_info(proc, case_type);
+ cond = ir_emit_comp(proc, Token_CmpEq, any_ti, case_ti);
}
- GB_ASSERT(index != NULL);
-
- irValue *tag_var = NULL;
- if (tag_var_entity != NULL) {
- tag_var = ir_add_local(proc, tag_var_entity, NULL);
- } else {
- tag_var = ir_add_local_generated(proc, tag_var_type);
- }
-
-
- irValue *data_ptr = ir_emit_conv(proc, union_data, tag_var_type);
- ir_emit_store(proc, tag_var, data_ptr);
+ GB_ASSERT(cond != NULL);
- cond = ir_emit_comp(proc, Token_CmpEq, tag_index, index);
- } else if (is_any) {
- Type *type = tag_var_type;
- irValue *any_data = ir_emit_struct_ev(proc, parent, 1);
- irValue *data = ir_emit_conv(proc, any_data, make_type_pointer(proc->module->allocator, type));
- if (tag_var_entity != NULL) {
- ir_module_add_value(proc->module, tag_var_entity, data);
- }
+ ir_emit_if(proc, cond, body, next);
+ ir_start_block(proc, next);
+ }
- irValue *any_ti = ir_emit_struct_ev(proc, parent, 0);
- irValue *case_ti = ir_type_info(proc, type);
- cond = ir_emit_comp(proc, Token_CmpEq, any_ti, case_ti);
- } else {
- GB_PANIC("Invalid type for type match statement");
+ Entity *case_entity = NULL;
+ {
+ Entity **found = map_entity_get(&proc->module->info->implicits, hash_pointer(clause));
+ GB_ASSERT(found != NULL);
+ case_entity = *found;
}
- next_cond = ir_new_block(proc, clause, "type-match.case.next");
- ir_emit_if(proc, cond, body, next_cond);
- ir_start_block(proc, next_cond);
+
+ irValue *value = parent_value;
ir_start_block(proc, body);
- ir_push_target_list(proc, done, NULL, NULL);
- ir_open_scope(proc);
- ir_build_stmt_list(proc, cc->stmts);
- ir_close_scope(proc, irDeferExit_Default, body);
- ir_pop_target_list(proc);
+ if (cc->list.count == 1) {
+ Type *ct = make_type_pointer(proc->module->allocator, case_entity->type);
+ irValue *data = NULL;
+ if (match_type_kind == MatchType_Union) {
+ data = union_data;
+ } else if (match_type_kind == MatchType_Any) {
+ irValue *any_data = ir_emit_load(proc, ir_emit_struct_ep(proc, parent_ptr, 1));
+ data = any_data;
+ }
+ value = ir_emit_load(proc, ir_emit_conv(proc, data, ct));
+ }
- ir_emit_jump(proc, done);
- proc->curr_block = next_cond;
- // ir_start_block(proc, next_cond);
+ ir_store_type_case_implicit(proc, clause, value);
+ ir_type_case_body(proc, ms->label, clause, body, done);
+ ir_start_block(proc, next);
}
- if (default_block != NULL) {
- ir_emit_jump(proc, default_block);
- ir_start_block(proc, default_block);
-
- ir_push_target_list(proc, done, NULL, NULL);
- ir_open_scope(proc);
- ir_build_stmt_list(proc, default_stmts);
- ir_close_scope(proc, irDeferExit_Default, default_block);
- ir_pop_target_list(proc);
+ if (default_ != NULL) {
+ ir_store_type_case_implicit(proc, default_, parent_value);
+ ir_type_case_body(proc, ms->label, default_, proc->curr_block, done);
+ } else {
+ ir_emit_jump(proc, done);
}
-
- ir_emit_jump(proc, done);
ir_start_block(proc, done);
case_end;
case_ast_node(bs, BranchStmt, node);
irBlock *block = NULL;
- switch (bs->token.kind) {
- case Token_break:
- for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
- block = t->break_;
- }
- break;
- case Token_continue:
- for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
- block = t->continue_;
+
+ if (bs->label != NULL) {
+ irBranchBlocks bb = ir_lookup_branch_blocks(proc, bs->label);
+ switch (bs->token.kind) {
+ case Token_break: block = bb.break_; break;
+ case Token_continue: block = bb.continue_; break;
+ case Token_fallthrough:
+ GB_PANIC("fallthrough cannot have a label");
+ break;
}
- break;
- case Token_fallthrough:
- for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
- block = t->fallthrough_;
+ } else {
+ switch (bs->token.kind) {
+ case Token_break:
+ for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
+ block = t->break_;
+ }
+ break;
+ case Token_continue:
+ for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
+ block = t->continue_;
+ }
+ break;
+ case Token_fallthrough:
+ for (irTargetList *t = proc->target_list; t != NULL && block == NULL; t = t->prev) {
+ block = t->fallthrough_;
+ }
+ break;
}
- break;
}
if (block != NULL) {
ir_emit_defer_stmts(proc, irDeferExit_Branch, block);
@@ -5599,7 +5693,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
irValue *prev_context = ir_add_local_generated(proc, t_context);
ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
- ir_add_defer_instr(proc, proc->scope_index, ir_make_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context)));
+ ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context)));
irValue *gep = ir_emit_struct_ep(proc, context_ptr, 1);
ir_emit_store(proc, gep, ir_build_expr(proc, pa->expr));
@@ -5610,7 +5704,7 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
case_end;
- case_ast_node(pa, PushContext, node);
+ case_ast_node(pc, PushContext, node);
ir_emit_comment(proc, str_lit("PushContext"));
ir_open_scope(proc);
@@ -5618,11 +5712,11 @@ void ir_build_stmt_internal(irProcedure *proc, AstNode *node) {
irValue *prev_context = ir_add_local_generated(proc, t_context);
ir_emit_store(proc, prev_context, ir_emit_load(proc, context_ptr));
- ir_add_defer_instr(proc, proc->scope_index, ir_make_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context)));
+ ir_add_defer_instr(proc, proc->scope_index, ir_instr_store(proc, context_ptr, ir_emit_load(proc, prev_context)));
- ir_emit_store(proc, context_ptr, ir_build_expr(proc, pa->expr));
+ ir_emit_store(proc, context_ptr, ir_build_expr(proc, pc->expr));
- ir_build_stmt(proc, pa->body);
+ ir_build_stmt(proc, pc->body);
ir_close_scope(proc, irDeferExit_Default, NULL);
case_end;
@@ -5653,9 +5747,11 @@ void ir_number_proc_registers(irProcedure *proc) {
GB_ASSERT(value->kind == irValue_Instr);
irInstr *instr = &value->Instr;
if (ir_instr_type(instr) == NULL) { // NOTE(bill): Ignore non-returning instructions
+ value->index = -1;
continue;
}
value->index = reg_index;
+ value->index_set = true;
reg_index++;
}
}
@@ -5664,9 +5760,20 @@ void ir_number_proc_registers(irProcedure *proc) {
void ir_begin_procedure_body(irProcedure *proc) {
array_add(&proc->module->procs, proc);
- array_init(&proc->blocks, heap_allocator());
- array_init(&proc->defer_stmts, heap_allocator());
- array_init(&proc->children, heap_allocator());
+ array_init(&proc->blocks, heap_allocator());
+ array_init(&proc->defer_stmts, heap_allocator());
+ array_init(&proc->children, heap_allocator());
+ array_init(&proc->branch_blocks, heap_allocator());
+
+ DeclInfo **found = map_decl_info_get(&proc->module->info->entities, hash_pointer(proc->entity));
+ if (found != NULL) {
+ DeclInfo *decl = *found;
+ for_array(i, decl->labels) {
+ BlockLabel bl = decl->labels.e[i];
+ irBranchBlocks bb = {bl.label, NULL, NULL};
+ array_add(&proc->branch_blocks, bb);
+ }
+ }
proc->decl_block = ir_new_block(proc, proc->type_expr, "decls");
ir_start_block(proc, proc->decl_block);
@@ -5835,7 +5942,7 @@ void ir_init_module(irModule *m, Checker *c) {
String name = str_lit(IR_TYPE_INFO_DATA_NAME);
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name), make_type_array(m->allocator, t_type_info, max_type_info_count), false);
- irValue *g = ir_make_value_global(m->allocator, e, NULL);
+ irValue *g = ir_value_global(m->allocator, e, NULL);
g->Global.is_private = true;
ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g);
@@ -5874,7 +5981,7 @@ void ir_init_module(irModule *m, Checker *c) {
String name = str_lit(IR_TYPE_INFO_TYPES_NAME);
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name),
make_type_array(m->allocator, t_type_info_ptr, count), false);
- irValue *g = ir_make_value_global(m->allocator, e, NULL);
+ irValue *g = ir_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_types = g;
@@ -5883,7 +5990,7 @@ void ir_init_module(irModule *m, Checker *c) {
String name = str_lit(IR_TYPE_INFO_NAMES_NAME);
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name),
make_type_array(m->allocator, t_string, count), false);
- irValue *g = ir_make_value_global(m->allocator, e, NULL);
+ irValue *g = ir_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_names = g;
@@ -5892,7 +5999,7 @@ void ir_init_module(irModule *m, Checker *c) {
String name = str_lit(IR_TYPE_INFO_OFFSETS_NAME);
Entity *e = make_entity_variable(m->allocator, NULL, make_token_ident(name),
make_type_array(m->allocator, t_int, count), false);
- irValue *g = ir_make_value_global(m->allocator, e, NULL);
+ irValue *g = ir_value_global(m->allocator, e, NULL);
ir_module_add_value(m, e, g);
map_ir_value_set(&m->members, hash_string(name), g);
ir_global_type_info_member_offsets = g;
@@ -5957,50 +6064,6 @@ void ir_gen_destroy(irGen *s) {
gb_file_close(&s->output_file);
}
-String ir_mangle_name(irGen *s, String path, Entity *e) {
- // NOTE(bill): prefix names not in the init scope
- // TODO(bill): make robust and not just rely on the file's name
- String name = e->token.string;
- irModule *m = &s->module;
- CheckerInfo *info = m->info;
- gbAllocator a = m->allocator;
- AstFile *file = *map_ast_file_get(&info->files, hash_string(path));
-
- char *str = gb_alloc_array(a, char, path.len+1);
- gb_memmove(str, path.text, path.len);
- str[path.len] = 0;
- for (isize i = 0; i < path.len; i++) {
- if (str[i] == '\\') {
- str[i] = '/';
- }
- }
-
- char const *base = gb_path_base_name(str);
- char const *ext = gb_path_extension(base);
- isize base_len = ext-1-base;
-
- isize max_len = base_len + 1 + 10 + 1 + name.len;
- bool is_overloaded = check_is_entity_overloaded(e);
- if (is_overloaded) {
- max_len += 21;
- }
-
- u8 *new_name = gb_alloc_array(a, u8, max_len);
- isize new_name_len = gb_snprintf(
- cast(char *)new_name, max_len,
- "%.*s-%u.%.*s",
- cast(int)base_len, base,
- file->id,
- LIT(name));
- if (is_overloaded) {
- char *str = cast(char *)new_name + new_name_len-1;
- isize len = max_len-new_name_len;
- isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e);
- new_name_len += extra-1;
- }
-
- return make_string(new_name, new_name_len-1);
-}
//
@@ -6060,14 +6123,14 @@ void ir_gen_tree(irGen *s) {
gbAllocator a = m->allocator;
if (v_zero == NULL) {
- v_zero = ir_make_const_int (m->allocator, 0);
- v_one = ir_make_const_int (m->allocator, 1);
- v_zero32 = ir_make_const_i32 (m->allocator, 0);
- v_one32 = ir_make_const_i32 (m->allocator, 1);
- v_two32 = ir_make_const_i32 (m->allocator, 2);
- v_false = ir_make_const_bool(m->allocator, false);
- v_true = ir_make_const_bool(m->allocator, true);
- v_raw_nil = ir_make_value_constant(m->allocator, t_rawptr, make_exact_value_pointer(0));
+ v_zero = ir_const_int (m->allocator, 0);
+ v_one = ir_const_int (m->allocator, 1);
+ v_zero32 = ir_const_i32 (m->allocator, 0);
+ v_one32 = ir_const_i32 (m->allocator, 1);
+ v_two32 = ir_const_i32 (m->allocator, 2);
+ v_false = ir_const_bool(m->allocator, false);
+ v_true = ir_const_bool(m->allocator, true);
+ v_raw_nil = ir_value_constant(m->allocator, t_rawptr, exact_value_pointer(0));
}
isize global_variable_max_count = 0;
@@ -6142,7 +6205,7 @@ void ir_gen_tree(irGen *s) {
break;
case Entity_Variable: {
- irValue *g = ir_make_value_global(a, e, NULL);
+ irValue *g = ir_value_global(a, e, NULL);
g->Global.is_thread_local = e->Variable.is_thread_local;
irGlobalVariable var = {0};
@@ -6185,7 +6248,7 @@ void ir_gen_tree(irGen *s) {
AstNode *type_expr = decl->proc_lit->ProcLit.type;
- irValue *p = ir_make_value_procedure(a, m, e, e->type, type_expr, body, name);
+ irValue *p = ir_value_procedure(a, m, e, e->type, type_expr, body, name);
p->Proc.tags = pd->tags;
ir_module_add_value(m, e, p);
@@ -6260,7 +6323,7 @@ void ir_gen_tree(irGen *s) {
AstNode *body = gb_alloc_item(a, AstNode);
Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
- irValue *p = ir_make_value_procedure(a, m, e, proc_type, NULL, body, name);
+ irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name);
map_ir_value_set(&m->values, hash_pointer(e), p);
map_ir_value_set(&m->members, hash_string(name), p);
@@ -6319,7 +6382,7 @@ void ir_gen_tree(irGen *s) {
AstNode *body = gb_alloc_item(a, AstNode);
Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
- irValue *p = ir_make_value_procedure(a, m, e, proc_type, NULL, body, name);
+ irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name);
m->entry_point_entity = e;
@@ -6344,7 +6407,7 @@ void ir_gen_tree(irGen *s) {
NULL, 0, false, ProcCC_Odin);
AstNode *body = gb_alloc_item(a, AstNode);
Entity *e = make_entity_procedure(a, NULL, make_token_ident(name), proc_type, 0);
- irValue *p = ir_make_value_procedure(a, m, e, proc_type, NULL, body, name);
+ irValue *p = ir_value_procedure(a, m, e, proc_type, NULL, body, name);
map_ir_value_set(&m->values, hash_pointer(e), p);
map_ir_value_set(&m->members, hash_string(name), p);
@@ -6389,7 +6452,7 @@ void ir_gen_tree(irGen *s) {
irValue *global_type_table = ir_find_global_variable(proc, str_lit("__type_table"));
Type *type = base_type(type_deref(ir_type(ir_global_type_info_data)));
GB_ASSERT(is_type_array(type));
- irValue *len = ir_make_const_int(proc->module->allocator, type->Array.count);
+ irValue *len = ir_const_int(proc->module->allocator, type->Array.count);
ir_fill_slice(proc, global_type_table,
ir_emit_array_epi(proc, ir_global_type_info_data, 0),
len, len);
@@ -6420,7 +6483,7 @@ void ir_gen_tree(irGen *s) {
tag = ir_emit_conv(proc, ti_ptr, t_type_info_named_ptr);
// TODO(bill): Which is better? The mangled name or actual name?
- irValue *name = ir_make_const_string(a, t->Named.type_name->token.string);
+ irValue *name = ir_const_string(a, t->Named.type_name->token.string);
irValue *gtip = ir_get_type_info_ptr(proc, t->Named.base);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), name);
@@ -6447,8 +6510,8 @@ void ir_gen_tree(irGen *s) {
case Basic_uint: {
tag = ir_emit_conv(proc, ti_ptr, t_type_info_integer_ptr);
bool is_unsigned = (t->Basic.flags & BasicFlag_Unsigned) != 0;
- irValue *bits = ir_make_const_int(a, type_size_of(a, t));
- irValue *is_signed = ir_make_const_bool(a, !is_unsigned);
+ irValue *bits = ir_const_int(a, type_size_of(a, t));
+ irValue *is_signed = ir_const_bool(a, !is_unsigned);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), bits);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), is_signed);
} break;
@@ -6459,7 +6522,7 @@ void ir_gen_tree(irGen *s) {
// case Basic_f128:
{
tag = ir_emit_conv(proc, ti_ptr, t_type_info_float_ptr);
- irValue *bits = ir_make_const_int(a, type_size_of(a, t));
+ irValue *bits = ir_const_int(a, type_size_of(a, t));
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), bits);
} break;
@@ -6491,10 +6554,10 @@ void ir_gen_tree(irGen *s) {
isize ez = type_size_of(a, t->Array.elem);
irValue *elem_size = ir_emit_struct_ep(proc, tag, 1);
- ir_emit_store(proc, elem_size, ir_make_const_int(a, ez));
+ ir_emit_store(proc, elem_size, ir_const_int(a, ez));
irValue *count = ir_emit_struct_ep(proc, tag, 2);
- ir_emit_store(proc, count, ir_make_const_int(a, t->Array.count));
+ ir_emit_store(proc, count, ir_const_int(a, t->Array.count));
} break;
case Type_DynamicArray: {
@@ -6505,7 +6568,7 @@ void ir_gen_tree(irGen *s) {
isize ez = type_size_of(a, t->DynamicArray.elem);
irValue *elem_size = ir_emit_struct_ep(proc, tag, 1);
- ir_emit_store(proc, elem_size, ir_make_const_int(a, ez));
+ ir_emit_store(proc, elem_size, ir_const_int(a, ez));
} break;
case Type_Slice: {
ir_emit_comment(proc, str_lit("Type_Info_Slice"));
@@ -6515,7 +6578,7 @@ void ir_gen_tree(irGen *s) {
isize ez = type_size_of(a, t->Slice.elem);
irValue *elem_size = ir_emit_struct_ep(proc, tag, 1);
- ir_emit_store(proc, elem_size, ir_make_const_int(a, ez));
+ ir_emit_store(proc, elem_size, ir_const_int(a, ez));
} break;
case Type_Vector: {
ir_emit_comment(proc, str_lit("Type_Info_Vector"));
@@ -6524,9 +6587,9 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), gep);
isize ez = type_size_of(a, t->Vector.elem);
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_make_const_int(a, ez));
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_make_const_int(a, t->Vector.count));
- ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_make_const_int(a, type_align_of(a, t)));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 1), ir_const_int(a, ez));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 2), ir_const_int(a, t->Vector.count));
+ ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_int(a, type_align_of(a, t)));
} break;
case Type_Proc: {
@@ -6544,8 +6607,8 @@ void ir_gen_tree(irGen *s) {
if (t->Proc.results != NULL) {
ir_emit_store(proc, results, ir_get_type_info_ptr(proc, t->Proc.results));
}
- ir_emit_store(proc, variadic, ir_make_const_bool(a, t->Proc.variadic));
- ir_emit_store(proc, convention, ir_make_const_int(a, t->Proc.calling_convention));
+ ir_emit_store(proc, variadic, ir_const_bool(a, t->Proc.variadic));
+ ir_emit_store(proc, convention, ir_const_int(a, t->Proc.calling_convention));
// TODO(bill): Type_Info for procedures
} break;
@@ -6555,7 +6618,7 @@ void ir_gen_tree(irGen *s) {
irValue *record = ir_emit_struct_ep(proc, tag, 0);
{
- irValue *align = ir_make_const_int(a, type_align_of(a, t));
+ irValue *align = ir_const_int(a, type_align_of(a, t));
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
}
@@ -6566,17 +6629,17 @@ void ir_gen_tree(irGen *s) {
// NOTE(bill): offset is not used for tuples
Entity *f = t->Tuple.variables[i];
- irValue *index = ir_make_const_int(a, i);
+ irValue *index = ir_const_int(a, i);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
- ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+ ir_emit_store(proc, name, ir_const_string(a, f->token.string));
}
}
- irValue *count = ir_make_const_int(a, t->Tuple.variable_count);
+ irValue *count = ir_const_int(a, t->Tuple.variable_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
} break;
@@ -6588,11 +6651,11 @@ void ir_gen_tree(irGen *s) {
irValue *record = ir_emit_struct_ep(proc, tag, 0);
{
- irValue *size = ir_make_const_int(a, type_size_of(a, t));
- irValue *align = ir_make_const_int(a, type_align_of(a, t));
- irValue *packed = ir_make_const_bool(a, t->Record.is_packed);
- irValue *ordered = ir_make_const_bool(a, t->Record.is_ordered);
- irValue *custom_align = ir_make_const_bool(a, t->Record.custom_align);
+ irValue *size = ir_const_int(a, type_size_of(a, t));
+ irValue *align = ir_const_int(a, type_align_of(a, t));
+ irValue *packed = ir_const_bool(a, t->Record.is_packed);
+ irValue *ordered = ir_const_bool(a, t->Record.is_ordered);
+ irValue *custom_align = ir_const_bool(a, t->Record.custom_align);
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 5), packed);
@@ -6612,19 +6675,19 @@ void ir_gen_tree(irGen *s) {
i64 foffset = t->Record.offsets[f->Variable.field_index];
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
- irValue *index = ir_make_const_int(a, source_index);
+ irValue *index = ir_const_int(a, source_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
- ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+ ir_emit_store(proc, name, ir_const_string(a, f->token.string));
}
- ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
+ ir_emit_store(proc, offset, ir_const_int(a, foffset));
}
- irValue *count = ir_make_const_int(a, t->Record.field_count);
+ irValue *count = ir_const_int(a, t->Record.field_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count);
@@ -6633,8 +6696,8 @@ void ir_gen_tree(irGen *s) {
ir_emit_comment(proc, str_lit("Type_Info_Union"));
tag = ir_emit_conv(proc, ti_ptr, t_type_info_union_ptr);
{
- irValue *size = ir_make_const_int(a, type_size_of(a, t));
- irValue *align = ir_make_const_int(a, type_align_of(a, t));
+ irValue *size = ir_const_int(a, type_size_of(a, t));
+ irValue *align = ir_const_int(a, type_align_of(a, t));
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), size);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), align);
}
@@ -6655,20 +6718,20 @@ void ir_gen_tree(irGen *s) {
i64 foffset = t->Record.offsets[f->Variable.field_index];
GB_ASSERT(f->kind == Entity_Variable && f->flags & EntityFlag_Field);
- irValue *index = ir_make_const_int(a, field_index);
+ irValue *index = ir_const_int(a, field_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
- ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+ ir_emit_store(proc, name, ir_const_string(a, f->token.string));
}
- ir_emit_store(proc, offset, ir_make_const_int(a, foffset));
+ ir_emit_store(proc, offset, ir_const_int(a, foffset));
}
- irValue *count = ir_make_const_int(a, field_count);
+ irValue *count = ir_const_int(a, field_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 1), memory_names, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, common_fields, 2), memory_offsets, count, count);
@@ -6687,17 +6750,17 @@ void ir_gen_tree(irGen *s) {
Entity *f = t->Record.variants[variant_index+1]; // Skip zeroth
irValue *tip = ir_get_type_info_ptr(proc, f->type);
- irValue *index = ir_make_const_int(a, variant_index);
+ irValue *index = ir_const_int(a, variant_index);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
- ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+ ir_emit_store(proc, name, ir_const_string(a, f->token.string));
}
}
- irValue *count = ir_make_const_int(a, variant_count);
+ irValue *count = ir_const_int(a, variant_count);
ir_fill_slice(proc, variant_names, memory_names, count, count);
ir_fill_slice(proc, variant_types, memory_types, count, count);
}
@@ -6709,8 +6772,8 @@ void ir_gen_tree(irGen *s) {
irValue *record = ir_emit_struct_ep(proc, tag, 0);
{
- irValue *size = ir_make_const_int(a, type_size_of(a, t));
- irValue *align = ir_make_const_int(a, type_align_of(a, t));
+ irValue *size = ir_const_int(a, type_size_of(a, t));
+ irValue *align = ir_const_int(a, type_align_of(a, t));
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 3), size);
ir_emit_store(proc, ir_emit_struct_ep(proc, record, 4), align);
}
@@ -6721,18 +6784,18 @@ void ir_gen_tree(irGen *s) {
for (isize i = 0; i < t->Record.field_count; i++) {
Entity *f = t->Record.fields[i];
- irValue *index = ir_make_const_int(a, i);
+ irValue *index = ir_const_int(a, i);
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
// NOTE(bill): Offsets are always 0
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
if (f->token.string.len > 0) {
irValue *name = ir_emit_ptr_offset(proc, memory_names, index);
- ir_emit_store(proc, name, ir_make_const_string(a, f->token.string));
+ ir_emit_store(proc, name, ir_const_string(a, f->token.string));
}
}
- irValue *count = ir_make_const_int(a, t->Record.field_count);
+ irValue *count = ir_const_int(a, t->Record.field_count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 0), memory_types, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 1), memory_names, count, count);
ir_fill_slice(proc, ir_emit_struct_ep(proc, record, 2), memory_offsets, count, count);
@@ -6764,18 +6827,18 @@ void ir_gen_tree(irGen *s) {
if (is_value_int) {
i64 i = value.value_integer;
value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr);
- ir_emit_store(proc, value_ep, ir_make_const_i64(a, i));
+ ir_emit_store(proc, value_ep, ir_const_i64(a, i));
} else {
GB_ASSERT(is_type_float(t->Record.enum_base_type));
f64 f = value.value_float;
value_ep = ir_emit_conv(proc, value_ep, t_f64_ptr);
- ir_emit_store(proc, value_ep, ir_make_const_f64(a, f));
+ ir_emit_store(proc, value_ep, ir_const_f64(a, f));
}
- ir_emit_store(proc, name_ep, ir_make_const_string(a, fields[i]->token.string));
+ ir_emit_store(proc, name_ep, ir_const_string(a, fields[i]->token.string));
}
- irValue *v_count = ir_make_const_int(a, count);
+ irValue *v_count = ir_const_int(a, count);
irValue *names = ir_emit_struct_ep(proc, tag, 1);
irValue *name_array_elem = ir_array_elem(proc, name_array);
@@ -6805,7 +6868,7 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, key, ir_get_type_info_ptr(proc, t->Map.key));
ir_emit_store(proc, value, ir_get_type_info_ptr(proc, t->Map.value));
ir_emit_store(proc, generated_struct, ir_get_type_info_ptr(proc, t->Map.generated_struct_type));
- ir_emit_store(proc, count, ir_make_const_int(a, t->Map.count));
+ ir_emit_store(proc, count, ir_const_int(a, t->Map.count));
} break;
}
@@ -6819,7 +6882,7 @@ void ir_gen_tree(irGen *s) {
Entity *f = ti->Record.variants[i];
if (are_types_identical(f->type, tag_type)) {
found = true;
- irValue *tag = ir_make_const_int(a, i);
+ irValue *tag = ir_const_int(a, i);
irValue *ptr = ir_emit_union_tag_ptr(proc, ti_ptr);
ir_emit_store(proc, ptr, tag);
break;
@@ -6861,6 +6924,7 @@ void ir_gen_tree(irGen *s) {
}
+
// m->layout = str_lit("e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64");
}
diff --git a/src/ir_print.c b/src/ir_print.c
index cca26b925..973b3d6a0 100644
--- a/src/ir_print.c
+++ b/src/ir_print.c
@@ -306,7 +306,7 @@ void ir_print_compound_element(irFileBuffer *f, irModule *m, ExactValue v, Type
}
void ir_print_exact_value(irFileBuffer *f, irModule *m, ExactValue value, Type *type) {
- type = base_type(base_enum_type(type));
+ type = core_type(type);
if (is_type_float(type)) {
value = exact_value_to_float(value);
} else if (is_type_integer(type)) {
@@ -942,7 +942,7 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
switch (uo->op) {
case Token_Sub:
if (is_type_float(elem_type)) {
- ir_print_exact_value(f, m, make_exact_value_float(0), type);
+ ir_print_exact_value(f, m, exact_value_float(0), type);
} else {
ir_fprintf(f, "0");
}
@@ -1197,17 +1197,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
ir_fprintf(f, "call void ");
ir_print_encoded_global(f, str_lit("__bounds_check_error"), false);
ir_fprintf(f, "(");
- ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
+ ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
- ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
+ ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
- ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
+ ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
@@ -1232,17 +1232,17 @@ void ir_print_instr(irFileBuffer *f, irModule *m, irValue *value) {
}
ir_fprintf(f, "(");
- ir_print_compound_element(f, m, make_exact_value_string(bc->pos.file), t_string);
+ ir_print_compound_element(f, m, exact_value_string(bc->pos.file), t_string);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
- ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.line), t_int);
+ ir_print_exact_value(f, m, exact_value_integer(bc->pos.line), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
ir_fprintf(f, " ");
- ir_print_exact_value(f, m, make_exact_value_integer(bc->pos.column), t_int);
+ ir_print_exact_value(f, m, exact_value_integer(bc->pos.column), t_int);
ir_fprintf(f, ", ");
ir_print_type(f, m, t_int);
@@ -1408,10 +1408,6 @@ void print_llvm_ir(irGen *ir) {
irFileBuffer buf = {0}, *f = &buf;
ir_file_buffer_init(f, &ir->output_file);
- if (m->layout.len > 0) {
- ir_fprintf(f, "target datalayout = \"%.*s\"\n", LIT(m->layout));
- }
-
ir_print_encoded_local(f, str_lit("..string"));
ir_fprintf(f, " = type {i8*, ");
ir_print_type(f, m, t_int);
diff --git a/src/main.c b/src/main.c
index 25ed2eb49..242af444d 100644
--- a/src/main.c
+++ b/src/main.c
@@ -2,15 +2,15 @@
extern "C" {
#endif
+#define USE_CUSTOM_BACKEND false
#include "common.c"
#include "timings.c"
#include "build_settings.c"
#include "tokenizer.c"
#include "parser.c"
-// #include "printer.c"
#include "checker.c"
-// #include "ssa.c"
+#include "ssa.c"
#include "ir.c"
#include "ir_opt.c"
#include "ir_print.c"
@@ -151,6 +151,7 @@ int main(int argc, char **argv) {
init_scratch_memory(gb_megabytes(10));
init_global_error_collector();
+
#if 1
init_build_context();
@@ -215,7 +216,7 @@ int main(int argc, char **argv) {
#endif
-#if 0
+#if USE_CUSTOM_BACKEND
if (global_error_collector.count != 0) {
return 1;
}
@@ -224,7 +225,7 @@ int main(int argc, char **argv) {
return 1;
}
- if (!ssa_generate(&checker.info)) {
+ if (!ssa_generate(&parser, &checker.info)) {
return 1;
}
#else
diff --git a/src/parser.c b/src/parser.c
index 160b72ef3..a41fc5c06 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -139,6 +139,10 @@ AstNodeArray make_ast_node_array(AstFile *f) {
AstNodeArray elems; \
Token open, close; \
}) \
+ AST_NODE_KIND(Alias, "alias", struct { \
+ Token token; \
+ AstNode *expr; \
+ }) \
AST_NODE_KIND(_ExprBegin, "", i32) \
AST_NODE_KIND(BadExpr, "bad expression", struct { Token begin, end; }) \
AST_NODE_KIND(TagExpr, "tag expression", struct { Token token, name; AstNode *expr; }) \
@@ -215,6 +219,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(ForStmt, "for statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *init; \
AstNode *cond; \
AstNode *post; \
@@ -222,6 +227,7 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(RangeStmt, "range statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *value; \
AstNode *index; \
Token in_token; \
@@ -235,20 +241,22 @@ AST_NODE_KIND(_ComplexStmtBegin, "", i32) \
}) \
AST_NODE_KIND(MatchStmt, "match statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *init; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(TypeMatchStmt, "type match statement", struct { \
Token token; \
+ AstNode *label; \
AstNode *tag; \
AstNode *body; \
}) \
AST_NODE_KIND(DeferStmt, "defer statement", struct { Token token; AstNode *stmt; }) \
- AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; }) \
+ AST_NODE_KIND(BranchStmt, "branch statement", struct { Token token; AstNode *label; }) \
AST_NODE_KIND(UsingStmt, "using statement", struct { \
Token token; \
- AstNode *node; \
+ AstNodeArray list; \
}) \
AST_NODE_KIND(AsmOperand, "assembly operand", struct { \
Token string; \
@@ -301,6 +309,10 @@ AST_NODE_KIND(_DeclBegin, "", i32) \
AstNode *cond; \
bool is_system; \
}) \
+ AST_NODE_KIND(Label, "label", struct { \
+ Token token; \
+ AstNode *name; \
+ }) \
AST_NODE_KIND(_DeclEnd, "", i32) \
AST_NODE_KIND(Field, "field", struct { \
AstNodeArray names; \
@@ -398,7 +410,6 @@ String const ast_node_strings[] = {
typedef struct AstNode {
AstNodeKind kind;
- // AstNode *prev, *next; // NOTE(bill): allow for Linked list
u32 stmt_state_flags;
union {
#define AST_NODE_KIND(_kind_name_, name, ...) GB_JOIN2(AstNode, _kind_name_) _kind_name_;
@@ -410,7 +421,9 @@ typedef struct AstNode {
#define ast_node(n_, Kind_, node_) GB_JOIN2(AstNode, Kind_) *n_ = &(node_)->Kind_; GB_ASSERT((node_)->kind == GB_JOIN2(AstNode_, Kind_))
#define case_ast_node(n_, Kind_, node_) case GB_JOIN2(AstNode_, Kind_): { ast_node(n_, Kind_, node_);
+#ifndef case_end
#define case_end } break;
+#endif
gb_inline bool is_ast_node_expr(AstNode *node) {
@@ -445,6 +458,8 @@ Token ast_node_token(AstNode *node) {
return ast_node_token(node->CompoundLit.type);
}
return node->CompoundLit.open;
+ case AstNode_Alias: return node->Alias.token;
+
case AstNode_TagExpr: return node->TagExpr.token;
case AstNode_RunExpr: return node->RunExpr.token;
case AstNode_BadExpr: return node->BadExpr.begin;
@@ -492,6 +507,7 @@ Token ast_node_token(AstNode *node) {
case AstNode_ValueDecl: return ast_node_token(node->ValueDecl.names.e[0]);
case AstNode_ImportDecl: return node->ImportDecl.token;
case AstNode_ForeignLibrary: return node->ForeignLibrary.token;
+ case AstNode_Label: return node->Label.token;
case AstNode_Field:
@@ -771,6 +787,13 @@ AstNode *ast_compound_lit(AstFile *f, AstNode *type, AstNodeArray elems, Token o
result->CompoundLit.close = close;
return result;
}
+AstNode *ast_alias(AstFile *f, Token token, AstNode *expr) {
+ AstNode *result = make_ast_node(f, AstNode_Alias);
+ result->Alias.token = token;
+ result->Alias.expr = expr;
+ return result;
+}
+
AstNode *ast_ternary_expr(AstFile *f, AstNode *cond, AstNode *x, AstNode *y) {
AstNode *result = make_ast_node(f, AstNode_TernaryExpr);
@@ -910,19 +933,21 @@ AstNode *ast_defer_stmt(AstFile *f, Token token, AstNode *stmt) {
return result;
}
-AstNode *ast_branch_stmt(AstFile *f, Token token) {
+AstNode *ast_branch_stmt(AstFile *f, Token token, AstNode *label) {
AstNode *result = make_ast_node(f, AstNode_BranchStmt);
result->BranchStmt.token = token;
+ result->BranchStmt.label = label;
return result;
}
-AstNode *ast_using_stmt(AstFile *f, Token token, AstNode *node) {
+AstNode *ast_using_stmt(AstFile *f, Token token, AstNodeArray list) {
AstNode *result = make_ast_node(f, AstNode_UsingStmt);
result->UsingStmt.token = token;
- result->UsingStmt.node = node;
+ result->UsingStmt.list = list;
return result;
}
+
AstNode *ast_asm_operand(AstFile *f, Token string, AstNode *operand) {
AstNode *result = make_ast_node(f, AstNode_AsmOperand);
result->AsmOperand.string = string;
@@ -1124,6 +1149,13 @@ AstNode *ast_foreign_library(AstFile *f, Token token, Token filepath, Token libr
return result;
}
+AstNode *ast_label_decl(AstFile *f, Token token, AstNode *name) {
+ AstNode *result = make_ast_node(f, AstNode_Label);
+ result->Label.token = token;
+ result->Label.name = name;
+ return result;
+}
+
bool next_token(AstFile *f) {
Token prev = f->curr_token;
@@ -1762,6 +1794,7 @@ AstNode *parse_operand(AstFile *f, bool lhs) {
} else if (str_eq(name.string, str_lit("line"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("procedure"))) { return ast_basic_directive(f, token, name.string);
} else if (str_eq(name.string, str_lit("type"))) { return ast_helper_type(f, token, parse_type(f));
+ } else if (!lhs && str_eq(name.string, str_lit("alias"))) { return ast_alias(f, token, parse_expr(f, false));
} else {
operand = ast_tag_expr(f, token, name, parse_expr(f, false));
}
@@ -2129,7 +2162,7 @@ AstNode *parse_expr(AstFile *f, bool lhs) {
AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
AstNodeArray list = make_ast_node_array(f);
- do {
+ for (;;) {
AstNode *e = parse_expr(f, lhs);
array_add(&list, e);
if (f->curr_token.kind != Token_Comma ||
@@ -2137,7 +2170,7 @@ AstNodeArray parse_expr_list(AstFile *f, bool lhs) {
break;
}
next_token(f);
- } while (true);
+ }
return list;
}
@@ -2320,7 +2353,7 @@ AstNode *parse_block_stmt(AstFile *f, b32 is_when) {
return parse_body(f);
}
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow);
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow);
AstNode *parse_results(AstFile *f) {
@@ -2339,7 +2372,7 @@ AstNode *parse_results(AstFile *f) {
AstNode *list = NULL;
expect_token(f, Token_OpenParen);
- list = parse_field_list(f, NULL, 0, Token_Comma, Token_CloseParen);
+ list = parse_field_list(f, NULL, 0, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
return list;
}
@@ -2350,7 +2383,7 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
Token proc_token = expect_token(f, Token_proc);
expect_token(f, Token_OpenParen);
- params = parse_field_list(f, NULL, FieldFlag_Signature, Token_Comma, Token_CloseParen);
+ params = parse_field_list(f, NULL, FieldFlag_Signature, Token_CloseParen);
expect_token_after(f, Token_CloseParen, "parameter list");
results = parse_results(f);
@@ -2369,17 +2402,6 @@ AstNode *parse_proc_type(AstFile *f, AstNode **foreign_library_, String *foreign
return ast_proc_type(f, proc_token, params, results, tags, cc);
}
-bool parse_expect_separator(AstFile *f, TokenKind separator, AstNode *param) {
- if (separator == Token_Semicolon) {
- expect_semicolon(f, param);
- } else {
- if (!allow_token(f, separator)) {
- return true;
- }
- }
- return false;
-}
-
AstNode *parse_var_type(AstFile *f, bool allow_ellipsis) {
if (allow_ellipsis && f->curr_token.kind == Token_Ellipsis) {
Token tok = f->curr_token;
@@ -2490,7 +2512,22 @@ AstNodeArray convert_to_ident_list(AstFile *f, AstNodeAndFlagsArray list, bool i
return idents;
}
-AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind separator, TokenKind follow) {
+
+bool parse_expect_field_separator(AstFile *f, AstNode *param) {
+ Token token = f->curr_token;
+ if (allow_token(f, Token_Comma)) {
+ return true;
+ }
+ if (token.kind == Token_Semicolon) {
+ next_token(f);
+ error(f->curr_token, "Expected a comma, got a semicolon");
+ return true;
+ }
+ return false;
+}
+
+AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow) {
+ TokenKind separator = Token_Comma;
Token start_token = f->curr_token;
AstNodeArray params = make_ast_node_array(f);
@@ -2528,7 +2565,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
- parse_expect_separator(f, separator, type);
+ parse_expect_field_separator(f, type);
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) {
@@ -2546,7 +2583,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *param = ast_field(f, names, type, set_flags);
array_add(&params, param);
- if (parse_expect_separator(f, separator, param)) {
+ if (!parse_expect_field_separator(f, param)) {
break;
}
}
@@ -2575,7 +2612,7 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
- return parse_field_list(f, field_count_, flags, Token_Comma, Token_CloseBrace);
+ return parse_field_list(f, field_count_, flags, Token_CloseBrace);
}
AstNode *parse_type_or_ident(AstFile *f) {
@@ -3041,46 +3078,6 @@ AstNode *parse_for_stmt(AstFile *f) {
cond = convert_stmt_to_expr(f, cond, str_lit("boolean expression"));
return ast_for_stmt(f, token, init, cond, post, body);
-
-#if 0
- Token token = expect_token(f, Token_for);
- AstNodeArray names = parse_ident_list(f);
- parse_check_name_list_for_reserves(f, names);
- Token colon = expect_token_after(f, Token_in, "for name list");
-
- isize prev_level = f->expr_level;
- f->expr_level = -1;
- AstNode *expr = parse_expr(f, false);
- switch (f->curr_token.kind) {
- case Token_HalfOpenRange:
- case Token_Ellipsis: {
- Token op = f->curr_token;
- next_token(f);
- AstNode *right = parse_expr(f, false);
- expr = ast_interval_expr(f, op, expr, right);
- } break;
- }
- f->expr_level = prev_level;
-
- AstNode *value = NULL;
- AstNode *index = NULL;
- AstNode *body = parse_block_stmt(f, false);
-
- switch (names.count) {
- case 1:
- value = names.e[0];
- break;
- case 2:
- value = names.e[0];
- index = names.e[1];
- break;
- default:
- error(token, "Expected at 1 or 2 identifiers");
- return ast_bad_stmt(f, token, f->curr_token);
- }
-
- return ast_range_stmt(f, token, value, index, expr, body);
-#endif
}
@@ -3102,9 +3099,17 @@ AstNode *parse_case_clause(AstFile *f) {
AstNode *parse_type_case_clause(AstFile *f) {
Token token = f->curr_token;
- AstNodeArray clause = make_ast_node_array(f);
+ AstNodeArray list = make_ast_node_array(f);
if (allow_token(f, Token_case)) {
- array_add(&clause, parse_type(f));
+ for (;;) {
+ AstNode *t = parse_type(f);
+ array_add(&list, t);
+ if (f->curr_token.kind != Token_Comma ||
+ f->curr_token.kind == Token_EOF) {
+ break;
+ }
+ next_token(f);
+ }
} else {
expect_token(f, Token_default);
}
@@ -3112,7 +3117,7 @@ AstNode *parse_type_case_clause(AstFile *f) {
// expect_token(f, Token_ArrowRight); // TODO(bill): Is this the best syntax?
AstNodeArray stmts = parse_stmt_list(f);
- return ast_case_clause(f, token, clause, stmts);
+ return ast_case_clause(f, token, list, stmts);
}
@@ -3256,43 +3261,47 @@ AstNode *parse_stmt(AstFile *f) {
case Token_break:
case Token_continue:
- case Token_fallthrough:
+ case Token_fallthrough: {
+ AstNode *label = NULL;
next_token(f);
- s = ast_branch_stmt(f, token);
+ if (token.kind != Token_fallthrough &&
+ f->curr_token.kind == Token_Ident) {
+ label = parse_ident(f);
+ }
+ s = ast_branch_stmt(f, token, label);
expect_semicolon(f, s);
return s;
+ }
case Token_using: {
// TODO(bill): Make using statements better
Token token = expect_token(f, Token_using);
- AstNode *node = parse_stmt(f);
+ AstNodeArray list = parse_lhs_expr_list(f);
+ if (list.count == 0) {
+ syntax_error(token, "Illegal use of `using` statement");
+ expect_semicolon(f, NULL);
+ return ast_bad_stmt(f, token, f->curr_token);
+ }
- switch (node->kind) {
- case AstNode_ValueDecl:
- if (!node->ValueDecl.is_var) {
+ if (f->curr_token.kind != Token_Colon) {
+ expect_semicolon(f, list.e[list.count-1]);
+ return ast_using_stmt(f, token, list);
+ }
+
+ AstNode *decl = parse_simple_stmt(f, false);
+ expect_semicolon(f, decl);
+
+ if (decl->kind == AstNode_ValueDecl) {
+ if (!decl->ValueDecl.is_var) {
syntax_error(token, "`using` may not be applied to constant declarations");
- } else {
- if (f->curr_proc == NULL) {
- syntax_error(token, "`using` is not allowed at the file scope");
- } else {
- node->ValueDecl.flags |= VarDeclFlag_using;
- }
+ return decl;
}
- return node;
- case AstNode_ExprStmt: {
- AstNode *e = unparen_expr(node->ExprStmt.expr);
- while (e->kind == AstNode_SelectorExpr) {
- e = unparen_expr(e->SelectorExpr.selector);
- }
- if (e->kind == AstNode_Ident) {
- return ast_using_stmt(f, token, node);
- } else if (e->kind == AstNode_Implicit) {
- syntax_error(token, "Illegal use of `using` statement with implicit value `%.*s`", LIT(e->Implicit.string));
- return ast_bad_stmt(f, token, f->curr_token);
+ if (f->curr_proc == NULL) {
+ syntax_error(token, "`using` is not allowed at the file scope");
+ } else {
+ decl->ValueDecl.flags |= VarDeclFlag_using;
}
- } break;
-
-
+ return decl;
}
syntax_error(token, "Illegal use of `using` statement");
@@ -3345,7 +3354,25 @@ AstNode *parse_stmt(AstFile *f) {
Token name = expect_token(f, Token_Ident);
String tag = name.string;
- if (str_eq(tag, str_lit("import"))) {
+ if (str_eq(tag, str_lit("label"))) {
+ AstNode *name = parse_ident(f);
+ AstNode *label = ast_label_decl(f, token, name);
+ AstNode *stmt = parse_stmt(f);
+
+ #define _SET_LABEL(Kind_, label_) case GB_JOIN2(AstNode_, Kind_): (stmt->Kind_).label = label_; break
+ switch (stmt->kind) {
+ _SET_LABEL(ForStmt, label);
+ _SET_LABEL(RangeStmt, label);
+ _SET_LABEL(MatchStmt, label);
+ _SET_LABEL(TypeMatchStmt, label);
+ default:
+ syntax_error(token, "#label may only be applied to a loop");
+ break;
+ }
+ #undef _SET_LABEL
+
+ return stmt;
+ } else if (str_eq(tag, str_lit("import"))) {
AstNode *cond = NULL;
Token import_name = {0};
@@ -3505,7 +3532,6 @@ AstNode *parse_stmt(AstFile *f) {
return s;
}
-
if (str_eq(tag, str_lit("include"))) {
syntax_error(token, "#include is not a valid import declaration kind. Use #load instead");
s = ast_bad_stmt(f, token, f->curr_token);
@@ -3827,7 +3853,7 @@ ParseFileError parse_files(Parser *p, char *init_filename) {
gb_printf_err("File permissions problem");
break;
case ParseFile_NotFound:
- gb_printf_err("File cannot be found");
+ gb_printf_err("File cannot be found (`%.*s`)", LIT(import_path));
break;
case ParseFile_InvalidToken:
gb_printf_err("Invalid token found in file");
diff --git a/src/ssa.c b/src/ssa.c
new file mode 100644
index 000000000..2ed9d59f9
--- /dev/null
+++ b/src/ssa.c
@@ -0,0 +1,2269 @@
+typedef struct ssaModule ssaModule;
+typedef struct ssaValue ssaValue;
+typedef struct ssaValueArgs ssaValueArgs;
+typedef struct ssaBlock ssaBlock;
+typedef struct ssaProc ssaProc;
+typedef struct ssaEdge ssaEdge;
+typedef struct ssaRegister ssaRegister;
+typedef struct ssaTargetList ssaTargetList;
+typedef enum ssaBlockKind ssaBlockKind;
+typedef enum ssaBranchPrediction ssaBranchPrediction;
+
+String ssa_mangle_name(ssaModule *m, String path, Entity *e);
+
+#define MAP_TYPE ssaValue *
+#define MAP_PROC map_ssa_value_
+#define MAP_NAME MapSsaValue
+#include "map.c"
+
+typedef Array(ssaValue *) ssaValueArray;
+
+#include "ssa_op.c"
+
+#define SSA_DEFAULT_VALUE_ARG_CAPACITY 8
+struct ssaValueArgs {
+ ssaValue ** e;
+ isize count;
+ isize capacity;
+ ssaValue * backing[SSA_DEFAULT_VALUE_ARG_CAPACITY];
+ gbAllocator allocator;
+};
+
+struct ssaValue {
+ i32 id; // Unique identifier but the pointer could be used too
+ ssaOp op; // Operation that computes this value
+ Type * type;
+ ssaBlock * block; // Containing basic block
+
+ i32 uses;
+ ssaValueArgs args;
+ ExactValue exact_value; // Used for constants
+
+ String comment_string;
+};
+
+enum ssaBlockKind {
+ ssaBlock_Invalid,
+
+ // NOTE(bill): These are the generic block types and for more specific
+ // architectures, these could become conditions blocks like amd64 LT or EQ
+ ssaBlock_Entry, // Entry point
+ ssaBlock_Plain,
+ ssaBlock_If,
+ ssaBlock_Ret,
+ ssaBlock_RetJmp, // Stores return value and jumps to Ret block
+ ssaBlock_Exit,
+
+ ssaBlock_Count,
+};
+
+enum ssaBranchPrediction {
+ ssaBranch_Unknown = 0,
+ ssaBranch_Likely = +1,
+ ssaBranch_Unlikely = -1,
+};
+
+// ssaEdge represents a control flow graph (CFG) edge
+struct ssaEdge {
+ // Succs array: Block To
+ // Preds array: Block From
+ ssaBlock *block;
+ // Index of reverse edge
+ isize index;
+};
+
+typedef Array(ssaEdge) ssaEdgeArray;
+
+struct ssaBlock {
+ i32 id; // Unique identifier but the pointer could be used too
+ ssaBlockKind kind;
+ ssaProc * proc; // Containing procedure
+ String name; // Optional
+
+ // Likely branch direction
+ ssaBranchPrediction likeliness;
+
+ // Determines how a block exits
+ // It depends on the type of block:
+ // - BlockIf will be a boolean value
+ // - BlockExit will be a memory control value
+ ssaValue *control;
+
+ ssaValueArray values;
+ ssaEdgeArray preds;
+ ssaEdgeArray succs;
+};
+
+struct ssaTargetList {
+ ssaTargetList *prev;
+ ssaBlock * break_;
+ ssaBlock * continue_;
+ ssaBlock * fallthrough_;
+};
+
+struct ssaProc {
+ ssaModule * module; // Parent module
+ gbAllocator allocator; // Same allocator as the parent module
+ String name; // Mangled name
+ Entity * entity;
+ DeclInfo * decl_info;
+
+ Array(ssaBlock *) blocks;
+ ssaBlock * entry; // Entry block
+ ssaBlock * exit; // Exit block
+ ssaBlock * curr_block;
+
+ ssaTargetList * target_list;
+
+ i32 block_id;
+ i32 value_id;
+ MapSsaValue values; // Key: Entity *
+};
+
+struct ssaRegister {
+ i32 id;
+ i32 size;
+};
+
+struct ssaModule {
+ CheckerInfo * info;
+ gbAllocator allocator;
+ gbArena arena;
+ gbAllocator tmp_allocator;
+ gbArena tmp_arena;
+
+ MapEntity min_dep_map; // Key: Entity *
+ MapSsaValue values; // Key: Entity *
+ // List of registers for the specific architecture
+ Array(ssaRegister) registers;
+
+ ssaProc *proc; // current procedure
+
+ Entity *entry_point_entity;
+
+ u32 stmt_state_flags;
+
+ Array(ssaProc *) procs;
+ ssaValueArray procs_to_generate;
+};
+
+
+void ssa_push_target_list(ssaProc *p, ssaBlock *break_, ssaBlock *continue_, ssaBlock *fallthrough_) {
+ ssaTargetList *tl = gb_alloc_item(p->allocator, ssaTargetList);
+ tl->prev = p->target_list;
+ tl->break_ = break_;
+ tl->continue_ = continue_;
+ tl->fallthrough_ = fallthrough_;
+ p->target_list = tl;
+}
+
+void ssa_pop_target_list(ssaProc *p) {
+ p->target_list = p->target_list->prev;
+}
+
+
+ssaBlock *ssa_new_block(ssaProc *p, ssaBlockKind kind, char *name) {
+ ssaBlock *b = gb_alloc_item(p->allocator, ssaBlock);
+ b->id = p->block_id++;
+ b->kind = kind;
+ b->proc = p;
+ if (name != NULL || name[0] != 0) {
+ b->name = make_string_c(name);
+ }
+
+ array_init(&b->values, heap_allocator());
+ array_init(&b->preds, heap_allocator());
+ array_init(&b->succs, heap_allocator());
+ array_add(&p->blocks, b);
+ return b;
+}
+
+void ssa_clear_block(ssaProc *p, ssaBlock *b) {
+ GB_ASSERT(b->proc != NULL);
+ array_clear(&b->values);
+ array_clear(&b->preds);
+ array_clear(&b->succs);
+ b->proc = NULL;
+ b->kind = ssaBlock_Plain;
+}
+
+
+void ssa_start_block(ssaProc *p, ssaBlock *b) {
+ GB_ASSERT(p->curr_block == NULL);
+ p->curr_block = b;
+}
+
+ssaBlock *ssa_end_block(ssaProc *p) {
+ ssaBlock *b = p->curr_block;
+ if (b == NULL) {
+ return NULL;
+ }
+ p->curr_block = NULL;
+ return b;
+}
+
+void ssa_add_edge_to(ssaBlock *b, ssaBlock *c) {
+ if (b == NULL) {
+ return;
+ }
+ GB_ASSERT(c != NULL);
+ isize i = b->succs.count;
+ isize j = b->preds.count;
+ ssaEdge s = {c, j};
+ ssaEdge p = {b, i};
+ array_add(&b->succs, s);
+ array_add(&c->preds, p);
+}
+
+void ssa_set_control(ssaBlock *b, ssaValue *v) {
+ if (b->control != NULL) {
+ b->control->uses--;
+ }
+ b->control = v;
+ if (v != NULL) {
+ v->uses++;
+ }
+}
+
+void ssa_emit_jump(ssaProc *p, ssaBlock *edge) {
+ ssa_add_edge_to(ssa_end_block(p), edge);
+}
+
+void ssa_init_value_args(ssaValueArgs *va, gbAllocator a) {
+ va->e = va->backing;
+ va->count = 0;
+ va->capacity = gb_count_of(va->backing);
+ va->allocator = a;
+}
+
+void ssa_add_arg(ssaValueArgs *va, ssaValue *arg) {
+ if (va->count >= va->capacity) {
+ isize capacity = 2*va->capacity;
+ if (va->e == va->backing) { // Replace the backing with an allocated version instead
+ ssaValue **new_args = gb_alloc_array(va->allocator, ssaValue *, capacity);
+ gb_memcopy_array(new_args, va->e, va->count);
+ va->e = new_args;
+ } else {
+ isize old_cap_size = va->capacity * gb_size_of(ssaValue *);
+ isize new_cap_size = capacity * gb_size_of(ssaValue *);
+ va->e = gb_resize(va->allocator, va->e, old_cap_size, new_cap_size);
+ }
+ va->capacity = capacity;
+ }
+ va->e[va->count++] = arg; arg->uses++;
+}
+
+
+
+ssaValue *ssa_new_value(ssaProc *p, ssaOp op, Type *t, ssaBlock *b) {
+ GB_ASSERT(b != NULL);
+ ssaValue *v = gb_alloc_item(p->allocator, ssaValue);
+ v->id = p->value_id++;
+ v->op = op;
+ v->type = t;
+ v->block = b;
+ ssa_init_value_args(&v->args, p->allocator);
+ array_add(&b->values, v);
+ return v;
+}
+
+ssaValue *ssa_new_value0(ssaProc *p, ssaOp op, Type *t) {
+ ssaValue *v = ssa_new_value(p, op, t, p->curr_block);
+ return v;
+}
+ssaValue *ssa_new_value0v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) {
+ ssaValue *v = ssa_new_value0(p, op, t);
+ v->exact_value = exact_value;
+ return v;
+}
+
+ssaValue *ssa_new_value1(ssaProc *p, ssaOp op, Type *t, ssaValue *arg) {
+ ssaValue *v = ssa_new_value(p, op, t, p->curr_block);
+ ssa_add_arg(&v->args, arg);
+ return v;
+}
+ssaValue *ssa_new_value1v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg) {
+ ssaValue *v = ssa_new_value1(p, op, t, arg);
+ v->exact_value = exact_value;
+ return v;
+}
+ssaValue *ssa_new_value1i(ssaProc *p, ssaOp op, Type *t, i64 i, ssaValue *arg) {
+ return ssa_new_value1v(p, op, t, exact_value_integer(i), arg);
+}
+
+ssaValue *ssa_new_value2(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1) {
+ ssaValue *v = ssa_new_value(p, op, t, p->curr_block);
+ ssa_add_arg(&v->args, arg0);
+ ssa_add_arg(&v->args, arg1);
+ return v;
+}
+ssaValue *ssa_new_value2v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1) {
+ ssaValue *v = ssa_new_value2(p, op, t, arg0, arg1);
+ v->exact_value = exact_value;
+ return v;
+}
+
+ssaValue *ssa_new_value3(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) {
+ ssaValue *v = ssa_new_value(p, op, t, p->curr_block);
+ ssa_add_arg(&v->args, arg0);
+ ssa_add_arg(&v->args, arg1);
+ ssa_add_arg(&v->args, arg2);
+ return v;
+}
+ssaValue *ssa_new_value3v(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2) {
+ ssaValue *v = ssa_new_value3(p, op, t, arg0, arg1, arg2);
+ v->exact_value = exact_value;
+ return v;
+}
+
+ssaValue *ssa_new_value4(ssaProc *p, ssaOp op, Type *t, ssaValue *arg0, ssaValue *arg1, ssaValue *arg2, ssaValue *arg3) {
+ ssaValue *v = ssa_new_value(p, op, t, p->curr_block);
+ ssa_add_arg(&v->args, arg0);
+ ssa_add_arg(&v->args, arg1);
+ ssa_add_arg(&v->args, arg2);
+ ssa_add_arg(&v->args, arg3);
+ return v;
+}
+
+ssaValue *ssa_const_val(ssaProc *p, ssaOp op, Type *t, ExactValue exact_value) {
+ return ssa_new_value0v(p, op, t, exact_value);
+}
+
+ssaValue *ssa_const_bool (ssaProc *p, Type *t, bool c) { return ssa_const_val(p, ssaOp_ConstBool, t, exact_value_bool(c)); }
+ssaValue *ssa_const_i8 (ssaProc *p, Type *t, i8 c) { return ssa_const_val(p, ssaOp_Const8, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i16 (ssaProc *p, Type *t, i16 c) { return ssa_const_val(p, ssaOp_Const16, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i32 (ssaProc *p, Type *t, i32 c) { return ssa_const_val(p, ssaOp_Const32, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_i64 (ssaProc *p, Type *t, i64 c) { return ssa_const_val(p, ssaOp_Const64, t, exact_value_integer(cast(i64)c)); }
+ssaValue *ssa_const_f32 (ssaProc *p, Type *t, f32 c) { return ssa_const_val(p, ssaOp_Const32F, t, exact_value_float(c)); }
+ssaValue *ssa_const_f64 (ssaProc *p, Type *t, f64 c) { return ssa_const_val(p, ssaOp_Const64F, t, exact_value_float(c)); }
+ssaValue *ssa_const_string (ssaProc *p, Type *t, String c) { return ssa_const_val(p, ssaOp_ConstString, t, exact_value_string(c)); }
+ssaValue *ssa_const_empty_string(ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstString, t, (ExactValue){0}); }
+ssaValue *ssa_const_slice (ssaProc *p, Type *t, ExactValue v) { return ssa_const_val(p, ssaOp_ConstSlice, t, v); }
+ssaValue *ssa_const_nil (ssaProc *p, Type *t) { return ssa_const_val(p, ssaOp_ConstNil, t, (ExactValue){0}); }
+
+ssaValue *ssa_const_int(ssaProc *p, Type *t, i64 c) {
+ switch (8*type_size_of(p->allocator, t)) {
+ case 8: return ssa_const_i8 (p, t, cast(i8)c);
+ case 16: return ssa_const_i16(p, t, cast(i16)c);
+ case 32: return ssa_const_i32(p, t, cast(i32)c);
+ case 64: return ssa_const_i64(p, t, cast(i64)c);
+ }
+ GB_PANIC("Unknown int size");
+ return NULL;
+}
+
+void ssa_reset_value_args(ssaValue *v) {
+ for_array(i, v->args) {
+ v->args.e[i]->uses--;
+ }
+ v->args.count = 0;
+}
+
+void ssa_reset(ssaValue *v, ssaOp op) {
+ v->op = op;
+ v->exact_value = (ExactValue){0};
+ ssa_reset_value_args(v);
+}
+
+ssaValue *ssa_emit_load(ssaProc *p, ssaValue *v) {
+ GB_ASSERT(is_type_pointer(v->type));
+ return ssa_new_value1(p, ssaOp_Load, type_deref(v->type), v);
+}
+
+ssaValue *ssa_emit_store(ssaProc *p, ssaValue *dst, ssaValue *v) {
+ GB_ASSERT(is_type_pointer(dst->type));
+#if 1
+ // NOTE(bill): Sanity check
+ Type *a = core_type(type_deref(dst->type));
+ Type *b = core_type(v->type);
+ if (!is_type_untyped(b)) {
+ GB_ASSERT_MSG(are_types_identical(a, b), "%s %s", type_to_string(a), type_to_string(b));
+ }
+#endif
+ return ssa_new_value2(p, ssaOp_Store, dst->type, dst, v);
+}
+
+bool ssa_is_op_const(ssaOp op) {
+ switch (op) {
+ case ssaOp_ConstBool:
+ case ssaOp_ConstString:
+ case ssaOp_ConstSlice:
+ case ssaOp_ConstNil:
+ case ssaOp_Const8:
+ case ssaOp_Const16:
+ case ssaOp_Const32:
+ case ssaOp_Const64:
+ case ssaOp_Const32F:
+ case ssaOp_Const64F:
+ return true;
+ }
+ return false;
+}
+
+
+
+bool ssa_is_blank_ident(AstNode *node) {
+ if (node->kind == AstNode_Ident) {
+ ast_node(i, Ident, node);
+ return is_blank_ident(i->string);
+ }
+ return false;
+}
+
+
+typedef enum ssaAddrKind {
+ ssaAddr_Default,
+ ssaAddr_Map,
+} ssaAddrKind;
+
+typedef struct ssaAddr {
+ ssaValue * addr;
+ ssaAddrKind kind;
+} ssaAddr;
+
+ssaAddr ssa_addr(ssaValue *v) {
+ if (v != NULL) {
+ GB_ASSERT(is_type_pointer(v->type));
+ }
+ ssaAddr addr = {0};
+ addr.addr = v;
+ return addr;
+}
+
+Type *ssa_addr_type(ssaAddr addr) {
+ if (addr.addr == NULL) {
+ return NULL;
+ }
+
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("TODO: ssa_addr_type");
+ return NULL;
+ }
+
+ Type *t = addr.addr->type;
+ GB_ASSERT(is_type_pointer(t));
+ return type_deref(t);
+}
+
+
+
+ssaProc *ssa_new_proc(ssaModule *m, String name, Entity *entity, DeclInfo *decl_info) {
+ ssaProc *p = gb_alloc_item(m->allocator, ssaProc);
+ p->module = m;
+ p->allocator = m->allocator;
+ p->name = name;
+ p->entity = entity;
+ p->decl_info = decl_info;
+
+ array_init(&p->blocks, heap_allocator());
+ map_ssa_value_init(&p->values, heap_allocator());
+
+ return p;
+}
+
+ssaAddr ssa_add_local(ssaProc *p, Entity *e, AstNode *expr) {
+ Type *t = make_type_pointer(p->allocator, e->type);
+
+ ssaBlock *cb = p->curr_block;
+ p->curr_block = p->entry;
+ ssaValue *local = ssa_new_value0(p, ssaOp_Local, t);
+ p->curr_block = cb;
+
+ map_ssa_value_set(&p->values, hash_pointer(e), local);
+ map_ssa_value_set(&p->module->values, hash_pointer(e), local);
+ local->comment_string = e->token.string;
+
+ ssaValue *addr = ssa_new_value1(p, ssaOp_Addr, local->type, local);
+ ssa_new_value1(p, ssaOp_Zero, t, addr);
+ return ssa_addr(addr);
+}
+ssaAddr ssa_add_local_for_ident(ssaProc *p, AstNode *name) {
+ Entity **found = map_entity_get(&p->module->info->definitions, hash_pointer(name));
+ if (found) {
+ Entity *e = *found;
+ return ssa_add_local(p, e, name);
+ }
+
+ return ssa_addr(NULL);
+}
+
+ssaAddr ssa_add_local_generated(ssaProc *p, Type *t) {
+ GB_ASSERT(t != NULL);
+
+ Scope *scope = NULL;
+ if (p->curr_block) {
+ // scope = p->curr_block->scope;
+ }
+ Entity *e = make_entity_variable(p->allocator, scope, empty_token, t, false);
+ return ssa_add_local(p, e, NULL);
+}
+
+void ssa_emit_comment(ssaProc *p, String s) {
+ // ssa_new_value0v(p, ssaOp_Comment, NULL, exact_value_string(s));
+}
+
+#define SSA_MAX_STRUCT_FIELD_COUNT 4
+
+bool can_ssa_type(Type *t) {
+ i64 s = type_size_of(heap_allocator(), t);
+ if (s > 4*build_context.word_size) {
+ return false;
+ }
+ t = core_type(t);
+
+ switch (t->kind) {
+ case Type_Array:
+ return t->Array.count == 0;
+ case Type_Vector:
+ return s < 2*build_context.word_size;
+
+ case Type_DynamicArray:
+ return false;
+ case Type_Map:
+ return false;
+ case Type_Tuple:
+ if (t->Tuple.variable_count > SSA_MAX_STRUCT_FIELD_COUNT) {
+ return false;
+ }
+ for (isize i = 0; i < t->Tuple.variable_count; i++) {
+ if (!can_ssa_type(t->Tuple.variables[i]->type)) {
+ return false;
+ }
+ }
+ return true;
+ case Type_Record:
+ if (t->Record.kind == TypeRecord_Union) {
+ return false;
+ } else if (t->Record.kind == TypeRecord_Struct) {
+ if (t->Record.field_count > SSA_MAX_STRUCT_FIELD_COUNT) {
+ return false;
+ }
+ for (isize i = 0; i < t->Record.field_count; i++) {
+ if (!can_ssa_type(t->Record.fields[i]->type)) {
+ return false;
+ }
+ }
+ }
+ return true;
+ }
+ return true;
+}
+
+ssaAddr ssa_build_addr (ssaProc *p, AstNode *expr);
+ssaValue *ssa_build_expr (ssaProc *p, AstNode *expr);
+void ssa_build_stmt (ssaProc *p, AstNode *node);
+void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes);
+ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel);
+
+void ssa_addr_store(ssaProc *p, ssaAddr addr, ssaValue *value) {
+ if (addr.addr == NULL) {
+ return;
+ }
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("TODO(bill): ssa_addr_store");
+ return;
+ }
+
+ ssa_emit_store(p, addr.addr, value);
+}
+
+ssaValue *ssa_addr_load(ssaProc *p, ssaAddr addr) {
+ if (addr.addr == NULL) {
+ return NULL;
+ }
+
+ if (addr.kind == ssaAddr_Map) {
+ GB_PANIC("here\n");
+ return NULL;
+ }
+
+ Type *t = addr.addr->type;
+ Type *bt = base_type(t);
+ if (bt->kind == Type_Proc) {
+ return addr.addr;
+ }
+
+ return ssa_emit_load(p, addr.addr);
+}
+
+ssaValue *ssa_get_using_variable(ssaProc *p, Entity *e) {
+ GB_ASSERT(e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous);
+ String name = e->token.string;
+ Entity *parent = e->using_parent;
+ Selection sel = lookup_field(p->allocator, parent->type, name, false);
+ GB_ASSERT(sel.entity != NULL);
+ ssaValue **pv = map_ssa_value_get(&p->module->values, hash_pointer(parent));
+ ssaValue *v = NULL;
+ if (pv != NULL) {
+ v = *pv;
+ } else {
+ v = ssa_build_addr(p, e->using_expr).addr;
+ }
+ GB_ASSERT(v != NULL);
+ GB_ASSERT(type_deref(v->type) == parent->type);
+ return ssa_emit_deep_field_ptr_index(p, v, sel);
+}
+
+ssaAddr ssa_build_addr_from_entity(ssaProc *p, Entity *e, AstNode *expr) {
+ GB_ASSERT(e != NULL);
+
+ ssaValue *v = NULL;
+ ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e));
+ if (found) {
+ v = *found;
+ } else if (e->kind == Entity_Variable && e->flags & EntityFlag_Anonymous) {
+ // NOTE(bill): Calculate the using variable every time
+ v = ssa_get_using_variable(p, e);
+ }
+
+ if (v == NULL) {
+ GB_PANIC("Unknown value: %.*s, entity: %p %.*s\n", LIT(e->token.string), e, LIT(entity_strings[e->kind]));
+ }
+
+ return ssa_addr(v);
+}
+
+
+ssaValue *ssa_emit_conv(ssaProc *p, ssaValue *v, Type *t) {
+ Type *src_type = v->type;
+ if (are_types_identical(t, src_type)) {
+ return v;
+ }
+
+ Type *src = core_type(src_type);
+ Type *dst = core_type(t);
+
+ if (is_type_untyped_nil(src)) {
+ return ssa_const_nil(p, t);
+ }
+
+ // Pointer <-> Pointer
+ if (is_type_pointer(src) && is_type_pointer(dst)) {
+ return ssa_new_value1(p, ssaOp_Copy, dst, v);
+ }
+ // proc <-> proc
+ if (is_type_proc(src) && is_type_proc(dst)) {
+ return ssa_new_value1(p, ssaOp_Copy, dst, v);
+ }
+ // pointer -> proc
+ if (is_type_pointer(src) && is_type_proc(dst)) {
+ return ssa_new_value1(p, ssaOp_Copy, dst, v);
+ }
+ // proc -> pointer
+ if (is_type_proc(src) && is_type_pointer(dst)) {
+ return ssa_new_value1(p, ssaOp_Copy, dst, v);
+ }
+
+
+ gb_printf_err("ssa_emit_conv: src -> dst\n");
+ gb_printf_err("Not Identical %s != %s\n", type_to_string(src_type), type_to_string(t));
+ gb_printf_err("Not Identical %s != %s\n", type_to_string(src), type_to_string(dst));
+
+
+ GB_PANIC("Invalid type conversion: `%s` to `%s`", type_to_string(src_type), type_to_string(t));
+
+ return NULL;
+}
+
+
+// NOTE(bill): Returns NULL if not possible
+ssaValue *ssa_address_from_load_or_generate_local(ssaProc *p, ssaValue *v) {
+ if (v->op == ssaOp_Load) {
+ return v->args.e[0];
+ }
+ ssaAddr addr = ssa_add_local_generated(p, v->type);
+ ssa_new_value2(p, ssaOp_Store, addr.addr->type, addr.addr, v);
+ return addr.addr;
+}
+
+
+ssaValue *ssa_emit_array_index(ssaProc *p, ssaValue *v, ssaValue *index) {
+ GB_ASSERT(v != NULL);
+ GB_ASSERT(is_type_pointer(v->type));
+ Type *t = base_type(type_deref(v->type));
+ GB_ASSERT_MSG(is_type_array(t) || is_type_vector(t), "%s", type_to_string(t));
+ Type *elem_ptr = NULL;
+ if (is_type_array(t)) {
+ elem_ptr = make_type_pointer(p->allocator, t->Array.elem);
+ } else if (is_type_vector(t)) {
+ elem_ptr = make_type_pointer(p->allocator, t->Vector.elem);
+ }
+
+ return ssa_new_value2(p, ssaOp_ArrayIndex, elem_ptr, v, index);
+}
+
+ssaValue *ssa_emit_ptr_index(ssaProc *p, ssaValue *s, i64 index) {
+ gbAllocator a = p->allocator;
+ Type *t = base_type(type_deref(s->type));
+ Type *result_type = NULL;
+
+ if (is_type_struct(t)) {
+ GB_ASSERT(t->Record.field_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
+ result_type = make_type_pointer(a, t->Record.fields[index]->type);
+ } else if (is_type_union(t)) {
+ type_set_offsets(a, t);
+ GB_ASSERT(t->Record.field_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
+ result_type = make_type_pointer(a, t->Record.fields[index]->type);
+ i64 offset = t->Record.offsets[index];
+ ssaValue *ptr = ssa_emit_conv(p, s, t_u8_ptr);
+ ptr = ssa_new_value2(p, ssaOp_PtrOffset, ptr->type, ptr, ssa_const_int(p, t_int, offset));
+ return ssa_emit_conv(p, ptr, result_type);
+ } else if (is_type_tuple(t)) {
+ GB_ASSERT(t->Tuple.variable_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+ result_type = make_type_pointer(a, t->Tuple.variables[index]->type);
+ } else if (is_type_slice(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->Slice.elem)); break;
+ case 1: result_type = make_type_pointer(a, t_int); break;
+ case 2: result_type = make_type_pointer(a, t_int); break;
+ }
+ } else if (is_type_string(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, t_u8_ptr); break;
+ case 1: result_type = make_type_pointer(a, t_int); break;
+ }
+ } else if (is_type_any(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, t_type_info_ptr); break;
+ case 1: result_type = make_type_pointer(a, t_rawptr); break;
+ }
+ } else if (is_type_dynamic_array(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, make_type_pointer(a, t->DynamicArray.elem)); break;
+ case 1: result_type = t_int_ptr; break;
+ case 2: result_type = t_int_ptr; break;
+ case 3: result_type = t_allocator_ptr; break;
+ }
+ } else if (is_type_dynamic_map(t)) {
+ Type *gst = t->Map.generated_struct_type;
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, gst->Record.fields[0]->type); break;
+ case 1: result_type = make_type_pointer(a, gst->Record.fields[1]->type); break;
+ }
+ }else {
+ GB_PANIC("TODO(bill): ssa_emit_ptr_index type: %s, %d", type_to_string(s->type), index);
+ }
+
+ GB_ASSERT(result_type != NULL);
+
+ return ssa_new_value1i(p, ssaOp_PtrIndex, result_type, index, s);
+}
+ssaValue *ssa_emit_value_index(ssaProc *p, ssaValue *s, i64 index) {
+ if (s->op == ssaOp_Load) {
+ if (!can_ssa_type(s->type)) {
+ ssaValue *e = ssa_emit_ptr_index(p, s->args.e[0], index);
+ return ssa_emit_load(p, e);
+ }
+ }
+ GB_ASSERT(can_ssa_type(s->type));
+
+ gbAllocator a = p->allocator;
+ Type *t = base_type(s->type);
+ Type *result_type = NULL;
+
+ if (is_type_struct(t)) {
+ GB_ASSERT(t->Record.field_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
+ result_type = t->Record.fields[index]->type;
+ } else if (is_type_union(t)) {
+ type_set_offsets(a, t);
+ GB_ASSERT(t->Record.field_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Record.field_count-1));
+ Type *ptr_type = make_type_pointer(a, t->Record.fields[index]->type);
+ i64 offset = t->Record.offsets[index];
+ ssaValue *ptr = ssa_address_from_load_or_generate_local(p, s);
+ ptr = ssa_emit_conv(p, s, t_u8_ptr);
+ ptr = ssa_new_value2(p, ssaOp_PtrOffset, ptr->type, ptr, ssa_const_int(p, t_int, offset));
+ ptr = ssa_emit_conv(p, ptr, ptr_type);
+ return ssa_emit_load(p, ptr);
+ } else if (is_type_tuple(t)) {
+ GB_ASSERT(t->Tuple.variable_count > 0);
+ GB_ASSERT(gb_is_between(index, 0, t->Tuple.variable_count-1));
+ result_type = t->Tuple.variables[index]->type;
+ } else if (is_type_slice(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, t->Slice.elem); break;
+ case 1: result_type = t_int; break;
+ case 2: result_type = t_int; break;
+ }
+ } else if (is_type_string(t)) {
+ switch (index) {
+ case 0: result_type = t_u8_ptr; break;
+ case 1: result_type = t_int; break;
+ }
+ } else if (is_type_any(t)) {
+ switch (index) {
+ case 0: result_type = t_type_info_ptr; break;
+ case 1: result_type = t_rawptr; break;
+ }
+ } else if (is_type_dynamic_array(t)) {
+ switch (index) {
+ case 0: result_type = make_type_pointer(a, t->DynamicArray.elem); break;
+ case 1: result_type = t_int; break;
+ case 2: result_type = t_int; break;
+ case 3: result_type = t_allocator; break;
+ }
+ } else if (is_type_dynamic_map(t)) {
+ Type *gst = t->Map.generated_struct_type;
+ switch (index) {
+ case 0: result_type = gst->Record.fields[0]->type; break;
+ case 1: result_type = gst->Record.fields[1]->type; break;
+ }
+ } else {
+ GB_PANIC("TODO(bill): struct_ev type: %s, %d", type_to_string(s->type), index);
+ }
+
+ GB_ASSERT(result_type != NULL);
+
+ return ssa_new_value1i(p, ssaOp_ValueIndex, result_type, index, s);
+}
+
+
+ssaValue *ssa_emit_deep_field_ptr_index(ssaProc *p, ssaValue *e, Selection sel) {
+ GB_ASSERT(sel.index.count > 0);
+ Type *type = type_deref(e->type);
+
+ for_array(i, sel.index) {
+ i32 index = cast(i32)sel.index.e[i];
+ if (is_type_pointer(type)) {
+ type = type_deref(type);
+ e = ssa_emit_load(p, e);
+ }
+ type = base_type(type);
+
+
+ if (is_type_raw_union(type)) {
+ type = type->Record.fields[index]->type;
+ e = ssa_emit_conv(p, e, make_type_pointer(p->allocator, type));
+ } else if (type->kind == Type_Record) {
+ type = type->Record.fields[index]->type;
+ e = ssa_emit_ptr_index(p, e, index);
+ } else if (type->kind == Type_Tuple) {
+ type = type->Tuple.variables[index]->type;
+ e = ssa_emit_ptr_index(p, e, index);
+ }else if (type->kind == Type_Basic) {
+ switch (type->Basic.kind) {
+ case Basic_any: {
+ if (index == 0) {
+ type = t_type_info_ptr;
+ } else if (index == 1) {
+ type = t_rawptr;
+ }
+ e = ssa_emit_ptr_index(p, e, index);
+ } break;
+
+ case Basic_string:
+ e = ssa_emit_ptr_index(p, e, index);
+ break;
+
+ default:
+ GB_PANIC("un-gep-able type");
+ break;
+ }
+ } else if (type->kind == Type_Slice) {
+ e = ssa_emit_ptr_index(p, e, index);
+ } else if (type->kind == Type_DynamicArray) {
+ e = ssa_emit_ptr_index(p, e, index);
+ } else if (type->kind == Type_Vector) {
+ e = ssa_emit_array_index(p, e, ssa_const_int(p, t_int, index));
+ } else if (type->kind == Type_Array) {
+ e = ssa_emit_array_index(p, e, ssa_const_int(p, t_int, index));
+ } else if (type->kind == Type_Map) {
+ e = ssa_emit_ptr_index(p, e, 1);
+ switch (index) {
+ case 0: e = ssa_emit_ptr_index(p, e, 1); break; // count
+ case 1: e = ssa_emit_ptr_index(p, e, 2); break; // capacity
+ case 2: e = ssa_emit_ptr_index(p, e, 3); break; // allocator
+ }
+ } else {
+ GB_PANIC("un-gep-able type");
+ }
+ }
+
+ return e;
+}
+
+ssaValue *ssa_emit_deep_field_value_index(ssaProc *p, ssaValue *e, Selection sel) {
+ GB_ASSERT(sel.index.count > 0);
+ Type *type = e->type;
+ if (e->op == ssaOp_Load) {
+ if (!can_ssa_type(e->type)) {
+ ssaValue *ptr = ssa_emit_deep_field_ptr_index(p, e->args.e[0], sel);
+ return ssa_emit_load(p, ptr);
+ }
+ }
+ GB_ASSERT(can_ssa_type(e->type));
+
+ for_array(i, sel.index) {
+ i32 index = cast(i32)sel.index.e[i];
+ if (is_type_pointer(type)) {
+ e = ssa_emit_load(p, e);
+ }
+ type = base_type(type);
+
+
+ if (is_type_raw_union(type)) {
+ GB_PANIC("TODO(bill): IS THIS EVEN CORRECT?");
+ type = type->Record.fields[index]->type;
+ e = ssa_emit_conv(p, e, type);
+ } else if (type->kind == Type_Map) {
+ e = ssa_emit_value_index(p, e, 1);
+ switch (index) {
+ case 0: e = ssa_emit_value_index(p, e, 1); break; // count
+ case 1: e = ssa_emit_value_index(p, e, 2); break; // capacity
+ case 2: e = ssa_emit_value_index(p, e, 3); break; // allocator
+ }
+ } else {
+ e = ssa_emit_value_index(p, e, index);
+ }
+ }
+
+ return e;
+}
+
+
+
+
+
+ssaAddr ssa_build_addr(ssaProc *p, AstNode *expr) {
+ switch (expr->kind) {
+ case_ast_node(i, Ident, expr);
+ if (ssa_is_blank_ident(expr)) {
+ ssaAddr val = {0};
+ return val;
+ }
+ Entity *e = entity_of_ident(p->module->info, expr);
+ return ssa_build_addr_from_entity(p, e, expr);
+ case_end;
+
+ case_ast_node(pe, ParenExpr, expr);
+ return ssa_build_addr(p, unparen_expr(expr));
+ case_end;
+
+ case_ast_node(se, SelectorExpr, expr);
+ ssa_emit_comment(p, str_lit("SelectorExpr"));
+ AstNode *sel = unparen_expr(se->selector);
+ if (sel->kind == AstNode_Ident) {
+ String selector = sel->Ident.string;
+ TypeAndValue *tav = type_and_value_of_expression(p->module->info, se->expr);
+
+ if (tav == NULL) {
+ // NOTE(bill): Imports
+ Entity *imp = entity_of_ident(p->module->info, se->expr);
+ if (imp != NULL) {
+ GB_ASSERT(imp->kind == Entity_ImportName);
+ }
+ return ssa_build_addr(p, se->selector);
+ }
+
+
+ Type *type = base_type(tav->type);
+ if (tav->mode == Addressing_Type) { // Addressing_Type
+ GB_PANIC("TODO: SelectorExpr Addressing_Type");
+ // Selection sel = lookup_field(p->allocator, type, selector, true);
+ // Entity *e = sel.entity;
+ // GB_ASSERT(e->kind == Entity_Variable);
+ // GB_ASSERT(e->flags & EntityFlag_TypeField);
+ // String name = e->token.string;
+ // if (str_eq(name, str_lit("names"))) {
+ // ssaValue *ti_ptr = ir_type_info(p, type);
+
+ // ssaValue *names_ptr = NULL;
+
+ // if (is_type_enum(type)) {
+ // ssaValue *enum_info = ssa_emit_conv(p, ti_ptr, t_type_info_enum_ptr);
+ // names_ptr = ssa_emit_ptr_index(p, enum_info, 1);
+ // } else if (type->kind == Type_Record) {
+ // ssaValue *record_info = ssa_emit_conv(p, ti_ptr, t_type_info_record_ptr);
+ // names_ptr = ssa_emit_ptr_index(p, record_info, 1);
+ // }
+ // return ssa_addr(names_ptr);
+ // } else {
+ // GB_PANIC("Unhandled TypeField %.*s", LIT(name));
+ // }
+ GB_PANIC("Unreachable");
+ }
+
+ Selection sel = lookup_field(p->allocator, type, selector, false);
+ GB_ASSERT(sel.entity != NULL);
+
+ ssaValue *a = ssa_build_addr(p, se->expr).addr;
+ a = ssa_emit_deep_field_ptr_index(p, a, sel);
+ return ssa_addr(a);
+ } else {
+ Type *type = base_type(type_of_expr(p->module->info, se->expr));
+ GB_ASSERT(is_type_integer(type));
+ ExactValue val = type_and_value_of_expression(p->module->info, sel)->value;
+ i64 index = val.value_integer;
+
+ Selection sel = lookup_field_from_index(p->allocator, type, index);
+ GB_ASSERT(sel.entity != NULL);
+
+ ssaValue *a = ssa_build_addr(p, se->expr).addr;
+ a = ssa_emit_deep_field_ptr_index(p, a, sel);
+ return ssa_addr(a);
+ }
+ case_end;
+ }
+
+ GB_PANIC("Cannot get entity's address");
+ return ssa_addr(NULL);
+}
+
+
+Type *ssa_proper_type(Type *t) {
+ t = default_type(core_type(t));
+
+ if (t->kind == Type_Basic) {
+ switch (t->Basic.kind) {
+ case Basic_int:
+ if (build_context.word_size == 8) {
+ return t_i64;
+ }
+ return t_i32;
+ case Basic_uint:
+ if (build_context.word_size == 8) {
+ return t_u64;
+ }
+ return t_u32;
+ }
+ }
+
+ return t;
+}
+
+ssaOp ssa_determine_op(TokenKind op, Type *t) {
+ t = ssa_proper_type(t);
+ if (t->kind == Type_Basic) {
+ switch (t->Basic.kind) {
+ case Basic_bool:
+ switch (op) {
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ }
+ break;
+ case Basic_i8:
+ switch (op) {
+ case Token_Add: return ssaOp_Add8;
+ case Token_Sub: return ssaOp_Sub8;
+ case Token_Mul: return ssaOp_Mul8;
+ case Token_Quo: return ssaOp_Div8;
+ case Token_Mod: return ssaOp_Mod8;
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ case Token_Lt: return ssaOp_Lt8;
+ case Token_LtEq: return ssaOp_Le8;
+ case Token_Gt: return ssaOp_Gt8;
+ case Token_GtEq: return ssaOp_Ge8;
+ case Token_CmpEq: return ssaOp_Eq8;
+ case Token_NotEq: return ssaOp_Ne8;
+ }
+ break;
+ case Basic_u8:
+ switch (op) {
+ case Token_Add: return ssaOp_Add8;
+ case Token_Sub: return ssaOp_Sub8;
+ case Token_Mul: return ssaOp_Mul8;
+ case Token_Quo: return ssaOp_Div8U;
+ case Token_Mod: return ssaOp_Mod8U;
+ case Token_And: return ssaOp_And8;
+ case Token_Or: return ssaOp_Or8;
+ case Token_Xor: return ssaOp_Xor8;
+ case Token_AndNot: return ssaOp_AndNot8;
+ case Token_Lt: return ssaOp_Lt8;
+ case Token_LtEq: return ssaOp_Le8;
+ case Token_Gt: return ssaOp_Gt8;
+ case Token_GtEq: return ssaOp_Ge8;
+ case Token_CmpEq: return ssaOp_Eq8;
+ case Token_NotEq: return ssaOp_Ne8;
+ }
+ break;
+ case Basic_i16:
+ switch (op) {
+ case Token_Add: return ssaOp_Add16;
+ case Token_Sub: return ssaOp_Sub16;
+ case Token_Mul: return ssaOp_Mul16;
+ case Token_Quo: return ssaOp_Div16;
+ case Token_Mod: return ssaOp_Mod16;
+ case Token_And: return ssaOp_And16;
+ case Token_Or: return ssaOp_Or16;
+ case Token_Xor: return ssaOp_Xor16;
+ case Token_AndNot: return ssaOp_AndNot16;
+ case Token_Lt: return ssaOp_Lt16;
+ case Token_LtEq: return ssaOp_Le16;
+ case Token_Gt: return ssaOp_Gt16;
+ case Token_GtEq: return ssaOp_Ge16;
+ case Token_CmpEq: return ssaOp_Eq16;
+ case Token_NotEq: return ssaOp_Ne16;
+ }
+ break;
+ case Basic_u16:
+ switch (op) {
+ case Token_Add: return ssaOp_Add16;
+ case Token_Sub: return ssaOp_Sub16;
+ case Token_Mul: return ssaOp_Mul16;
+ case Token_Quo: return ssaOp_Div16U;
+ case Token_Mod: return ssaOp_Mod16U;
+ case Token_And: return ssaOp_And16;
+ case Token_Or: return ssaOp_Or16;
+ case Token_Xor: return ssaOp_Xor16;
+ case Token_AndNot: return ssaOp_AndNot16;
+ case Token_Lt: return ssaOp_Lt16;
+ case Token_LtEq: return ssaOp_Le16;
+ case Token_Gt: return ssaOp_Gt16;
+ case Token_GtEq: return ssaOp_Ge16;
+ case Token_CmpEq: return ssaOp_Eq16;
+ case Token_NotEq: return ssaOp_Ne16;
+ }
+ break;
+ case Basic_i32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32;
+ case Token_Sub: return ssaOp_Sub32;
+ case Token_Mul: return ssaOp_Mul32;
+ case Token_Quo: return ssaOp_Div32;
+ case Token_Mod: return ssaOp_Mod32;
+ case Token_And: return ssaOp_And32;
+ case Token_Or: return ssaOp_Or32;
+ case Token_Xor: return ssaOp_Xor32;
+ case Token_AndNot: return ssaOp_AndNot32;
+ case Token_Lt: return ssaOp_Lt32;
+ case Token_LtEq: return ssaOp_Le32;
+ case Token_Gt: return ssaOp_Gt32;
+ case Token_GtEq: return ssaOp_Ge32;
+ case Token_CmpEq: return ssaOp_Eq32;
+ case Token_NotEq: return ssaOp_Ne32;
+ }
+ break;
+ case Basic_u32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32;
+ case Token_Sub: return ssaOp_Sub32;
+ case Token_Mul: return ssaOp_Mul32;
+ case Token_Quo: return ssaOp_Div32U;
+ case Token_Mod: return ssaOp_Mod32U;
+ case Token_And: return ssaOp_And32;
+ case Token_Or: return ssaOp_Or32;
+ case Token_Xor: return ssaOp_Xor32;
+ case Token_AndNot: return ssaOp_AndNot32;
+ case Token_Lt: return ssaOp_Lt32;
+ case Token_LtEq: return ssaOp_Le32;
+ case Token_Gt: return ssaOp_Gt32;
+ case Token_GtEq: return ssaOp_Ge32;
+ case Token_CmpEq: return ssaOp_Eq32;
+ case Token_NotEq: return ssaOp_Ne32;
+ }
+ break;
+ case Basic_i64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64;
+ case Token_Sub: return ssaOp_Sub64;
+ case Token_Mul: return ssaOp_Mul64;
+ case Token_Quo: return ssaOp_Div64;
+ case Token_Mod: return ssaOp_Mod64;
+ case Token_And: return ssaOp_And64;
+ case Token_Or: return ssaOp_Or64;
+ case Token_Xor: return ssaOp_Xor64;
+ case Token_AndNot: return ssaOp_AndNot64;
+ case Token_Lt: return ssaOp_Lt64;
+ case Token_LtEq: return ssaOp_Le64;
+ case Token_Gt: return ssaOp_Gt64;
+ case Token_GtEq: return ssaOp_Ge64;
+ case Token_CmpEq: return ssaOp_Eq64;
+ case Token_NotEq: return ssaOp_Ne64;
+ }
+ break;
+ case Basic_u64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64;
+ case Token_Sub: return ssaOp_Sub64;
+ case Token_Mul: return ssaOp_Mul64;
+ case Token_Quo: return ssaOp_Div64U;
+ case Token_Mod: return ssaOp_Mod64U;
+ case Token_And: return ssaOp_And64;
+ case Token_Or: return ssaOp_Or64;
+ case Token_Xor: return ssaOp_Xor64;
+ case Token_AndNot: return ssaOp_AndNot64;
+ case Token_Lt: return ssaOp_Lt64;
+ case Token_LtEq: return ssaOp_Le64;
+ case Token_Gt: return ssaOp_Gt64;
+ case Token_GtEq: return ssaOp_Ge64;
+ case Token_CmpEq: return ssaOp_Eq64;
+ case Token_NotEq: return ssaOp_Ne64;
+ }
+ break;
+ case Basic_f32:
+ switch (op) {
+ case Token_Add: return ssaOp_Add32F;
+ case Token_Sub: return ssaOp_Sub32F;
+ case Token_Mul: return ssaOp_Mul32F;
+ case Token_Quo: return ssaOp_Div32F;
+ case Token_Lt: return ssaOp_Lt32F;
+ case Token_LtEq: return ssaOp_Le32F;
+ case Token_Gt: return ssaOp_Gt32F;
+ case Token_GtEq: return ssaOp_Ge32F;
+ case Token_CmpEq: return ssaOp_Eq32F;
+ case Token_NotEq: return ssaOp_Ne32F;
+ }
+ break;
+ case Basic_f64:
+ switch (op) {
+ case Token_Add: return ssaOp_Add64F;
+ case Token_Sub: return ssaOp_Sub64F;
+ case Token_Mul: return ssaOp_Mul64F;
+ case Token_Quo: return ssaOp_Div64F;
+ case Token_Lt: return ssaOp_Lt64F;
+ case Token_LtEq: return ssaOp_Le64F;
+ case Token_Gt: return ssaOp_Gt64F;
+ case Token_GtEq: return ssaOp_Ge64F;
+ case Token_CmpEq: return ssaOp_Eq64F;
+ case Token_NotEq: return ssaOp_Ne64F;
+ }
+ break;
+ }
+ }
+
+ GB_PANIC("Invalid Op for type");
+ return ssaOp_Invalid;
+}
+
+ssaValue *ssa_emit_comp(ssaProc *p, TokenKind op, ssaValue *x, ssaValue *y) {
+ GB_ASSERT(x != NULL && y != NULL);
+ Type *a = core_type(x->type);
+ Type *b = core_type(y->type);
+ if (are_types_identical(a, b)) {
+ // NOTE(bill): No need for a conversion
+ } else if (ssa_is_op_const(x->op)) {
+ x = ssa_emit_conv(p, x, y->type);
+ } else if (ssa_is_op_const(y->op)) {
+ y = ssa_emit_conv(p, y, x->type);
+ }
+
+ Type *result = t_bool;
+ if (is_type_vector(a)) {
+ result = make_type_vector(p->allocator, t_bool, a->Vector.count);
+ }
+
+ if (is_type_vector(a)) {
+ ssa_emit_comment(p, str_lit("vector.comp.begin"));
+ Type *tl = base_type(a);
+ ssaValue *lhs = ssa_address_from_load_or_generate_local(p, x);
+ ssaValue *rhs = ssa_address_from_load_or_generate_local(p, y);
+
+ GB_ASSERT(is_type_vector(result));
+ Type *elem_type = base_type(result)->Vector.elem;
+
+ ssaAddr addr = ssa_add_local_generated(p, result);
+ for (i32 i = 0; i < tl->Vector.count; i++) {
+ ssaValue *index = ssa_const_int(p, t_int, i);
+ ssaValue *x = ssa_emit_load(p, ssa_emit_array_index(p, lhs, index));
+ ssaValue *y = ssa_emit_load(p, ssa_emit_array_index(p, rhs, index));
+ ssaValue *z = ssa_emit_comp(p, op, x, y);
+ ssa_emit_store(p, ssa_emit_array_index(p, addr.addr, index), z);
+ }
+
+ ssa_emit_comment(p, str_lit("vector.comp.end"));
+ return ssa_addr_load(p, addr);
+ }
+
+ return ssa_new_value2(p, ssa_determine_op(op, x->type), x->type, x, y);
+}
+
+
+
+ssaValue *ssa_build_cond(ssaProc *p, AstNode *cond, ssaBlock *yes, ssaBlock *no) {
+ switch (cond->kind) {
+ case_ast_node(pe, ParenExpr, cond);
+ return ssa_build_cond(p, pe->expr, yes, no);
+ case_end;
+
+ case_ast_node(ue, UnaryExpr, cond);
+ if (ue->op.kind == Token_Not) {
+ return ssa_build_cond(p, ue->expr, no, yes);
+ }
+ case_end;
+
+ case_ast_node(be, BinaryExpr, cond);
+ if (be->op.kind == Token_CmpAnd) {
+ ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmd.and");
+ ssa_build_cond(p, be->left, block, no);
+ ssa_start_block(p, block);
+ return ssa_build_cond(p, be->right, yes, no);
+ } else if (be->op.kind == Token_CmpOr) {
+ ssaBlock *block = ssa_new_block(p, ssaBlock_Plain, "cmp.or");
+ ssa_build_cond(p, be->left, yes, block);
+ ssa_start_block(p, block);
+ return ssa_build_cond(p, be->right, yes, no);
+ }
+ case_end;
+ }
+
+ ssaValue *c = ssa_build_expr(p, cond);
+ ssaBlock *b = ssa_end_block(p);
+ b->kind = ssaBlock_If;
+ ssa_set_control(b, c);
+ ssa_add_edge_to(b, yes);
+ ssa_add_edge_to(b, no);
+ return c;
+}
+
+ssaValue *ssa_emit_logical_binary_expr(ssaProc *p, AstNode *expr) {
+ ast_node(be, BinaryExpr, expr);
+
+ ssaBlock *rhs = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.rhs");
+ ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "logical.cmp.done");
+
+ GB_ASSERT(p->curr_block != NULL);
+
+ Type *type = default_type(type_of_expr(p->module->info, expr));
+
+ bool short_circuit_value = false;
+ if (be->op.kind == Token_CmpAnd) {
+ ssa_build_cond(p, be->left, rhs, done);
+ short_circuit_value = false;
+ } else if (be->op.kind == Token_CmpOr) {
+ ssa_build_cond(p, be->left, done, rhs);
+ short_circuit_value = true;
+ }
+ if (rhs->preds.count == 0) {
+ ssa_start_block(p, done);
+ return ssa_const_bool(p, type, short_circuit_value);
+ }
+
+ if (done->preds.count == 0) {
+ ssa_start_block(p, rhs);
+ return ssa_build_expr(p, be->right);
+ }
+
+ ssa_start_block(p, rhs);
+ ssaValue *short_circuit = ssa_const_bool(p, type, short_circuit_value);
+ ssaValueArgs edges = {0};
+ ssa_init_value_args(&edges, p->allocator);
+ for_array(i, done->preds) {
+ ssa_add_arg(&edges, short_circuit);
+ }
+
+ ssa_add_arg(&edges, ssa_build_expr(p, be->right));
+ ssa_emit_jump(p, done);
+ ssa_start_block(p, done);
+
+ ssaValue *phi = ssa_new_value0(p, ssaOp_Phi, type);
+ phi->args = edges;
+ return phi;
+}
+
+ssaValue *ssa_build_expr(ssaProc *p, AstNode *expr) {
+ expr = unparen_expr(expr);
+
+ TypeAndValue *tv = map_tav_get(&p->module->info->types, hash_pointer(expr));
+ GB_ASSERT_NOT_NULL(tv);
+
+ if (tv->value.kind != ExactValue_Invalid) {
+ Type *t = core_type(tv->type);
+ if (is_type_boolean(t)) {
+ return ssa_const_bool(p, tv->type, tv->value.value_bool);
+ } else if (is_type_string(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_String);
+ return ssa_const_string(p, tv->type, tv->value.value_string);
+ } else if(is_type_slice(t)) {
+ return ssa_const_slice(p, tv->type, tv->value);
+ } else if (is_type_integer(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_Integer);
+
+ i64 s = 8*type_size_of(p->allocator, t);
+ switch (s) {
+ case 8: return ssa_const_i8 (p, tv->type, tv->value.value_integer);
+ case 16: return ssa_const_i16(p, tv->type, tv->value.value_integer);
+ case 32: return ssa_const_i32(p, tv->type, tv->value.value_integer);
+ case 64: return ssa_const_i64(p, tv->type, tv->value.value_integer);
+ default: GB_PANIC("Unknown integer size");
+ }
+ } else if (is_type_float(t)) {
+ GB_ASSERT(tv->value.kind == ExactValue_Float);
+ i64 s = 8*type_size_of(p->allocator, t);
+ switch (s) {
+ case 32: return ssa_const_f32(p, tv->type, tv->value.value_float);
+ case 64: return ssa_const_f64(p, tv->type, tv->value.value_float);
+ default: GB_PANIC("Unknown float size");
+ }
+ }
+ // IMPORTANT TODO(bill): Do constant record/array literals correctly
+ return ssa_const_nil(p, tv->type);
+ }
+
+ if (tv->mode == Addressing_Variable) {
+ return ssa_addr_load(p, ssa_build_addr(p, expr));
+ }
+
+
+ switch (expr->kind) {
+ case_ast_node(bl, BasicLit, expr);
+ GB_PANIC("Non-constant basic literal");
+ case_end;
+
+ case_ast_node(bd, BasicDirective, expr);
+ TokenPos pos = bd->token.pos;
+ GB_PANIC("Non-constant basic literal %.*s(%td:%td) - %.*s", LIT(pos.file), pos.line, pos.column, LIT(bd->name));
+ case_end;
+
+ case_ast_node(i, Ident, expr);
+ Entity *e = *map_entity_get(&p->module->info->uses, hash_pointer(expr));
+ if (e->kind == Entity_Builtin) {
+ Token token = ast_node_token(expr);
+ GB_PANIC("TODO(bill): ssa_build_expr Entity_Builtin `%.*s`\n"
+ "\t at %.*s(%td:%td)", LIT(builtin_procs[e->Builtin.id].name),
+ LIT(token.pos.file), token.pos.line, token.pos.column);
+ return NULL;
+ } else if (e->kind == Entity_Nil) {
+ GB_PANIC("TODO(bill): nil");
+ return NULL;
+ }
+
+ ssaValue **found = map_ssa_value_get(&p->module->values, hash_pointer(e));
+ if (found) {
+ ssaValue *v = *found;
+ if (v->op == ssaOp_Proc) {
+ return v;
+ }
+
+ ssaAddr addr = ssa_build_addr(p, expr);
+ return ssa_addr_load(p, addr);
+ }
+ case_end;
+
+ case_ast_node(ue, UnaryExpr, expr);
+ switch (ue->op.kind) {
+ case Token_Pointer: {
+ return ssa_build_addr(p, ue->expr).addr;
+ } break;
+
+ case Token_Add:
+ return ssa_build_expr(p, ue->expr);
+
+ case Token_Not: // Boolean not
+ return ssa_new_value1(p, ssaOp_NotB, tv->type, ssa_build_expr(p, ue->expr));
+ case Token_Xor: { // Bitwise not
+ ssaValue *x = ssa_build_expr(p, ue->expr);
+ isize bits = 8*type_size_of(p->allocator, x->type);
+ switch (bits) {
+ case 8: return ssa_new_value1(p, ssaOp_Not8, tv->type, x);
+ case 16: return ssa_new_value1(p, ssaOp_Not16, tv->type, x);
+ case 32: return ssa_new_value1(p, ssaOp_Not32, tv->type, x);
+ case 64: return ssa_new_value1(p, ssaOp_Not64, tv->type, x);
+ }
+ GB_PANIC("unknown integer size");
+ } break;
+
+ case Token_Sub: { // 0-x
+ ssaValue *x = ssa_build_expr(p, ue->expr);
+ isize bits = 8*type_size_of(p->allocator, x->type);
+ if (is_type_integer(x->type)) {
+ switch (bits) {
+ case 8: return ssa_new_value1(p, ssaOp_Neg8, tv->type, x);
+ case 16: return ssa_new_value1(p, ssaOp_Neg16, tv->type, x);
+ case 32: return ssa_new_value1(p, ssaOp_Neg32, tv->type, x);
+ case 64: return ssa_new_value1(p, ssaOp_Neg64, tv->type, x);
+ }
+ } else if (is_type_float(x->type)) {
+ switch (bits) {
+ case 32: return ssa_new_value1(p, ssaOp_Neg32F, tv->type, x);
+ case 64: return ssa_new_value1(p, ssaOp_Neg64F, tv->type, x);
+ }
+ }
+ GB_PANIC("unknown type for -x");
+ } break;
+ }
+ case_end;
+
+ case_ast_node(be, BinaryExpr, expr);
+ Type *type = default_type(tv->type);
+
+ switch (be->op.kind) {
+ case Token_Add:
+ case Token_Sub:
+ case Token_Mul:
+ case Token_Quo:
+ case Token_Mod:
+ case Token_And:
+ case Token_Or:
+ case Token_Xor:
+ case Token_AndNot: {
+ ssaValue *x = ssa_build_expr(p, be->left);
+ ssaValue *y = ssa_build_expr(p, be->right);
+ GB_ASSERT(x != NULL && y != NULL);
+ return ssa_new_value2(p, ssa_determine_op(be->op.kind, x->type), tv->type, x, y);
+ }
+
+ case Token_Shl:
+ case Token_Shr: {
+ GB_PANIC("TODO: shifts");
+ return NULL;
+ }
+
+ case Token_CmpEq:
+ case Token_NotEq:
+ case Token_Lt:
+ case Token_LtEq:
+ case Token_Gt:
+ case Token_GtEq: {
+ ssaValue *x = ssa_build_expr(p, be->left);
+ ssaValue *y = ssa_build_expr(p, be->right);
+ return ssa_emit_comp(p, be->op.kind, x, y);
+ } break;
+
+ case Token_CmpAnd:
+ case Token_CmpOr:
+ return ssa_emit_logical_binary_expr(p, expr);
+
+ default:
+ GB_PANIC("Invalid binary expression");
+ break;
+ }
+ case_end;
+ }
+
+
+ return NULL;
+}
+
+
+
+void ssa_build_stmt_list(ssaProc *p, AstNodeArray nodes) {
+ for_array(i, nodes) {
+ ssa_build_stmt(p, nodes.e[i]);
+ }
+}
+
+
+
+void ssa_build_when_stmt(ssaProc *p, AstNodeWhenStmt *ws) {
+ ssaValue *cond = ssa_build_expr(p, ws->cond);
+ GB_ASSERT(is_type_boolean(cond->type));
+
+ GB_ASSERT(cond->exact_value.kind == ExactValue_Bool);
+ if (cond->exact_value.value_bool) {
+ ssa_build_stmt_list(p, ws->body->BlockStmt.stmts);
+ } else if (ws->else_stmt) {
+ switch (ws->else_stmt->kind) {
+ case AstNode_BlockStmt:
+ ssa_build_stmt_list(p, ws->else_stmt->BlockStmt.stmts);
+ break;
+ case AstNode_WhenStmt:
+ ssa_build_when_stmt(p, &ws->else_stmt->WhenStmt);
+ break;
+ default:
+ GB_PANIC("Invalid `else` statement in `when` statement");
+ break;
+ }
+ }
+}
+
+void ssa_build_assign_op(ssaProc *p, ssaAddr lhs, ssaValue *value, TokenKind op) {
+ // ssaValue *old_value = ssa_addr_load(p, lhs);
+ // Type *type = old_value->type;
+
+ // ssaValue *change = value;
+ // if (is_type_pointer(type) && is_type_integer(value->type)) {
+ // change = ssa_emit_conv(p, value, default_type(value->type));
+ // } else {
+ // change = ssa_emit_conv(p, value, type);
+ // }
+ // ssaValue *new_value = ssa_emit_arith(p, op, old_value, change, type);
+ // ssa_addr_store(p, lhs, new_value);
+}
+
+
+void ssa_build_stmt(ssaProc *p, AstNode *node) {
+ if (p->curr_block == NULL) {
+ ssaBlock *dead_block = ssa_new_block(p, ssaBlock_Plain, "");
+ ssa_start_block(p, dead_block);
+ }
+
+ switch (node->kind) {
+ case_ast_node(es, EmptyStmt, node);
+ case_end;
+
+ case_ast_node(bs, BlockStmt, node);
+ ssa_build_stmt_list(p, bs->stmts);
+ case_end;
+
+ case_ast_node(us, UsingStmt, node);
+ for_array(i, us->list) {
+ AstNode *decl = unparen_expr(us->list.e[i]);
+ if (decl->kind == AstNode_ValueDecl) {
+ ssa_build_stmt(p, decl);
+ }
+ }
+ case_end;
+
+ case_ast_node(ws, WhenStmt, node);
+ ssa_build_when_stmt(p, ws);
+ case_end;
+
+ case_ast_node(s, IncDecStmt, node);
+ TokenKind op = Token_Add;
+ if (s->op.kind == Token_Dec) {
+ op = Token_Sub;
+ }
+ ssaAddr addr = ssa_build_addr(p, s->expr);
+ Type *t = ssa_addr_type(addr);
+ ssa_build_assign_op(p, addr, ssa_const_int(p, t, 1), op);
+ case_end;
+
+ case_ast_node(vd, ValueDecl, node);
+ if (vd->is_var) {
+ ssaModule *m = p->module;
+ gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
+ if (vd->values.count == 0) {
+ for_array(i, vd->names) {
+ AstNode *name = vd->names.e[i];
+ if (!ssa_is_blank_ident(name)) {
+ ssa_add_local_for_ident(p, name);
+ }
+ }
+ } else {
+ Array(ssaAddr) lvals = {0};
+ ssaValueArray inits = {0};
+ array_init_reserve(&lvals, m->tmp_allocator, vd->names.count);
+ array_init_reserve(&inits, m->tmp_allocator, vd->names.count);
+
+ for_array(i, vd->names) {
+ AstNode *name = vd->names.e[i];
+ ssaAddr lval = ssa_addr(NULL);
+ if (!ssa_is_blank_ident(name)) {
+ lval = ssa_add_local_for_ident(p, name);
+ }
+
+ array_add(&lvals, lval);
+ }
+
+ for_array(i, vd->values) {
+ ssaValue *init = ssa_build_expr(p, vd->values.e[i]);
+ if (init == NULL) { // TODO(bill): remove this
+ continue;
+ }
+ Type *t = type_deref(init->type);
+ if (init->op == ssaOp_Addr && t->kind == Type_Tuple) {
+ for (isize i = 0; i < t->Tuple.variable_count; i++) {
+ Entity *e = t->Tuple.variables[i];
+ ssaValue *v = ssa_emit_ptr_index(p, init, i);
+ array_add(&inits, v);
+ }
+ } else {
+ array_add(&inits, init);
+ }
+ }
+
+ for_array(i, inits) {
+ ssa_addr_store(p, lvals.e[i], inits.e[i]);
+ }
+ }
+
+ gb_temp_arena_memory_end(tmp);
+ }
+ case_end;
+
+ case_ast_node(as, AssignStmt, node);
+ ssa_emit_comment(p, str_lit("AssignStmt"));
+
+ ssaModule *m = p->module;
+ gbTempArenaMemory tmp = gb_temp_arena_memory_begin(&m->tmp_arena);
+
+ switch (as->op.kind) {
+ case Token_Eq: {
+ Array(ssaAddr) lvals = {0};
+ array_init(&lvals, m->tmp_allocator);
+
+ for_array(i, as->lhs) {
+ AstNode *lhs = as->lhs.e[i];
+ ssaAddr lval = {0};
+ if (!ssa_is_blank_ident(lhs)) {
+ lval = ssa_build_addr(p, lhs);
+ }
+ array_add(&lvals, lval);
+ }
+
+ if (as->lhs.count == as->rhs.count) {
+ if (as->lhs.count == 1) {
+ AstNode *rhs = as->rhs.e[0];
+ ssaValue *init = ssa_build_expr(p, rhs);
+ ssa_addr_store(p, lvals.e[0], init);
+ } else {
+ ssaValueArray inits;
+ array_init_reserve(&inits, m->tmp_allocator, lvals.count);
+
+ for_array(i, as->rhs) {
+ ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
+ array_add(&inits, init);
+ }
+
+ for_array(i, inits) {
+ ssa_addr_store(p, lvals.e[i], inits.e[i]);
+ }
+ }
+ } else {
+ ssaValueArray inits;
+ array_init_reserve(&inits, m->tmp_allocator, lvals.count);
+
+ for_array(i, as->rhs) {
+ ssaValue *init = ssa_build_expr(p, as->rhs.e[i]);
+ Type *t = type_deref(init->type);
+ // TODO(bill): refactor for code reuse as this is repeated a bit
+ if (init->op == ssaOp_Addr && t->kind == Type_Tuple) {
+ for (isize i = 0; i < t->Tuple.variable_count; i++) {
+ Entity *e = t->Tuple.variables[i];
+ ssaValue *v = ssa_emit_ptr_index(p, init, i);
+ array_add(&inits, v);
+ }
+ } else {
+ array_add(&inits, init);
+ }
+ }
+
+ for_array(i, inits) {
+ ssa_addr_store(p, lvals.e[i], inits.e[i]);
+ }
+ }
+ } break;
+
+ default: {
+ GB_PANIC("TODO(bill): assign operations");
+ // NOTE(bill): Only 1 += 1 is allowed, no tuples
+ // +=, -=, etc
+ // i32 op = cast(i32)as->op.kind;
+ // op += Token_Add - Token_AddEq; // Convert += to +
+ // ssaAddr lhs = ssa_build_addr(p, as->lhs.e[0]);
+ // ssaValue *value = ssa_build_expr(p, as->rhs.e[0]);
+ // ssa_build_assign_op(p, lhs, value, cast(TokenKind)op);
+ } break;
+ }
+
+ gb_temp_arena_memory_end(tmp);
+ case_end;
+
+ case_ast_node(es, ExprStmt, node);
+ // NOTE(bill): No need to use return value
+ ssa_build_expr(p, es->expr);
+ case_end;
+
+ case_ast_node(ds, DeferStmt, node);
+ GB_PANIC("TODO: DeferStmt");
+ case_end;
+
+ case_ast_node(rs, ReturnStmt, node);
+ GB_PANIC("TODO: ReturnStmt");
+ case_end;
+
+ case_ast_node(is, IfStmt, node);
+ ssa_emit_comment(p, str_lit("IfStmt"));
+ if (is->init != NULL) {
+ ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "if.init");
+ ssa_emit_jump(p, init);
+ ssa_start_block(p, init);
+ ssa_build_stmt(p, is->init);
+ }
+ ssaBlock *then = ssa_new_block(p, ssaBlock_Plain, "if.then");
+ ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "if.done");
+ ssaBlock *else_ = done;
+ if (is->else_stmt != NULL) {
+ else_ = ssa_new_block(p, ssaBlock_Plain, "if.else");
+ }
+ ssaBlock *b = NULL;
+
+ ssa_build_cond(p, is->cond, then, else_);
+ ssa_start_block(p, then);
+
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, is->body);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+
+ ssa_emit_jump(p, done);
+
+ if (is->else_stmt != NULL) {
+ ssa_start_block(p, else_);
+
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, is->else_stmt);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+
+ ssa_emit_jump(p, done);
+ }
+
+ ssa_start_block(p, done);
+ case_end;
+
+
+ case_ast_node(fs, ForStmt, node);
+ ssa_emit_comment(p, str_lit("ForStmt"));
+ if (fs->init != NULL) {
+ ssaBlock *init = ssa_new_block(p, ssaBlock_Plain, "for.init");
+ ssa_emit_jump(p, init);
+ ssa_start_block(p, init);
+ ssa_build_stmt(p, fs->init);
+ }
+
+ ssaBlock *body = ssa_new_block(p, ssaBlock_Plain, "for.body");
+ ssaBlock *done = ssa_new_block(p, ssaBlock_Plain, "for.done");
+ ssaBlock *loop = body;
+ if (fs->cond != NULL) {
+ loop = ssa_new_block(p, ssaBlock_Plain, "for.loop");
+ }
+ ssaBlock *post = loop;
+ if (fs->post != NULL) {
+ post = ssa_new_block(p, ssaBlock_Plain, "for.post");
+ }
+
+ ssa_emit_jump(p, loop);
+ ssa_start_block(p, loop);
+
+ if (loop != body) {
+ ssa_build_cond(p, fs->cond, body, done);
+ ssa_start_block(p, body);
+ }
+
+ ssa_push_target_list(p, done, post, NULL);
+ // ssa_open_scope(p);
+ ssa_build_stmt(p, fs->body);
+ // ssa_close_scope(p, ssaDeferExit_Default, NULL);
+ ssa_pop_target_list(p);
+
+ ssa_emit_jump(p, post);
+
+ if (fs->post != NULL) {
+ ssa_start_block(p, post);
+ ssa_build_stmt(p, fs->post);
+ ssa_emit_jump(p, post);
+ }
+
+ ssa_start_block(p, done);
+ case_end;
+
+ case_ast_node(rs, RangeStmt, node);
+ GB_PANIC("TODO: RangeStmt");
+ case_end;
+
+ case_ast_node(rs, MatchStmt, node);
+ GB_PANIC("TODO: MatchStmt");
+ case_end;
+
+ case_ast_node(rs, TypeMatchStmt, node);
+ GB_PANIC("TODO: TypeMatchStmt");
+ case_end;
+
+ case_ast_node(bs, BranchStmt, node);
+ ssaBlock *b = NULL;
+ switch (bs->token.kind) {
+ case Token_break:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->break_;
+ }
+ break;
+ case Token_continue:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->continue_;
+ }
+ break;
+ case Token_fallthrough:
+ for (ssaTargetList *t = p->target_list; t != NULL && b == NULL; t = t->prev) {
+ b = t->fallthrough_;
+ }
+ break;
+ }
+ if (b != NULL) {
+ // ssa_emit_defer_stmts(p, irDeferExit_Branch, b);
+ }
+ switch (bs->token.kind) {
+ case Token_break: ssa_emit_comment(p, str_lit("break")); break;
+ case Token_continue: ssa_emit_comment(p, str_lit("continue")); break;
+ case Token_fallthrough: ssa_emit_comment(p, str_lit("fallthrough")); break;
+ }
+ ssa_emit_jump(p, b);
+ case_end;
+
+ case_ast_node(pa, PushAllocator, node);
+ GB_PANIC("TODO: PushAllocator");
+ case_end;
+ case_ast_node(pc, PushContext, node);
+ GB_PANIC("TODO: PushContext");
+ case_end;
+ }
+}
+
+void ssa_print_value(gbFile *f, ssaValue *v) {
+ if (v == NULL) {
+ gb_fprintf(f, "nil");
+ }
+ gb_fprintf(f, "v%d", v->id);
+}
+
+void ssa_print_exact_value(gbFile *f, ssaValue *v) {
+ Type *t = default_type(v->type);
+ ExactValue ev = v->exact_value;
+ switch (ev.kind) {
+ case ExactValue_Bool:
+ if (ev.value_bool == false) {
+ gb_fprintf(f, " [false]");
+ } else {
+ gb_fprintf(f, " [true]");
+ }
+ break;
+ case ExactValue_Integer:
+ if (is_type_unsigned(t)) {
+ gb_fprintf(f, " [%llu]", ev.value_integer);
+ } else {
+ gb_fprintf(f, " [%lld]", ev.value_integer);
+ }
+ break;
+ case ExactValue_Float:
+ if (is_type_f32(t)) {
+ f32 fp = cast(f32)ev.value_float;
+ u32 x = *cast(u32 *)&fp;
+ gb_fprintf(f, " [0x%x]", x);
+ } else if (is_type_f64(t)) {
+ f64 fp = cast(f64)ev.value_float;
+ u64 x = *cast(u64 *)&fp;
+ gb_fprintf(f, " [0x%llx]", x);
+ } else {
+ GB_PANIC("unhandled integer");
+ }
+ break;
+ case ExactValue_String:
+ gb_fprintf(f, " [%.*s]", LIT(ev.value_string));
+ break;
+ case ExactValue_Pointer:
+ gb_fprintf(f, " [0x%llx]", ev.value_pointer);
+ break;
+ }
+}
+
+
+void ssa_print_reg_value(gbFile *f, ssaValue *v) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "v%d = %.*s", v->id, LIT(ssa_op_strings[v->op]));
+
+ if (v->type != NULL) {
+ gbString type_str = type_to_string(default_type(v->type));
+ gb_fprintf(f, " %s", type_str);
+ gb_string_free(type_str);
+ }
+
+ ssa_print_exact_value(f, v);
+
+ for_array(i, v->args) {
+ gb_fprintf(f, " ");
+ ssa_print_value(f, v->args.e[i]);
+ }
+
+ if (v->comment_string.len > 0) {
+ gb_fprintf(f, " ; %.*s", LIT(v->comment_string));
+ }
+
+ gb_fprintf(f, "\n");
+
+}
+
+void ssa_print_proc(gbFile *f, ssaProc *p) {
+ gbString type_str = type_to_string(p->entity->type);
+ gb_fprintf(f, "%.*s %s\n", LIT(p->name), type_str);
+ gb_string_free(type_str);
+
+ bool *printed = gb_alloc_array(heap_allocator(), bool, p->value_id+1);
+
+ for_array(i, p->blocks) {
+ ssaBlock *b = p->blocks.e[i];
+ gb_fprintf(f, " b%d:", b->id);
+ if (b->preds.count > 0) {
+ gb_fprintf(f, " <-");
+ for_array(j, b->preds) {
+ ssaBlock *pred = b->preds.e[j].block;
+ gb_fprintf(f, " b%d", pred->id);
+ }
+ }
+ gb_fprintf(f, "\n");
+
+ isize n = 0;
+ for_array(j, b->values) {
+ ssaValue *v = b->values.e[j];
+ if (v->op != ssaOp_Phi) {
+ continue;
+ }
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+
+ while (n < b->values.count) {
+ isize m = 0;
+ for_array(j, b->values) {
+ ssaValue *v = b->values.e[j];
+ if (printed[v->id]) {
+ continue;
+ }
+ bool skip = false;
+ for_array(k, v->args) {
+ ssaValue *w = v->args.e[k];
+ if (w != NULL && w->block == b && !printed[w->id]) {
+ skip = true;
+ break;
+ }
+ }
+
+ if (skip) {
+ break;
+ }
+
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+ if (m == n) {
+ gb_fprintf(f, "!!!!DepCycle!!!!\n");
+ for_array(k, b->values) {
+ ssaValue *v = b->values.e[k];
+ if (printed[v->id]) {
+ continue;
+ }
+
+ ssa_print_reg_value(f, v);
+ printed[v->id] = true;
+ n++;
+ }
+ }
+ }
+
+ if (b->kind == ssaBlock_Plain) {
+ GB_ASSERT(b->succs.count == 1);
+ ssaBlock *next = b->succs.e[0].block;
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "jump b%d", next->id);
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_If) {
+ GB_ASSERT(b->succs.count == 2);
+ ssaBlock *yes = b->succs.e[0].block;
+ ssaBlock *no = b->succs.e[1].block;
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "branch v%d, b%d, b%d", b->control->id, yes->id, no->id);
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_Exit) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "exit");
+ gb_fprintf(f, "\n");
+ } else if (b->kind == ssaBlock_Ret) {
+ gb_fprintf(f, " ");
+ gb_fprintf(f, "ret");
+ gb_fprintf(f, "\n");
+ }
+ }
+
+ gb_free(heap_allocator(), printed);
+}
+
+
+void ssa_opt_proc(ssaProc *p) {
+}
+
+void ssa_build_proc(ssaModule *m, ssaProc *p) {
+ p->module = m;
+ m->proc = p;
+
+ if (p->decl_info->proc_lit == NULL ||
+ p->decl_info->proc_lit->kind != AstNode_ProcLit) {
+ return;
+ }
+
+ ast_node(pl, ProcLit, p->decl_info->proc_lit);
+ if (pl->body == NULL) {
+ return;
+ }
+ p->entry = ssa_new_block(p, ssaBlock_Entry, "entry");
+
+ ssa_start_block(p, p->entry);
+ ssa_build_stmt(p, pl->body);
+
+ p->exit = ssa_new_block(p, ssaBlock_Exit, "exit");
+ ssa_emit_jump(p, p->exit);
+
+ ssa_opt_proc(p);
+
+ ssa_print_proc(gb_file_get_standard(gbFileStandard_Error), p);
+}
+
+
+
+bool ssa_generate(Parser *parser, CheckerInfo *info) {
+ if (global_error_collector.count != 0) {
+ return false;
+ }
+
+ ssaModule m = {0};
+ { // Init ssaModule
+ m.info = info;
+
+ isize token_count = parser->total_token_count;
+ isize arena_size = 4 * token_count * gb_max3(gb_size_of(ssaValue), gb_size_of(ssaBlock), gb_size_of(ssaProc));
+
+ gb_arena_init_from_allocator(&m.arena, heap_allocator(), arena_size);
+ gb_arena_init_from_allocator(&m.tmp_arena, heap_allocator(), arena_size);
+ m.tmp_allocator = gb_arena_allocator(&m.tmp_arena);
+ m.allocator = gb_arena_allocator(&m.arena);
+
+ map_ssa_value_init(&m.values, heap_allocator());
+ array_init(&m.registers, heap_allocator());
+ array_init(&m.procs, heap_allocator());
+ array_init(&m.procs_to_generate, heap_allocator());
+ }
+
+ isize global_variable_max_count = 0;
+ Entity *entry_point = NULL;
+ bool has_dll_main = false;
+ bool has_win_main = false;
+
+ for_array(i, info->entities.entries) {
+ MapDeclInfoEntry *entry = &info->entities.entries.e[i];
+ Entity *e = cast(Entity *)cast(uintptr)entry->key.key;
+ String name = e->token.string;
+ if (e->kind == Entity_Variable) {
+ global_variable_max_count++;
+ } else if (e->kind == Entity_Procedure && !e->scope->is_global) {
+ if (e->scope->is_init && str_eq(name, str_lit("main"))) {
+ entry_point = e;
+ }
+ if ((e->Procedure.tags & ProcTag_export) != 0 ||
+ (e->Procedure.link_name.len > 0) ||
+ (e->scope->is_file && e->Procedure.link_name.len > 0)) {
+ if (!has_dll_main && str_eq(name, str_lit("DllMain"))) {
+ has_dll_main = true;
+ } else if (!has_win_main && str_eq(name, str_lit("WinMain"))) {
+ has_win_main = true;
+ }
+ }
+ }
+ }
+
+
+ m.entry_point_entity = entry_point;
+ m.min_dep_map = generate_minimum_dependency_map(info, entry_point);
+
+ for_array(i, info->entities.entries) {
+ MapDeclInfoEntry *entry = &info->entities.entries.e[i];
+ Entity *e = cast(Entity *)entry->key.ptr;
+ String name = e->token.string;
+ DeclInfo *decl = entry->value;
+ Scope *scope = e->scope;
+
+ if (!scope->is_file) {
+ continue;
+ }
+
+ if (map_entity_get(&m.min_dep_map, hash_pointer(e)) == NULL) {
+ // NOTE(bill): Nothing depends upon it so doesn't need to be built
+ continue;
+ }
+
+ if (!scope->is_global) {
+ if (e->kind == Entity_Procedure && (e->Procedure.tags & ProcTag_export) != 0) {
+ } else if (e->kind == Entity_Procedure && e->Procedure.link_name.len > 0) {
+ // Handle later
+ } else if (scope->is_init && e->kind == Entity_Procedure && str_eq(name, str_lit("main"))) {
+ } else {
+ name = ssa_mangle_name(&m, e->token.pos.file, e);
+ }
+ }
+
+
+ switch (e->kind) {
+ case Entity_TypeName:
+ break;
+
+ case Entity_Variable: {
+
+ } break;
+
+ case Entity_Procedure: {
+ ast_node(pd, ProcLit, decl->proc_lit);
+ String original_name = name;
+ AstNode *body = pd->body;
+ if (e->Procedure.is_foreign) {
+ name = e->token.string; // NOTE(bill): Don't use the mangled name
+ }
+ if (pd->foreign_name.len > 0) {
+ name = pd->foreign_name;
+ } else if (pd->link_name.len > 0) {
+ name = pd->link_name;
+ }
+
+ if (e == entry_point) {
+ ssaProc *p = ssa_new_proc(&m, name, e, decl);
+ ssa_build_proc(&m, p);
+ }
+
+ // ssaValue *p = ssa_make_value_procedure(a, m, e, e->type, decl->type_expr, body, name);
+ // p->Proc.tags = pd->tags;
+
+ // ssa_module_add_value(m, e, p);
+ // HashKey hash_name = hash_string(name);
+ // if (map_ssa_value_get(&m.members, hash_name) == NULL) {
+ // map_ssa_value_set(&m.members, hash_name, p);
+ // }
+ } break;
+ }
+ }
+
+ return true;
+}
+
+
+
+
+
+
+String ssa_mangle_name(ssaModule *m, String path, Entity *e) {
+ // NOTE(bill): prefix names not in the init scope
+ // TODO(bill): make robust and not just rely on the file's name
+ String name = e->token.string;
+ CheckerInfo *info = m->info;
+ gbAllocator a = m->allocator;
+ AstFile *file = *map_ast_file_get(&info->files, hash_string(path));
+
+ char *str = gb_alloc_array(a, char, path.len+1);
+ gb_memmove(str, path.text, path.len);
+ str[path.len] = 0;
+ for (isize i = 0; i < path.len; i++) {
+ if (str[i] == '\\') {
+ str[i] = '/';
+ }
+ }
+
+ char const *base = gb_path_base_name(str);
+ char const *ext = gb_path_extension(base);
+ isize base_len = ext-1-base;
+
+ isize max_len = base_len + 1 + 10 + 1 + name.len;
+ bool is_overloaded = check_is_entity_overloaded(e);
+ if (is_overloaded) {
+ max_len += 21;
+ }
+
+ u8 *new_name = gb_alloc_array(a, u8, max_len);
+ isize new_name_len = gb_snprintf(
+ cast(char *)new_name, max_len,
+ "%.*s-%u.%.*s",
+ cast(int)base_len, base,
+ file->id,
+ LIT(name));
+ if (is_overloaded) {
+ char *str = cast(char *)new_name + new_name_len-1;
+ isize len = max_len-new_name_len;
+ isize extra = gb_snprintf(str, len, "-%tu", cast(usize)cast(uintptr)e);
+ new_name_len += extra-1;
+ }
+
+ return make_string(new_name, new_name_len-1);
+}
diff --git a/src/ssa_op.c b/src/ssa_op.c
new file mode 100644
index 000000000..22bde663d
--- /dev/null
+++ b/src/ssa_op.c
@@ -0,0 +1,277 @@
+#define SSA_OPS \
+ SSA_OP(Invalid)\
+\
+ SSA_OP(Unknown)\
+\
+ SSA_OP(Comment) /* Does nothing */\
+\
+ SSA_OP(SP) /* Stack Pointer */\
+ SSA_OP(SB) /* Stack Base */\
+ SSA_OP(Addr) /* Address of something - special rules for certain types when loading and storing (e.g. Maps) */\
+\
+ SSA_OP(Local)\
+ SSA_OP(Global)\
+ SSA_OP(Proc)\
+\
+ SSA_OP(Load)\
+ SSA_OP(Store)\
+ SSA_OP(Move)\
+ SSA_OP(LoadReg)\
+ SSA_OP(StoreReg)\
+ SSA_OP(Zero) /* Zero initialize */\
+\
+ SSA_OP(ArrayIndex) /* Index for a fixed array */\
+ SSA_OP(PtrIndex) /* Index for a struct/tuple/etc */\
+ SSA_OP(PtrOffset)\
+ SSA_OP(ValueIndex) /* Extract for a value from a register */\
+\
+ SSA_OP(Phi)\
+ SSA_OP(Copy)\
+\
+ /* TODO(bill): calling conventions */\
+ SSA_OP(CallOdin)\
+ SSA_OP(CallC)\
+ SSA_OP(CallStd)\
+ SSA_OP(CallFast)\
+\
+ SSA_OP(BoundsCheck)\
+ SSA_OP(SliceBoundsCheck)\
+\
+ /* Built in operations/procedures */\
+ SSA_OP(Bswap16)\
+ SSA_OP(Bswap32)\
+ SSA_OP(Bswap64)\
+\
+ SSA_OP(Assume)\
+ SSA_OP(DebugTrap)\
+ SSA_OP(Trap)\
+ SSA_OP(ReadCycleCounter)\
+\
+\
+ SSA_OP(ConstBool)\
+ SSA_OP(ConstString)\
+ SSA_OP(ConstSlice)\
+ SSA_OP(ConstNil)\
+ SSA_OP(Const8)\
+ SSA_OP(Const16)\
+ SSA_OP(Const32)\
+ SSA_OP(Const64)\
+ SSA_OP(Const32F)\
+ SSA_OP(Const64F)\
+\
+ /* These should be all the operations I could possibly need for the mean time */\
+ SSA_OP(Add8)\
+ SSA_OP(Add16)\
+ SSA_OP(Add32)\
+ SSA_OP(Add64)\
+ SSA_OP(AddPtr)\
+ SSA_OP(Add32F)\
+ SSA_OP(Add64F)\
+ SSA_OP(Sub8)\
+ SSA_OP(Sub16)\
+ SSA_OP(Sub32)\
+ SSA_OP(Sub64)\
+ SSA_OP(SubPtr)\
+ SSA_OP(Sub32F)\
+ SSA_OP(Sub64F)\
+ SSA_OP(Mul8)\
+ SSA_OP(Mul16)\
+ SSA_OP(Mul32)\
+ SSA_OP(Mul64)\
+ SSA_OP(Mul32F)\
+ SSA_OP(Mul64F)\
+ SSA_OP(Div8)\
+ SSA_OP(Div8U)\
+ SSA_OP(Div16)\
+ SSA_OP(Div16U)\
+ SSA_OP(Div32)\
+ SSA_OP(Div32U)\
+ SSA_OP(Div64)\
+ SSA_OP(Div64U)\
+ SSA_OP(Div32F)\
+ SSA_OP(Div64F)\
+ SSA_OP(Mod8)\
+ SSA_OP(Mod8U)\
+ SSA_OP(Mod16)\
+ SSA_OP(Mod16U)\
+ SSA_OP(Mod32)\
+ SSA_OP(Mod32U)\
+ SSA_OP(Mod64)\
+ SSA_OP(Mod64U)\
+\
+ SSA_OP(And8)\
+ SSA_OP(And16)\
+ SSA_OP(And32)\
+ SSA_OP(And64)\
+ SSA_OP(Or8)\
+ SSA_OP(Or16)\
+ SSA_OP(Or32)\
+ SSA_OP(Or64)\
+ SSA_OP(Xor8)\
+ SSA_OP(Xor16)\
+ SSA_OP(Xor32)\
+ SSA_OP(Xor64)\
+ SSA_OP(AndNot8)\
+ SSA_OP(AndNot16)\
+ SSA_OP(AndNot32)\
+ SSA_OP(AndNot64)\
+\
+ SSA_OP(Lsh8x8)\
+ SSA_OP(Lsh8x16)\
+ SSA_OP(Lsh8x32)\
+ SSA_OP(Lsh8x64)\
+ SSA_OP(Lsh16x8)\
+ SSA_OP(Lsh16x16)\
+ SSA_OP(Lsh16x32)\
+ SSA_OP(Lsh16x64)\
+ SSA_OP(Lsh32x8)\
+ SSA_OP(Lsh32x16)\
+ SSA_OP(Lsh32x32)\
+ SSA_OP(Lsh32x64)\
+ SSA_OP(Lsh64x8)\
+ SSA_OP(Lsh64x16)\
+ SSA_OP(Lsh64x32)\
+ SSA_OP(Lsh64x64)\
+ SSA_OP(Rsh8x8)\
+ SSA_OP(Rsh8x16)\
+ SSA_OP(Rsh8x32)\
+ SSA_OP(Rsh8x64)\
+ SSA_OP(Rsh16x8)\
+ SSA_OP(Rsh16x16)\
+ SSA_OP(Rsh16x32)\
+ SSA_OP(Rsh16x64)\
+ SSA_OP(Rsh32x8)\
+ SSA_OP(Rsh32x16)\
+ SSA_OP(Rsh32x32)\
+ SSA_OP(Rsh32x64)\
+ SSA_OP(Rsh64x8)\
+ SSA_OP(Rsh64x16)\
+ SSA_OP(Rsh64x32)\
+ SSA_OP(Rsh64x64)\
+ SSA_OP(Rsh8Ux8)\
+ SSA_OP(Rsh8Ux16)\
+ SSA_OP(Rsh8Ux32)\
+ SSA_OP(Rsh8Ux64)\
+ SSA_OP(Rsh16Ux8)\
+ SSA_OP(Rsh16Ux16)\
+ SSA_OP(Rsh16Ux32)\
+ SSA_OP(Rsh16Ux64)\
+ SSA_OP(Rsh32Ux8)\
+ SSA_OP(Rsh32Ux16)\
+ SSA_OP(Rsh32Ux32)\
+ SSA_OP(Rsh32Ux64)\
+ SSA_OP(Rsh64Ux8)\
+ SSA_OP(Rsh64Ux16)\
+ SSA_OP(Rsh64Ux32)\
+ SSA_OP(Rsh64Ux64)\
+\
+ SSA_OP(Eq8)\
+ SSA_OP(Eq16)\
+ SSA_OP(Eq32)\
+ SSA_OP(Eq64)\
+ SSA_OP(EqPtr)\
+ SSA_OP(Eq32F)\
+ SSA_OP(Eq64F)\
+ SSA_OP(Ne8)\
+ SSA_OP(Ne16)\
+ SSA_OP(Ne32)\
+ SSA_OP(Ne64)\
+ SSA_OP(NePtr)\
+ SSA_OP(Ne32F)\
+ SSA_OP(Ne64F)\
+ SSA_OP(Lt8)\
+ SSA_OP(Lt16)\
+ SSA_OP(Lt32)\
+ SSA_OP(Lt64)\
+ SSA_OP(LtPtr)\
+ SSA_OP(Lt32F)\
+ SSA_OP(Lt64F)\
+ SSA_OP(Gt8)\
+ SSA_OP(Gt16)\
+ SSA_OP(Gt32)\
+ SSA_OP(Gt64)\
+ SSA_OP(GtPtr)\
+ SSA_OP(Gt32F)\
+ SSA_OP(Gt64F)\
+ SSA_OP(Le8)\
+ SSA_OP(Le16)\
+ SSA_OP(Le32)\
+ SSA_OP(Le64)\
+ SSA_OP(LePtr)\
+ SSA_OP(Le32F)\
+ SSA_OP(Le64F)\
+ SSA_OP(Ge8)\
+ SSA_OP(Ge16)\
+ SSA_OP(Ge32)\
+ SSA_OP(Ge64)\
+ SSA_OP(GePtr)\
+ SSA_OP(Ge32F)\
+ SSA_OP(Ge64F)\
+\
+ SSA_OP(NotB)\
+ SSA_OP(EqB)\
+ SSA_OP(NeB)\
+\
+ SSA_OP(Neg8)\
+ SSA_OP(Neg16)\
+ SSA_OP(Neg32)\
+ SSA_OP(Neg64)\
+ SSA_OP(Neg32F)\
+ SSA_OP(Neg64F)\
+\
+ SSA_OP(Not8)\
+ SSA_OP(Not16)\
+ SSA_OP(Not32)\
+ SSA_OP(Not64)\
+\
+ SSA_OP(SignExt8to16)\
+ SSA_OP(SignExt8to32)\
+ SSA_OP(SignExt8to64)\
+ SSA_OP(SignExt16to32)\
+ SSA_OP(SignExt16to64)\
+ SSA_OP(SignExt32to64)\
+ SSA_OP(ZeroExt8to16)\
+ SSA_OP(ZeroExt8to32)\
+ SSA_OP(ZeroExt8to64)\
+ SSA_OP(ZeroExt16to32)\
+ SSA_OP(ZeroExt16to64)\
+ SSA_OP(ZeroExt32to64)\
+ SSA_OP(Trunc16to8)\
+ SSA_OP(Trunc32to8)\
+ SSA_OP(Trunc32to16)\
+ SSA_OP(Trunc64to8)\
+ SSA_OP(Trunc64to16)\
+ SSA_OP(Trunc64to32)\
+\
+ SSA_OP(Cvt32to32F)\
+ SSA_OP(Cvt32to64F)\
+ SSA_OP(Cvt64to32F)\
+ SSA_OP(Cvt64to64F)\
+ SSA_OP(Cvt32Fto32)\
+ SSA_OP(Cvt32Fto64)\
+ SSA_OP(Cvt64Fto32)\
+ SSA_OP(Cvt64Fto64)\
+ SSA_OP(Cvt32Fto64F)\
+ SSA_OP(Cvt64Fto32F)\
+ SSA_OP(Cvt32Uto32F)\
+ SSA_OP(Cvt32Uto64F)\
+ SSA_OP(Cvt32Fto32U)\
+ SSA_OP(Cvt64Fto32U)\
+ SSA_OP(Cvt64Uto32F)\
+ SSA_OP(Cvt64Uto64F)\
+ SSA_OP(Cvt32Fto64U)\
+ SSA_OP(Cvt64Fto64U)\
+
+
+enum ssaOp {
+#define SSA_OP(k) GB_JOIN2(ssaOp_, k),
+ SSA_OPS
+#undef SSA_OP
+};
+typedef enum ssaOp ssaOp;
+
+String const ssa_op_strings[] = {
+#define SSA_OP(k) {cast(u8 *)#k, gb_size_of(#k)-1},
+ SSA_OPS
+#undef SSA_OP
+};
diff --git a/src/tokenizer.c b/src/tokenizer.c
index cfc1423f0..6c7f76c02 100644
--- a/src/tokenizer.c
+++ b/src/tokenizer.c
@@ -484,15 +484,9 @@ gb_inline i32 digit_value(Rune r) {
return 16; // NOTE(bill): Larger than highest possible
}
-gb_inline void scan_mantissa(Tokenizer *t, i32 base, bool allow_underscore) {
- if (allow_underscore) {
- while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
- advance_to_next_rune(t);
- }
- } else {
- while (digit_value(t->curr_rune) < base) {
- advance_to_next_rune(t);
- }
+gb_inline void scan_mantissa(Tokenizer *t, i32 base) {
+ while (digit_value(t->curr_rune) < base || t->curr_rune == '_') {
+ advance_to_next_rune(t);
}
}
@@ -506,7 +500,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
if (seen_decimal_point) {
token.kind = Token_Float;
- scan_mantissa(t, 10, true);
+ scan_mantissa(t, 10);
goto exponent;
}
@@ -515,31 +509,37 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
advance_to_next_rune(t);
if (t->curr_rune == 'b') { // Binary
advance_to_next_rune(t);
- scan_mantissa(t, 2, true);
+ scan_mantissa(t, 2);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'o') { // Octal
advance_to_next_rune(t);
- scan_mantissa(t, 8, true);
+ scan_mantissa(t, 8);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'd') { // Decimal
advance_to_next_rune(t);
- scan_mantissa(t, 10, true);
+ scan_mantissa(t, 10);
+ if (t->curr - prev <= 2) {
+ token.kind = Token_Invalid;
+ }
+ } else if (t->curr_rune == 'z') { // Dozenal
+ advance_to_next_rune(t);
+ scan_mantissa(t, 12);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else if (t->curr_rune == 'x') { // Hexadecimal
advance_to_next_rune(t);
- scan_mantissa(t, 16, true);
+ scan_mantissa(t, 16);
if (t->curr - prev <= 2) {
token.kind = Token_Invalid;
}
} else {
seen_decimal_point = false;
- scan_mantissa(t, 10, true);
+ scan_mantissa(t, 10);
if (t->curr_rune == '.' || t->curr_rune == 'e' || t->curr_rune == 'E') {
seen_decimal_point = true;
@@ -551,7 +551,7 @@ Token scan_number_to_token(Tokenizer *t, bool seen_decimal_point) {
return token;
}
- scan_mantissa(t, 10, true);
+ scan_mantissa(t, 10);
fraction:
if (t->curr_rune == '.') {
@@ -564,7 +564,7 @@ fraction:
goto end;
}
token.kind = Token_Float;
- scan_mantissa(t, 10, true);
+ scan_mantissa(t, 10);
}
exponent:
@@ -574,7 +574,7 @@ exponent:
if (t->curr_rune == '-' || t->curr_rune == '+') {
advance_to_next_rune(t);
}
- scan_mantissa(t, 10, false);
+ scan_mantissa(t, 10);
}
end:
diff --git a/src/types.c b/src/types.c
index 362e949fb..75510cf85 100644
--- a/src/types.c
+++ b/src/types.c
@@ -375,6 +375,10 @@ Type *base_enum_type(Type *t) {
return t;
}
+Type *core_type(Type *t) {
+ return base_type(base_enum_type(t));
+}
+
void set_base_type(Type *t, Type *base) {
if (t && t->kind == Type_Named) {
t->Named.base = base;
@@ -530,28 +534,28 @@ bool is_type_named(Type *t) {
return t->kind == Type_Named;
}
bool is_type_boolean(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Boolean) != 0;
}
return false;
}
bool is_type_integer(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Integer) != 0;
}
return false;
}
bool is_type_unsigned(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Unsigned) != 0;
}
return false;
}
bool is_type_numeric(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Numeric) != 0;
}
@@ -586,7 +590,7 @@ bool is_type_untyped(Type *t) {
return false;
}
bool is_type_ordered(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
switch (t->kind) {
case Type_Basic:
return (t->Basic.flags & BasicFlag_Ordered) != 0;
@@ -598,28 +602,28 @@ bool is_type_ordered(Type *t) {
return false;
}
bool is_type_constant_type(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_ConstantType) != 0;
}
return false;
}
bool is_type_float(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return (t->Basic.flags & BasicFlag_Float) != 0;
}
return false;
}
bool is_type_f32(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_f32;
}
return false;
}
bool is_type_f64(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (t->kind == Type_Basic) {
return t->Basic.kind == Basic_f64;
}
@@ -737,7 +741,7 @@ bool is_type_untyped_nil(Type *t) {
bool is_type_valid_for_keys(Type *t) {
- t = base_type(base_enum_type(t));
+ t = core_type(t);
if (is_type_untyped(t)) {
return false;
}
@@ -798,7 +802,7 @@ bool is_type_comparable(Type *t) {
return true;
case Type_Record: {
if (is_type_enum(t)) {
- return is_type_comparable(base_enum_type(t));
+ return is_type_comparable(core_type(t));
}
return false;
} break;
@@ -1032,7 +1036,21 @@ typedef enum ProcTypeOverloadKind {
} ProcTypeOverloadKind;
+bool has_encountered_null_proc_type = false;
ProcTypeOverloadKind are_proc_types_overload_safe(Type *x, Type *y) {
+ if(x == NULL && y == NULL) {
+ if(!has_encountered_null_proc_type) {
+ printf("The compiler has encountered a NULL proc type.\n"
+ " This is probably not an error in your code, and\n"
+ " the compile is probably still successful.\n"
+ " This does mean that (at least once), there could be a\n"
+ " bad procedure overload in your program, and Odin wouldn't catch it.\n"
+ " As far as I know, this is a porting bug, and doesn't occur on mainline Odin.\n"
+ " Be careful, and sorry about this bug :(\n");
+ has_encountered_null_proc_type = true;
+ }
+ return ProcOverload_ParamCount;
+ }
if (!is_type_proc(x)) return ProcOverload_NotProcedure;
if (!is_type_proc(y)) return ProcOverload_NotProcedure;
TypeProc px = base_type(x)->Proc;
@@ -1215,7 +1233,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
// NOTE(bill): Underlying memory address cannot be changed
if (str_eq(field_name, count_str)) {
// HACK(bill): Memory leak
- sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Array.count));
+ sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Array.count));
return sel;
}
} else if (type->kind == Type_Vector) {
@@ -1223,7 +1241,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
// NOTE(bill): Vectors are not addressable
if (str_eq(field_name, count_str)) {
// HACK(bill): Memory leak
- sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, make_exact_value_integer(type->Vector.count));
+ sel.entity = make_entity_constant(a, NULL, make_token_ident(count_str), t_int, exact_value_integer(type->Vector.count));
return sel;
}
diff --git a/src/unicode.c b/src/unicode.c
index d65f2f2ae..c1277c4da 100644
--- a/src/unicode.c
+++ b/src/unicode.c
@@ -6,6 +6,7 @@
#pragma warning(pop)
+
bool rune_is_letter(Rune r) {
if ((r < 0x80 && gb_char_is_alpha(cast(char)r)) ||
r == '_') {
diff --git a/src/utf8proc/utf8proc.c b/src/utf8proc/utf8proc.c
index 7a6c984ac..c14bbe13f 100644
--- a/src/utf8proc/utf8proc.c
+++ b/src/utf8proc/utf8proc.c
@@ -166,24 +166,24 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_encode_char(utf8proc_int32_t uc, ut
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
- dst[0] = uc;
+ dst[0] = (utf8proc_uint8_t) uc;
return 1;
} else if (uc < 0x800) {
- dst[0] = 0xC0 + (uc >> 6);
- dst[1] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
+ dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
// Note: we allow encoding 0xd800-0xdfff here, so as not to change
// the API, however, these are actually invalid in UTF-8
} else if (uc < 0x10000) {
- dst[0] = 0xE0 + (uc >> 12);
- dst[1] = 0x80 + ((uc >> 6) & 0x3F);
- dst[2] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
+ dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
+ dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
- dst[0] = 0xF0 + (uc >> 18);
- dst[1] = 0x80 + ((uc >> 12) & 0x3F);
- dst[2] = 0x80 + ((uc >> 6) & 0x3F);
- dst[3] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
+ dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
+ dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
+ dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -193,28 +193,28 @@ static utf8proc_ssize_t unsafe_encode_char(utf8proc_int32_t uc, utf8proc_uint8_t
if (uc < 0x00) {
return 0;
} else if (uc < 0x80) {
- dst[0] = uc;
+ dst[0] = (utf8proc_uint8_t)uc;
return 1;
} else if (uc < 0x800) {
- dst[0] = 0xC0 + (uc >> 6);
- dst[1] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xC0 + (uc >> 6));
+ dst[1] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 2;
} else if (uc == 0xFFFF) {
- dst[0] = 0xFF;
+ dst[0] = (utf8proc_uint8_t)0xFF;
return 1;
} else if (uc == 0xFFFE) {
- dst[0] = 0xFE;
+ dst[0] = (utf8proc_uint8_t)0xFE;
return 1;
} else if (uc < 0x10000) {
- dst[0] = 0xE0 + (uc >> 12);
- dst[1] = 0x80 + ((uc >> 6) & 0x3F);
- dst[2] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xE0 + (uc >> 12));
+ dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
+ dst[2] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 3;
} else if (uc < 0x110000) {
- dst[0] = 0xF0 + (uc >> 18);
- dst[1] = 0x80 + ((uc >> 12) & 0x3F);
- dst[2] = 0x80 + ((uc >> 6) & 0x3F);
- dst[3] = 0x80 + (uc & 0x3F);
+ dst[0] = (utf8proc_uint8_t)(0xF0 + (uc >> 18));
+ dst[1] = (utf8proc_uint8_t)(0x80 + ((uc >> 12) & 0x3F));
+ dst[2] = (utf8proc_uint8_t)(0x80 + ((uc >> 6) & 0x3F));
+ dst[3] = (utf8proc_uint8_t)(0x80 + (uc & 0x3F));
return 4;
} else return 0;
}
@@ -383,7 +383,7 @@ UTF8PROC_DLLEXPORT int utf8proc_charwidth(utf8proc_int32_t c) {
}
UTF8PROC_DLLEXPORT utf8proc_category_t utf8proc_category(utf8proc_int32_t c) {
- return (utf8proc_category_t)utf8proc_get_property(c)->category;
+ return utf8proc_get_property(c)->category;
}
UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
@@ -391,11 +391,9 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t c) {
return s[utf8proc_category(c)];
}
-
-
#define utf8proc_decompose_lump(replacement_uc) \
- return utf8proc_decompose_char((utf8proc_int32_t)(replacement_uc), dst, bufsize, \
- (utf8proc_option_t)((utf8proc_int32_t)options & ~UTF8PROC_LUMP), last_boundclass)
+ return utf8proc_decompose_char((replacement_uc), dst, bufsize, \
+ options & ~UTF8PROC_LUMP, last_boundclass)
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc, utf8proc_int32_t *dst, utf8proc_ssize_t bufsize, utf8proc_option_t options, int *last_boundclass) {
const utf8proc_property_t *property;
@@ -458,12 +456,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(utf8proc_int32_t uc,
category == UTF8PROC_CATEGORY_ME) return 0;
}
if (options & UTF8PROC_CASEFOLD) {
- if ((utf8proc_int16_t)property->casefold_seqindex != UINT16_MAX) {
+ if (property->casefold_seqindex != UINT16_MAX) {
return seqindex_write_char_decomposed(property->casefold_seqindex, dst, bufsize, options, last_boundclass);
}
}
if (options & (UTF8PROC_COMPOSE|UTF8PROC_DECOMPOSE)) {
- if ((utf8proc_int16_t)property->decomp_seqindex != UINT16_MAX &&
+ if (property->decomp_seqindex != UINT16_MAX &&
(!property->decomp_type || (options & UTF8PROC_COMPAT))) {
return seqindex_write_char_decomposed(property->decomp_seqindex, dst, bufsize, options, last_boundclass);
}
@@ -486,6 +484,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options
) {
+ return utf8proc_decompose_custom(str, strlen, buffer, bufsize, options, NULL, NULL);
+}
+
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
+ const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
+ utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
+ utf8proc_custom_func custom_func, void *custom_data
+) {
/* strlen will be ignored, if UTF8PROC_NULLTERM is set in options */
utf8proc_ssize_t wpos = 0;
if ((options & UTF8PROC_COMPOSE) && (options & UTF8PROC_DECOMPOSE))
@@ -511,6 +517,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
rpos += utf8proc_iterate(str + rpos, strlen - rpos, &uc);
if (uc < 0) return UTF8PROC_ERROR_INVALIDUTF8;
}
+ if (custom_func != NULL) {
+ uc = custom_func(uc, custom_data); /* user-specified custom mapping */
+ }
decomp_result = utf8proc_decompose_char(
uc, buffer + wpos, (bufsize > wpos) ? (bufsize - wpos) : 0, options,
&boundclass
@@ -545,9 +554,8 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
return wpos;
}
-UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
- /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
- ASSERT: 'buffer' has one spare byte of free space at the end! */
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
+ /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored */
if (options & (UTF8PROC_NLF2LS | UTF8PROC_NLF2PS | UTF8PROC_STRIPCC)) {
utf8proc_ssize_t rpos;
utf8proc_ssize_t wpos = 0;
@@ -621,7 +629,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
starter_property = unsafe_get_property(*starter);
}
if (starter_property->comb_index < 0x8000 &&
- (utf8proc_int16_t)current_property->comb_index != UINT16_MAX &&
+ current_property->comb_index != UINT16_MAX &&
current_property->comb_index >= 0x8000) {
int sidx = starter_property->comb_index;
int idx = (current_property->comb_index & 0x3FFF) - utf8proc_combinations[sidx];
@@ -655,6 +663,14 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
}
length = wpos;
}
+ return length;
+}
+
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options) {
+ /* UTF8PROC_NULLTERM option will be ignored, 'length' is never ignored
+ ASSERT: 'buffer' has one spare byte of free space at the end! */
+ length = utf8proc_normalize_utf32(buffer, length, options);
+ if (length < 0) return length;
{
utf8proc_ssize_t rpos, wpos = 0;
utf8proc_int32_t uc;
@@ -677,14 +693,21 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_reencode(utf8proc_int32_t *buffer,
UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
) {
+ return utf8proc_map_custom(str, strlen, dstptr, options, NULL, NULL);
+}
+
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
+ const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
+ utf8proc_custom_func custom_func, void *custom_data
+) {
utf8proc_int32_t *buffer;
utf8proc_ssize_t result;
*dstptr = NULL;
- result = utf8proc_decompose(str, strlen, NULL, 0, options);
+ result = utf8proc_decompose_custom(str, strlen, NULL, 0, options, custom_func, custom_data);
if (result < 0) return result;
buffer = (utf8proc_int32_t *) malloc(result * sizeof(utf8proc_int32_t) + 1);
if (!buffer) return UTF8PROC_ERROR_NOMEM;
- result = utf8proc_decompose(str, strlen, buffer, result, options);
+ result = utf8proc_decompose_custom(str, strlen, buffer, result, options, custom_func, custom_data);
if (result < 0) {
free(buffer);
return result;
@@ -705,29 +728,28 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
- utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
- UTF8PROC_DECOMPOSE));
+ utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_DECOMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
- utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
- UTF8PROC_COMPOSE));
+ utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_COMPOSE);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
- utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
- UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT));
+ utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_DECOMPOSE | UTF8PROC_COMPAT);
return retval;
}
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str) {
utf8proc_uint8_t *retval;
- utf8proc_map(str, 0, &retval, (utf8proc_option_t)(UTF8PROC_NULLTERM | UTF8PROC_STABLE |
- UTF8PROC_COMPOSE | UTF8PROC_COMPAT));
+ utf8proc_map(str, 0, &retval, UTF8PROC_NULLTERM | UTF8PROC_STABLE |
+ UTF8PROC_COMPOSE | UTF8PROC_COMPAT);
return retval;
}
-
diff --git a/src/utf8proc/utf8proc.h b/src/utf8proc/utf8proc.h
index 240fac66f..2dd8c1917 100644
--- a/src/utf8proc/utf8proc.h
+++ b/src/utf8proc/utf8proc.h
@@ -71,14 +71,15 @@
/** The MAJOR version number (increased when backwards API compatibility is broken). */
#define UTF8PROC_VERSION_MAJOR 2
/** The MINOR version number (increased when new functionality is added in a backwards-compatible manner). */
-#define UTF8PROC_VERSION_MINOR 0
+#define UTF8PROC_VERSION_MINOR 1
/** The PATCH version (increased for fixes that do not change the API). */
-#define UTF8PROC_VERSION_PATCH 2
+#define UTF8PROC_VERSION_PATCH 0
/** @} */
#include <stdlib.h>
-#include <sys/types.h>
-#ifdef _MSC_VER
+
+#if defined(_MSC_VER) && _MSC_VER < 1800
+// MSVC prior to 2013 lacked stdbool.h and inttypes.h
typedef signed char utf8proc_int8_t;
typedef unsigned char utf8proc_uint8_t;
typedef short utf8proc_int16_t;
@@ -93,12 +94,18 @@ typedef int utf8proc_ssize_t;
typedef unsigned int utf8proc_size_t;
# endif
# ifndef __cplusplus
+// emulate C99 bool
typedef unsigned char utf8proc_bool;
-// enum {false, true};
+# ifndef __bool_true_false_are_defined
+# define false 0
+# define true 1
+# define __bool_true_false_are_defined 1
+# endif
# else
typedef bool utf8proc_bool;
# endif
#else
+# include <stddef.h>
# include <stdbool.h>
# include <inttypes.h>
typedef int8_t utf8proc_int8_t;
@@ -108,22 +115,12 @@ typedef uint16_t utf8proc_uint16_t;
typedef int32_t utf8proc_int32_t;
typedef uint32_t utf8proc_uint32_t;
typedef size_t utf8proc_size_t;
-typedef ssize_t utf8proc_ssize_t;
+typedef ptrdiff_t utf8proc_ssize_t;
typedef bool utf8proc_bool;
#endif
#include <limits.h>
-#ifdef _WIN32
-# ifdef UTF8PROC_EXPORTS
-# define UTF8PROC_DLLEXPORT __declspec(dllexport)
-# else
-# define UTF8PROC_DLLEXPORT /*__declspec(dllimport)*/
-# endif
-#elif __GNUC__ >= 4
-# define UTF8PROC_DLLEXPORT __attribute__ ((visibility("default")))
-#else
-# define UTF8PROC_DLLEXPORT
-#endif
+#define UTF8PROC_DLLEXPORT
#ifdef __cplusplus
extern "C" {
@@ -134,7 +131,7 @@ extern "C" {
#endif
#ifndef UINT16_MAX
-# define UINT16_MAX ~(utf8proc_uint16_t)0
+# define UINT16_MAX 65535U
#endif
/**
@@ -374,6 +371,13 @@ typedef enum {
} utf8proc_boundclass_t;
/**
+ * Function pointer type passed to @ref utf8proc_map_custom and
+ * @ref utf8proc_decompose_custom, which is used to specify a user-defined
+ * mapping of codepoints to be applied in conjunction with other mappings.
+ */
+typedef utf8proc_int32_t (*utf8proc_custom_func)(utf8proc_int32_t codepoint, void *data);
+
+/**
* Array containing the byte lengths of a UTF-8 encoded codepoint based
* on the first byte.
*/
@@ -480,6 +484,7 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_char(
* `buffer` (which must contain at least `bufsize` entries). In case of
* success, the number of codepoints written is returned; in case of an
* error, a negative error code is returned (@ref utf8proc_errmsg).
+ * See @ref utf8proc_decompose_custom to supply additional transformations.
*
* If the number of written codepoints would be bigger than `bufsize`, the
* required buffer size is returned, while the buffer will be overwritten with
@@ -491,8 +496,46 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
);
/**
+ * The same as @ref utf8proc_decompose, but also takes a `custom_func` mapping function
+ * that is called on each codepoint in `str` before any other transformations
+ * (along with a `custom_data` pointer that is passed through to `custom_func`).
+ * The `custom_func` argument is ignored if it is `NULL`. See also @ref utf8proc_map_custom.
+ */
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose_custom(
+ const utf8proc_uint8_t *str, utf8proc_ssize_t strlen,
+ utf8proc_int32_t *buffer, utf8proc_ssize_t bufsize, utf8proc_option_t options,
+ utf8proc_custom_func custom_func, void *custom_data
+);
+
+/**
+ * Normalizes the sequence of `length` codepoints pointed to by `buffer`
+ * in-place (i.e., the result is also stored in `buffer`).
+ *
+ * @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
+ * @param length the length (in codepoints) of the buffer.
+ * @param options a bitwise or (`|`) of one or more of the following flags:
+ * - @ref UTF8PROC_NLF2LS - convert LF, CRLF, CR and NEL into LS
+ * - @ref UTF8PROC_NLF2PS - convert LF, CRLF, CR and NEL into PS
+ * - @ref UTF8PROC_NLF2LF - convert LF, CRLF, CR and NEL into LF
+ * - @ref UTF8PROC_STRIPCC - strip or convert all non-affected control characters
+ * - @ref UTF8PROC_COMPOSE - try to combine decomposed codepoints into composite
+ * codepoints
+ * - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
+ * the unicode versioning stability
+ *
+ * @return
+ * In case of success, the length (in codepoints) of the normalized UTF-32 string is
+ * returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
+ *
+ * @warning The entries of the array pointed to by `str` have to be in the
+ * range `0x0000` to `0x10FFFF`. Otherwise, the program might crash!
+ */
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_normalize_utf32(utf8proc_int32_t *buffer, utf8proc_ssize_t length, utf8proc_option_t options);
+
+/**
* Reencodes the sequence of `length` codepoints pointed to by `buffer`
* UTF-8 data in-place (i.e., the result is also stored in `buffer`).
+ * Can optionally normalize the UTF-32 sequence prior to UTF-8 conversion.
*
* @param buffer the (native-endian UTF-32) unicode codepoints to re-encode.
* @param length the length (in codepoints) of the buffer.
@@ -505,10 +548,12 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_decompose(
* codepoints
* - @ref UTF8PROC_STABLE - prohibit combining characters that would violate
* the unicode versioning stability
+ * - @ref UTF8PROC_CHARBOUND - insert 0xFF bytes before each grapheme cluster
*
* @return
- * In case of success, the length (in bytes) of the resulting UTF-8 string is
- * returned; otherwise, a negative error code is returned (@ref utf8proc_errmsg).
+ * In case of success, the length (in bytes) of the resulting nul-terminated
+ * UTF-8 string is returned; otherwise, a negative error code is returned
+ * (@ref utf8proc_errmsg).
*
* @warning The amount of free space pointed to by `buffer` must
* exceed the amount of the input data by one byte, and the
@@ -595,7 +640,8 @@ UTF8PROC_DLLEXPORT const char *utf8proc_category_string(utf8proc_int32_t codepoi
* in any case the result will be NULL terminated (though it might
* contain NULL characters with the string if `str` contained NULL
* characters). Other flags in the `options` field are passed to the
- * functions defined above, and regarded as described.
+ * functions defined above, and regarded as described. See also
+ * @ref utfproc_map_custom to supply a custom codepoint transformation.
*
* In case of success the length of the new string is returned,
* otherwise a negative error code is returned.
@@ -607,6 +653,17 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options
);
+/**
+ * Like @ref utf8proc_map, but also takes a `custom_func` mapping function
+ * that is called on each codepoint in `str` before any other transformations
+ * (along with a `custom_data` pointer that is passed through to `custom_func`).
+ * The `custom_func` argument is ignored if it is `NULL`.
+ */
+UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map_custom(
+ const utf8proc_uint8_t *str, utf8proc_ssize_t strlen, utf8proc_uint8_t **dstptr, utf8proc_option_t options,
+ utf8proc_custom_func custom_func, void *custom_data
+);
+
/** @name Unicode normalization
*
* Returns a pointer to newly allocated memory of a NFD, NFC, NFKD or NFKC
@@ -619,9 +676,9 @@ UTF8PROC_DLLEXPORT utf8proc_ssize_t utf8proc_map(
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFD(const utf8proc_uint8_t *str);
/** NFC normalization (@ref UTF8PROC_COMPOSE). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFC(const utf8proc_uint8_t *str);
-/** NFD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
+/** NFKD normalization (@ref UTF8PROC_DECOMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKD(const utf8proc_uint8_t *str);
-/** NFD normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
+/** NFKC normalization (@ref UTF8PROC_COMPOSE and @ref UTF8PROC_COMPAT). */
UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
/** @} */
@@ -630,4 +687,3 @@ UTF8PROC_DLLEXPORT utf8proc_uint8_t *utf8proc_NFKC(const utf8proc_uint8_t *str);
#endif
#endif
-
diff --git a/src/utf8proc/utf8proc_data.c b/src/utf8proc/utf8proc_data.c
index dc44f8125..defd77303 100644
--- a/src/utf8proc/utf8proc_data.c
+++ b/src/utf8proc/utf8proc_data.c
@@ -1,7 +1,4 @@
-#pragma warning(push)
-#pragma warning(disable: 4838)
-
-const utf8proc_uint16_t utf8proc_sequences[] = {
+static const utf8proc_uint16_t utf8proc_sequences[] = {
97, 98, 99, 100, 101, 102, 103,
104, 105, 106, 107, 108, 109, 110, 111,
112, 113, 114, 115, 116, 117, 118, 119,
@@ -1179,7 +1176,7 @@ const utf8proc_uint16_t utf8proc_sequences[] = {
56603, 55354, 56604, 55354, 56605, 55354, 56606, 55354,
56607, 55354, 56608, 55354, 56609, };
-const utf8proc_uint16_t utf8proc_stage1table[] = {
+static const utf8proc_uint16_t utf8proc_stage1table[] = {
0, 256, 512, 768, 1024, 1280, 1536,
1792, 2048, 2304, 2560, 2816, 3072, 3328, 3584,
3840, 4096, 4352, 4608, 4864, 5120, 5376, 5632,
@@ -1726,7 +1723,7 @@ const utf8proc_uint16_t utf8proc_stage1table[] = {
18432, 18432, 18432, 18432, 18432, 18432, 18432, 18432,
38656, };
-const utf8proc_uint16_t utf8proc_stage2table[] = {
+static const utf8proc_uint16_t utf8proc_stage2table[] = {
1, 2, 2, 2, 2, 2, 2,
2, 2, 3, 4, 3, 5, 6, 2,
2, 2, 2, 2, 2, 2, 2, 2,
@@ -5899,7 +5896,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
540, 540, 540, 1180, 0, 0, 0, 0,
0, 1154, 1154, 1154, 1154, 1154, 1154, 1154,
1154, 1154, 1154, 0, 0, 0, 0, 1103,
- 1158, 0, 0, 0, 0, 0, 0, 0,
+ 1103, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
@@ -6593,7 +6590,7 @@ const utf8proc_uint16_t utf8proc_stage2table[] = {
3984, 3984, 3984, 3984, 3984, 3984, 3984, 0,
0, };
-const utf8proc_property_t utf8proc_properties[] = {
+static const utf8proc_property_t utf8proc_properties[] = {
{0, 0, 0, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false,false,false,false, 0, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, true, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
{UTF8PROC_CATEGORY_CC, 0, UTF8PROC_BIDI_CLASS_BN, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, true, 0, 0, UTF8PROC_BOUNDCLASS_CONTROL},
@@ -7850,7 +7847,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_MN, 122, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9523, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_COMPAT, 9525, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
- {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
+ {UTF8PROC_CATEGORY_PO, 0, UTF8PROC_BIDI_CLASS_L, UTF8PROC_DECOMP_TYPE_NOBREAK, 1335, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_MN, 216, UTF8PROC_BIDI_CLASS_NSM, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 0, 0, UTF8PROC_BOUNDCLASS_EXTEND},
{UTF8PROC_CATEGORY_PS, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_PE, 0, UTF8PROC_BIDI_CLASS_ON, 0, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, true, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -10478,7 +10475,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1470, UINT16_MAX, 1470, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1478, UINT16_MAX, 1478, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5132, UINT16_MAX, 5132, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
- {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
+ {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1480, UINT16_MAX, 1480, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5133, UINT16_MAX, 5133, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 5134, UINT16_MAX, 5134, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 1482, UINT16_MAX, 1482, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12168,7 +12165,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6787, UINT16_MAX, 6787, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6789, UINT16_MAX, 6789, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6791, UINT16_MAX, 6791, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
- {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
+ {UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6793, UINT16_MAX, 6793, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6795, UINT16_MAX, 6795, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6797, UINT16_MAX, 6797, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LU, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, 6799, UINT16_MAX, 6799, UINT16_MAX, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -12204,7 +12201,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9104, UINT16_MAX, 9104, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9106, UINT16_MAX, 9106, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9108, UINT16_MAX, 9108, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
- {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
+ {UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9110, UINT16_MAX, 9110, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9112, UINT16_MAX, 9112, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9114, UINT16_MAX, 9114, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
{UTF8PROC_CATEGORY_LL, 0, UTF8PROC_BIDI_CLASS_L, 0, UINT16_MAX, UINT16_MAX, 9116, UINT16_MAX, 9116, UINT16_MAX, false, false, false, false, 1, 0, UTF8PROC_BOUNDCLASS_OTHER},
@@ -13423,7 +13420,7 @@ const utf8proc_property_t utf8proc_properties[] = {
{UTF8PROC_CATEGORY_LO, 0, UTF8PROC_BIDI_CLASS_L, 0, 7975, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, UINT16_MAX, false, false, false, false, 2, 0, UTF8PROC_BOUNDCLASS_OTHER},
};
-const utf8proc_uint16_t utf8proc_combinations[] = {
+static const utf8proc_uint16_t utf8proc_combinations[] = {
0, 46, 192, 193, 194, 195, 196, 197, 0,
256, 258, 260, 550, 461, 0, 0, 512,
514, 0, 0, 0, 0, 0, 0, 0,
@@ -14386,5 +14383,3 @@ const utf8proc_uint16_t utf8proc_combinations[] = {
72, 75,
1, 53694, 1, 53696,
};
-
-#pragma warning(pop)