diff options
| author | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-03-21 14:16:42 -0500 |
|---|---|---|
| committer | Zac Pierson <zacpiersonhehe@gmail.com> | 2017-03-21 14:16:42 -0500 |
| commit | c7bb861d3ca19f1a81043b8ad1e014ad10aa225f (patch) | |
| tree | 56719cc445ebe06b4d2e486e2da3c17c57e216c2 | |
| parent | d890731716ea96fd69d7543c7d7225702cbd7268 (diff) | |
| parent | 188b290dd50664aa8a89955ac2ab7dbebf7a653d (diff) | |
Merge https://github.com/gingerBill/Odin
"Fixed" a proc overload bug. Still needs a *real* fix.
| -rw-r--r-- | .gitignore | 7 | ||||
| -rw-r--r-- | README.md | 4 | ||||
| -rw-r--r-- | bin/CODE_OWNERS.TXT | 200 | ||||
| -rw-r--r-- | bin/CREDITS.TXT | 467 | ||||
| -rw-r--r-- | bin/LICENSE.TXT | 70 | ||||
| -rw-r--r-- | bin/llc.exe | bin | 25395712 -> 0 bytes | |||
| -rw-r--r-- | bin/lli.exe | bin | 12783616 -> 0 bytes | |||
| -rw-r--r-- | bin/opt.exe | bin | 26361344 -> 0 bytes | |||
| -rw-r--r-- | build.bat | 16 | ||||
| -rw-r--r-- | code/demo.odin | 302 | ||||
| -rw-r--r-- | core/_preload.odin | 37 | ||||
| -rw-r--r-- | core/fmt.odin | 101 | ||||
| -rw-r--r-- | core/math.odin | 67 | ||||
| -rw-r--r-- | core/mem.odin | 41 | ||||
| -rw-r--r-- | core/os_windows.odin | 90 | ||||
| -rw-r--r-- | core/strconv.odin | 50 | ||||
| -rw-r--r-- | core/sync.odin | 2 | ||||
| -rw-r--r-- | core/sys/wgl.odin | 50 | ||||
| -rw-r--r-- | core/sys/windows.odin | 268 | ||||
| -rw-r--r-- | misc/compile_time_execution_problems.md (renamed from compile_time_execution_problems.md) | 0 | ||||
| -rw-r--r-- | misc/lib_maker_clang.bat | 11 | ||||
| -rw-r--r-- | misc/libs.txt (renamed from libs.txt) | 0 | ||||
| -rw-r--r-- | misc/logo-slim.png (renamed from logo-slim.png) | bin | 251710 -> 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.bat | 4 | ||||
| -rw-r--r-- | src/array.c | 10 | ||||
| -rw-r--r-- | src/build_settings.c | 2 | ||||
| -rw-r--r-- | src/check_decl.c | 60 | ||||
| -rw-r--r-- | src/check_expr.c | 305 | ||||
| -rw-r--r-- | src/check_stmt.c | 229 | ||||
| -rw-r--r-- | src/checker.c | 88 | ||||
| -rw-r--r-- | src/entity.c | 27 | ||||
| -rw-r--r-- | src/exact_value.c | 98 | ||||
| -rw-r--r-- | src/gb/gb.h | 438 | ||||
| -rw-r--r-- | src/ir.c | 1156 | ||||
| -rw-r--r-- | src/ir_print.c | 20 | ||||
| -rw-r--r-- | src/main.c | 9 | ||||
| -rw-r--r-- | src/parser.c | 222 | ||||
| -rw-r--r-- | src/ssa.c | 2269 | ||||
| -rw-r--r-- | src/ssa_op.c | 277 | ||||
| -rw-r--r-- | src/tokenizer.c | 36 | ||||
| -rw-r--r-- | src/types.c | 44 | ||||
| -rw-r--r-- | src/unicode.c | 1 | ||||
| -rw-r--r-- | src/utf8proc/utf8proc.c | 110 | ||||
| -rw-r--r-- | src/utf8proc/utf8proc.h | 104 | ||||
| -rw-r--r-- | src/utf8proc/utf8proc_data.c | 25 |
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 @@ -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 Binary files differdeleted file mode 100644 index a7bb7cc25..000000000 --- a/bin/llc.exe +++ /dev/null diff --git a/bin/lli.exe b/bin/lli.exe Binary files differdeleted file mode 100644 index 7691672dc..000000000 --- a/bin/lli.exe +++ /dev/null diff --git a/bin/opt.exe b/bin/opt.exe Binary files differdeleted file mode 100644 index 9b34c9ac8..000000000 --- a/bin/opt.exe +++ /dev/null @@ -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 Binary files differindex 2b70e6a0c..2b70e6a0c 100644 --- a/logo-slim.png +++ b/misc/logo-slim.png diff --git a/roadmap.md b/misc/roadmap.md index 83fbbb695..83fbbb695 100644 --- a/roadmap.md +++ b/misc/roadmap.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; @@ -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(¶ms, 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(¶ms, 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) |