diff --git a/.travis.yml b/.travis.yml index 301d7871d0..04e455a285 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,6 +5,7 @@ rust: - nightly matrix: allow_failures: + - rust: beta - rust: nightly dist: trusty sudo: false diff --git a/README.rst b/README.rst index 445fbf3c06..28f2250ace 100644 --- a/README.rst +++ b/README.rst @@ -6,23 +6,52 @@ Cretonne is a low-level retargetable code generator. It translates a `target-ind intermediate representation `_ into executable machine code. -*This is a work in progress that is not yet functional.* - .. image:: https://readthedocs.org/projects/cretonne/badge/?version=latest :target: https://cretonne.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status -.. image:: https://travis-ci.org/Cretonne/cretonne.svg?branch=master - :target: https://travis-ci.org/Cretonne/cretonne +.. image:: https://travis-ci.org/cretonne/cretonne.svg?branch=master + :target: https://travis-ci.org/cretonne/cretonne :alt: Build Status -.. image:: https://badges.gitter.im/Cretonne/cretonne.png - :target: https://gitter.im/Cretonne/Lobby/~chat +.. image:: https://badges.gitter.im/cretonne/cretonne.png + :target: https://gitter.im/cretonne/Lobby/~chat :alt: Gitter chat For more information, see `the documentation `_. +Status +------ + +Cretonne currently supports enough functionality to run a wide variety of +programs, including all the functionality needed to execute WebAssembly MVP +functions, although it needs to be used within an external WebAssembly +embedding to be part of a complete WebAssembly implementation. + +The x86-64 backend is currently the most complete and stable; other +architectures are in various stages of development. Cretonne currently supports +the System V AMD64 ABI calling convention used on many platforms, but does not +yet support the Windows x64 calling convention. The performance of code +produced by Cretonne is not yet impressive, though we have plans to fix that. + +The core codegen crates have minimal dependencies, and do not require any host +floating-point support. Support for `no_std` mode in the core codegen crates is +`in development `_. + +Cretonne does not yet perform mitigations for Spectre or related security +issues, though it may do so in the future. It does not currently make any +security-relevant instruction timing guarantees. It has seen a fair amount +of testing and fuzzing, although more work is needed before it would be +ready for a production use case. + +Cretonne's APIs are not yet stable. + +Cretonne currently supports Rust 1.22.1 and later. We intend to always support +the latest *stable* Rust. And, we currently support the version of Rust in the +latest Ubuntu LTS, although whether we will always do so is not yet determined. +Cretonne requires Python 2.7 or Python 3 to build. + Planned uses ------------ diff --git a/cranelift/.gitignore b/cranelift/.gitignore index a481ff48e8..041b7ad3a8 100644 --- a/cranelift/.gitignore +++ b/cranelift/.gitignore @@ -10,3 +10,4 @@ Cargo.lock cretonne.dbg* .mypy_cache rusty-tags.* +docs/_build diff --git a/cranelift/Cargo.toml b/cranelift/Cargo.toml index 947b50b44a..9c4c1608ff 100644 --- a/cranelift/Cargo.toml +++ b/cranelift/Cargo.toml @@ -1,11 +1,11 @@ [package] name = "cretonne-tools" authors = ["The Cretonne Project Developers"] -version = "0.4.1" -description = "Binaries for testing the Cretonne library" +version = "0.5.0" +description = "Binaries for testing the Cretonne libraries" license = "Apache-2.0" documentation = "https://cretonne.readthedocs.io/" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" publish = false [[bin]] @@ -13,12 +13,16 @@ name = "cton-util" path = "src/cton-util.rs" [dependencies] -cretonne = { path = "lib/cretonne", version = "0.4.1" } -cretonne-reader = { path = "lib/reader", version = "0.4.1" } -cretonne-frontend = { path = "lib/frontend", version = "0.4.1" } -cretonne-wasm = { path = "lib/wasm", version = "0.4.1" } -cretonne-native = { path = "lib/native", version = "0.4.1" } -cretonne-filetests = { path = "lib/filetests", version = "0.4.1" } +cretonne-codegen = { path = "lib/codegen", version = "0.5.0" } +cretonne-reader = { path = "lib/reader", version = "0.5.0" } +cretonne-frontend = { path = "lib/frontend", version = "0.5.0" } +cretonne-wasm = { path = "lib/wasm", version = "0.5.0" } +cretonne-native = { path = "lib/native", version = "0.5.0" } +cretonne-filetests = { path = "lib/filetests", version = "0.5.0" } +cretonne-module = { path = "lib/module", version = "0.5.0" } +cretonne-faerie = { path = "lib/faerie", version = "0.5.0" } +cretonne-simplejit = { path = "lib/simplejit", version = "0.5.0" } +cretonne = { path = "lib/umbrella", version = "0.5.0" } filecheck = "0.2.1" docopt = "0.8.0" serde = "1.0.8" @@ -30,7 +34,7 @@ term = "0.5.1" # Enable debug assertions and parallel compilation when building cretonne-tools # since they are for testing and development mostly. This doesn't affect the -# flags used to build the Cretonne crate when used as a dependency. +# flags used to build the cretonne-* crates when used as a dependency. [profile.release] opt-level = 2 debug-assertions = true diff --git a/cranelift/docs/Makefile b/cranelift/docs/Makefile index 335779f1f3..6ac763bdd3 100644 --- a/cranelift/docs/Makefile +++ b/cranelift/docs/Makefile @@ -14,7 +14,7 @@ help: @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) autohtml: html - $(SPHINXABUILD) -z ../lib/cretonne/meta --ignore '.*' -b html -E $(ALLSPHINXOPTS) $(BUILDDIR)/html + $(SPHINXABUILD) -z ../lib/codegen/meta --ignore '.*' -b html -E $(ALLSPHINXOPTS) $(BUILDDIR)/html .PHONY: help Makefile diff --git a/cranelift/docs/callex.cton b/cranelift/docs/callex.cton index 837f9ea6e7..26abda55b4 100644 --- a/cranelift/docs/callex.cton +++ b/cranelift/docs/callex.cton @@ -1,7 +1,7 @@ test verifier function %gcd(i32 uext, i32 uext) -> i32 uext system_v { - fn1 = function %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext + fn1 = %divmod(i32 uext, i32 uext) -> i32 uext, i32 uext ebb1(v1: i32, v2: i32): brz v2, ebb2 diff --git a/cranelift/docs/compare-llvm.rst b/cranelift/docs/compare-llvm.rst index 4a622dbeda..abc47caaa3 100644 --- a/cranelift/docs/compare-llvm.rst +++ b/cranelift/docs/compare-llvm.rst @@ -6,8 +6,8 @@ Cretonne compared to LLVM a set of C++ libraries. It can be used to build both JIT compilers and static compilers like `Clang `_, and it is deservedly very popular. `Chris Lattner's chapter about LLVM -`_ in the `Architecture of Open Source -Applications `_ book gives an excellent +`_ in the `Architecture of Open Source +Applications `_ book gives an excellent overview of the architecture and design of LLVM. Cretonne and LLVM are superficially similar projects, so it is worth @@ -174,7 +174,7 @@ is emitted, there are opcodes for every native instruction that can be generated. There is a lot of overlap between different ISAs, so for example the :cton:inst:`iadd_imm` instruction is used by every ISA that can add an immediate integer to a register. A simple RISC ISA like RISC-V can be defined -with only shared instructions, while an Intel ISA needs a number of specific +with only shared instructions, while x86 needs a number of specific instructions to model addressing modes. Undefined behavior diff --git a/cranelift/docs/conf.py b/cranelift/docs/conf.py index 20cfd32f91..b2c1f14f97 100644 --- a/cranelift/docs/conf.py +++ b/cranelift/docs/conf.py @@ -23,7 +23,7 @@ sys.path.insert(0, os.path.abspath('.')) # Also add the meta directory to sys.path so autodoc can find the Cretonne meta # language definitions. -sys.path.insert(0, os.path.abspath('../lib/cretonne/meta')) +sys.path.insert(0, os.path.abspath('../lib/codegen/meta')) # -- General configuration ------------------------------------------------ diff --git a/cranelift/docs/langref.rst b/cranelift/docs/langref.rst index edcc039c86..33fc1f0694 100644 --- a/cranelift/docs/langref.rst +++ b/cranelift/docs/langref.rst @@ -48,8 +48,7 @@ A ``.cton`` file consists of a sequence of independent function definitions: .. productionlist:: function_list : { function } - function : function_spec "{" preamble function_body "}" - function_spec : "function" function_name signature + function : "function" function_name signature "{" preamble function_body "}" preamble : { preamble_decl } function_body : { extended_basic_block } @@ -75,7 +74,7 @@ SSA values: In the entry block, ``v4`` is the initial value. In the loop block variable during each iteration. Finally, ``v12`` is computed as the induction variable value for the next iteration. -The `cton_frontend` crate contains utilities for translating from programs +The `cretonne_frontend` crate contains utilities for translating from programs containing multiple assignments to the same variables into SSA form for Cretonne :term:`IR`. @@ -409,10 +408,14 @@ compilers. Functions that are called directly must be declared in the :term:`function preamble`: -.. inst:: FN = function NAME signature +.. inst:: FN = [colocated] NAME signature Declare a function so it can be called directly. + If the colocated keyword is present, the symbol's definition will be + defined along with the current function, such that it can use more + efficient addressing. + :arg NAME: Name of the function, passed to the linker for resolution. :arg signature: Function signature. See below. :result FN: A function identifier that can be used with :inst:`call`. @@ -570,13 +573,17 @@ runtime data structures. variable. :result GV: Global variable. -.. inst:: GV = globalsym name +.. inst:: GV = [colocated] globalsym name Declare a global variable at a symbolic address. The address of GV is symbolic and will be assigned a relocation, so that it can be resolved by a later linking phase. + If the colocated keyword is present, the symbol's definition will be + defined along with the current function, such that it can use more + efficient addressing. + :arg name: External name. :result GV: Global variable. @@ -998,20 +1005,20 @@ ISA-specific instructions Target ISAs can define supplemental instructions that do not make sense to support generally. -Intel +x86 ----- -Instructions that can only be used by the Intel target ISA. +Instructions that can only be used by the x86 target ISA. -.. autoinst:: isa.intel.instructions.sdivmodx -.. autoinst:: isa.intel.instructions.udivmodx -.. autoinst:: isa.intel.instructions.cvtt2si -.. autoinst:: isa.intel.instructions.fmin -.. autoinst:: isa.intel.instructions.fmax -.. autoinst:: isa.intel.instructions.bsf -.. autoinst:: isa.intel.instructions.bsr -.. autoinst:: isa.intel.instructions.push -.. autoinst:: isa.intel.instructions.pop +.. autoinst:: isa.x86.instructions.sdivmodx +.. autoinst:: isa.x86.instructions.udivmodx +.. autoinst:: isa.x86.instructions.cvtt2si +.. autoinst:: isa.x86.instructions.fmin +.. autoinst:: isa.x86.instructions.fmax +.. autoinst:: isa.x86.instructions.bsf +.. autoinst:: isa.x86.instructions.bsr +.. autoinst:: isa.x86.instructions.push +.. autoinst:: isa.x86.instructions.pop Instruction groups ================== @@ -1023,7 +1030,7 @@ group. Target ISAs may define further instructions in their own instruction groups: -.. autoinstgroup:: isa.intel.instructions.GROUP +.. autoinstgroup:: isa.x86.instructions.GROUP Implementation limits ===================== diff --git a/cranelift/docs/metaref.rst b/cranelift/docs/metaref.rst index 6f23647b0a..134628a8b1 100644 --- a/cranelift/docs/metaref.rst +++ b/cranelift/docs/metaref.rst @@ -11,7 +11,7 @@ domain specific language embedded in Python. This document describes the Python modules that form the embedded DSL. The meta language descriptions are Python modules under the -:file:`lib/cretonne/meta` directory. The descriptions are processed in two +:file:`lib/codegen/meta` directory. The descriptions are processed in two steps: 1. The Python modules are imported. This has the effect of building static data @@ -23,8 +23,8 @@ steps: constant tables. The main driver for this source code generation process is the -:file:`lib/cretonne/meta/build.py` script which is invoked as part of the build -process if anything in the :file:`lib/cretonne/meta` directory has changed +:file:`lib/codegen/meta/build.py` script which is invoked as part of the build +process if anything in the :file:`lib/codegen/meta` directory has changed since the last build. @@ -38,7 +38,7 @@ of code generation. Each setting is defined in the meta language so a compact and consistent Rust representation can be generated. Shared settings are defined in the :mod:`base.settings` module. Some settings are specific to a target ISA, and defined in a :file:`settings.py` module under the appropriate -:file:`lib/cretonne/meta/isa/*` directory. +:file:`lib/codegen/meta/isa/*` directory. Settings can take boolean on/off values, small numbers, or explicitly enumerated symbolic values. Each type is represented by a sub-class of :class:`Setting`: @@ -400,7 +400,7 @@ Fixed register operands ----------------------- Some instructions use hard-coded input and output registers for some value -operands. An example is the ``pblendvb`` Intel SSE instruction which takes one +operands. An example is the ``pblendvb`` x86 SSE instruction which takes one of its three value operands in the hard-coded ``%xmm0`` register:: XMM0 = FPR[0] @@ -433,13 +433,13 @@ architectures. Each ISA is represented by a :py:class:`cdsl.isa.TargetISA` insta .. autoclass:: TargetISA The definitions for each supported target live in a package under -:file:`lib/cretonne/meta/isa`. +:file:`lib/codegen/meta/isa`. .. automodule:: isa :members: .. automodule:: isa.riscv -.. automodule:: isa.intel +.. automodule:: isa.x86 .. automodule:: isa.arm32 .. automodule:: isa.arm64 diff --git a/cranelift/docs/regalloc.rst b/cranelift/docs/regalloc.rst index 74bd6e8575..a87753a34f 100644 --- a/cranelift/docs/regalloc.rst +++ b/cranelift/docs/regalloc.rst @@ -79,7 +79,7 @@ Different register banks Instructions with fixed operands Some instructions use a fixed register for an operand. This happens on the - Intel ISAs: + x86 ISAs: - Dynamic shift and rotate instructions take the shift amount in CL. - Division instructions use RAX and RDX for both input and output operands. @@ -109,7 +109,7 @@ ABI boundaries Aliasing registers Different registers sometimes share the same bits in the register bank. This can make it difficult to measure register pressure. For example, the - Intel registers RAX, EAX, AX, AL, and AH overlap. + x86 registers RAX, EAX, AX, AL, and AH overlap. If only one of the aliasing registers can be used at a time, the aliasing doesn't cause problems since the registers can simply be counted as one diff --git a/cranelift/docs/testing.rst b/cranelift/docs/testing.rst index db7efb1da1..b2ea827075 100644 --- a/cranelift/docs/testing.rst +++ b/cranelift/docs/testing.rst @@ -51,7 +51,7 @@ tested:: //! //! # Example //! ``` - //! use cretonne::settings::{self, Configurable}; + //! use cretonne_codegen::settings::{self, Configurable}; //! //! let mut b = settings::builder(); //! b.set("opt_level", "fastest"); @@ -73,9 +73,9 @@ test. These tests are usually found in the :file:`tests` top-level directory where they have access to all the crates in the Cretonne repository. The -:file:`lib/cretonne` and :file:`lib/reader` crates have no external +:file:`lib/codegen` and :file:`lib/reader` crates have no external dependencies, which can make testing tedious. Integration tests that don't need -to depend on other crates can be placed in :file:`lib/cretonne/tests` and +to depend on other crates can be placed in :file:`lib/codegen/tests` and :file:`lib/reader/tests`. File tests @@ -109,7 +109,7 @@ header: isa_spec : "isa" isa_name { `option` } "\n" The options given on the ``isa`` line modify the ISA-specific settings defined in -:file:`lib/cretonne/meta/isa/*/settings.py`. +:file:`lib/codegen/meta/isa/*/settings.py`. All types of tests allow shared Cretonne settings to be modified: @@ -119,7 +119,7 @@ All types of tests allow shared Cretonne settings to be modified: option : flag | setting "=" value The shared settings available for all target ISAs are defined in -:file:`lib/cretonne/meta/base/settings.py`. +:file:`lib/codegen/meta/base/settings.py`. The ``set`` lines apply settings cumulatively:: diff --git a/cranelift/filetests/isa/intel/binary64-pic.cton b/cranelift/filetests/isa/intel/binary64-pic.cton deleted file mode 100644 index 3129bd9563..0000000000 --- a/cranelift/filetests/isa/intel/binary64-pic.cton +++ /dev/null @@ -1,54 +0,0 @@ -; binary emission of 64-bit code. -test binemit -set is_64bit -set is_compressed -set is_pic -isa intel haswell - -; The binary encodings can be verified with the command: -; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary64-pic.cton | llvm-mc -show-encoding -triple=x86_64 -; - -; Tests for i64 instructions. -function %I64() { - sig0 = () - fn0 = function %foo() - - gv0 = globalsym %some_gv - - ; Use incoming_arg stack slots because they won't be relocated by the frame - ; layout. - ss0 = incoming_arg 8, offset 0 - ss1 = incoming_arg 1024, offset -1024 - ss2 = incoming_arg 1024, offset -2048 - ss3 = incoming_arg 8, offset -2056 - -ebb0: - - ; asm: call foo@PLT - call fn0() ; bin: e8 PLTRel4(%foo-4) 00000000 - - ; asm: mov 0x0(%rip), %rax - [-,%rax] v0 = func_addr.i64 fn0 ; bin: 48 8b 05 GOTPCRel4(%foo-4) 00000000 - ; asm: mov 0x0(%rip), %rsi - [-,%rsi] v1 = func_addr.i64 fn0 ; bin: 48 8b 35 GOTPCRel4(%foo-4) 00000000 - ; asm: mov 0x0(%rip), %r10 - [-,%r10] v2 = func_addr.i64 fn0 ; bin: 4c 8b 15 GOTPCRel4(%foo-4) 00000000 - - ; asm: call *%rax - call_indirect sig0, v0() ; bin: ff d0 - ; asm: call *%rsi - call_indirect sig0, v1() ; bin: ff d6 - ; asm: call *%r10 - call_indirect sig0, v2() ; bin: 41 ff d2 - - ; asm: mov 0x0(%rip), %rcx - [-,%rcx] v3 = globalsym_addr.i64 gv0 ; bin: 48 8b 0d GOTPCRel4(%some_gv-4) 00000000 - ; asm: mov 0x0(%rip), %rsi - [-,%rsi] v4 = globalsym_addr.i64 gv0 ; bin: 48 8b 35 GOTPCRel4(%some_gv-4) 00000000 - ; asm: mov 0x0(%rip), %r10 - [-,%r10] v5 = globalsym_addr.i64 gv0 ; bin: 4c 8b 15 GOTPCRel4(%some_gv-4) 00000000 - - return -} diff --git a/cranelift/filetests/isa/intel/prologue-epilogue.cton b/cranelift/filetests/isa/intel/prologue-epilogue.cton deleted file mode 100644 index cd774fe6bd..0000000000 --- a/cranelift/filetests/isa/intel/prologue-epilogue.cton +++ /dev/null @@ -1,32 +0,0 @@ -test compile -set is_64bit -set is_compressed -isa intel haswell - -function %foo() { - ss0 = explicit_slot 168 -ebb0: - return -} - -; check: function %foo(i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v { -; nextln: ss0 = explicit_slot 168, offset -224 -; nextln: ss1 = incoming_arg 56, offset -56 -; check: ebb0(v0: i64 [%rbp], v1: i64 [%rbx], v2: i64 [%r12], v3: i64 [%r13], v4: i64 [%r14], v5: i64 [%r15]): -; nextln: x86_push v0 -; nextln: copy_special %rsp -> %rbp -; nextln: x86_push v1 -; nextln: x86_push v2 -; nextln: x86_push v3 -; nextln: x86_push v4 -; nextln: x86_push v5 -; nextln: adjust_sp_imm -168 -; nextln: adjust_sp_imm 168 -; nextln: v11 = x86_pop.i64 -; nextln: v10 = x86_pop.i64 -; nextln: v9 = x86_pop.i64 -; nextln: v8 = x86_pop.i64 -; nextln: v7 = x86_pop.i64 -; nextln: v6 = x86_pop.i64 -; nextln: return v6, v7, v8, v9, v10, v11 -; nextln: } diff --git a/cranelift/filetests/isa/riscv/binary32.cton b/cranelift/filetests/isa/riscv/binary32.cton index 459d9d7419..7837672bcc 100644 --- a/cranelift/filetests/isa/riscv/binary32.cton +++ b/cranelift/filetests/isa/riscv/binary32.cton @@ -4,7 +4,7 @@ isa riscv function %RV32I(i32 link [%x1]) -> i32 link [%x1] { sig0 = () - fn0 = function %foo() + fn0 = %foo() ebb0(v9999: i32): [-,%x10] v1 = iconst.i32 1 diff --git a/cranelift/filetests/isa/riscv/legalize-abi.cton b/cranelift/filetests/isa/riscv/legalize-abi.cton index 44865120ea..df60b91f81 100644 --- a/cranelift/filetests/isa/riscv/legalize-abi.cton +++ b/cranelift/filetests/isa/riscv/legalize-abi.cton @@ -17,8 +17,8 @@ ebb0(v0: i64): } function %split_call_arg(i32) { - fn1 = function %foo(i64) - fn2 = function %foo(i32, i64) + fn1 = %foo(i64) + fn2 = %foo(i32, i64) ebb0(v0: i32): v1 = uextend.i64 v0 call fn1(v1) @@ -30,7 +30,7 @@ ebb0(v0: i32): } function %split_ret_val() { - fn1 = function %foo() -> i64 + fn1 = %foo() -> i64 ebb0: v1 = call fn1() ; check: ebb0($(link=$V): i32): @@ -45,7 +45,7 @@ ebb1(v10: i64): ; First return value is fine, second one is expanded. function %split_ret_val2() { - fn1 = function %foo() -> i32, i64 + fn1 = %foo() -> i32, i64 ebb0: v1, v2 = call fn1() ; check: ebb0($(link=$V): i32): @@ -70,7 +70,7 @@ ebb0(v1: i8, v2: i8, v3: i8): ; Function produces single return value, still need to copy. function %ext_ret_val() { - fn1 = function %foo() -> i8 sext + fn1 = %foo() -> i8 sext ebb0: v1 = call fn1() ; check: ebb0($V: i32): @@ -124,7 +124,7 @@ ebb0(v0: i32, v1: f32x2): ; Call a function that takes arguments on the stack. function %stack_args(i32) { ; check: $(ss0=$SS) = outgoing_arg 4 - fn1 = function %foo(i64, i64, i64, i64, i32) + fn1 = %foo(i64, i64, i64, i64, i32) ebb0(v0: i32): v1 = iconst.i64 1 call fn1(v1, v1, v1, v1, v0) diff --git a/cranelift/filetests/isa/riscv/parse-encoding.cton b/cranelift/filetests/isa/riscv/parse-encoding.cton index 0fc0879f38..b8220b1688 100644 --- a/cranelift/filetests/isa/riscv/parse-encoding.cton +++ b/cranelift/filetests/isa/riscv/parse-encoding.cton @@ -27,9 +27,9 @@ function %parse_encoding(i32 [%x5]) -> i32 [%x10] { ; check: sig5 = () -> f32 [0] system_v ; function + signature - fn0 = function %bar(i32 [%x10]) -> b1 [%x10] system_v + fn0 = %bar(i32 [%x10]) -> b1 [%x10] system_v ; check: sig6 = (i32 [%x10]) -> b1 [%x10] system_v - ; nextln: fn0 = sig6 %bar + ; nextln: fn0 = %bar sig6 ebb0(v0: i32): return v0 diff --git a/cranelift/filetests/isa/riscv/verify-encoding.cton b/cranelift/filetests/isa/riscv/verify-encoding.cton index 725b9e5744..1aaedf1c89 100644 --- a/cranelift/filetests/isa/riscv/verify-encoding.cton +++ b/cranelift/filetests/isa/riscv/verify-encoding.cton @@ -2,7 +2,7 @@ test verifier isa riscv function %RV32I(i32 link [%x1]) -> i32 link [%x1] { - fn0 = function %foo() + fn0 = %foo() ebb0(v9999: i32): ; iconst.i32 needs legalizing, so it should throw a @@ -11,7 +11,7 @@ ebb0(v9999: i32): } function %RV32I(i32 link [%x1]) -> i32 link [%x1] { - fn0 = function %foo() + fn0 = %foo() ebb0(v9999: i32): v1 = iconst.i32 1 diff --git a/cranelift/filetests/isa/intel/abi-bool.cton b/cranelift/filetests/isa/x86/abi-bool.cton similarity index 95% rename from cranelift/filetests/isa/intel/abi-bool.cton rename to cranelift/filetests/isa/x86/abi-bool.cton index 6a53cdbb3c..48ac976a84 100644 --- a/cranelift/filetests/isa/intel/abi-bool.cton +++ b/cranelift/filetests/isa/x86/abi-bool.cton @@ -1,6 +1,6 @@ test compile set is_64bit=1 -isa intel haswell +isa x86 haswell function %foo(i64, i64, i64, i32) -> b1 system_v { ebb3(v0: i64, v1: i64, v2: i64, v3: i32): diff --git a/cranelift/filetests/isa/intel/abi32.cton b/cranelift/filetests/isa/x86/abi32.cton similarity index 97% rename from cranelift/filetests/isa/intel/abi32.cton rename to cranelift/filetests/isa/x86/abi32.cton index b949af16f7..04b8d2ec6f 100644 --- a/cranelift/filetests/isa/intel/abi32.cton +++ b/cranelift/filetests/isa/x86/abi32.cton @@ -1,6 +1,6 @@ ; Test the legalization of function signatures. test legalizer -isa intel +isa x86 ; regex: V=v\d+ diff --git a/cranelift/filetests/isa/intel/abi64.cton b/cranelift/filetests/isa/x86/abi64.cton similarity index 97% rename from cranelift/filetests/isa/intel/abi64.cton rename to cranelift/filetests/isa/x86/abi64.cton index 8aa6a49b0f..40321f90fb 100644 --- a/cranelift/filetests/isa/intel/abi64.cton +++ b/cranelift/filetests/isa/x86/abi64.cton @@ -1,7 +1,7 @@ ; Test the legalization of function signatures. test legalizer set is_64bit -isa intel +isa x86 ; regex: V=v\d+ @@ -21,7 +21,7 @@ ebb0: function %pass_stack_int64(i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 vmctx) spiderwasm { sig0 = (i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64, i64 vmctx) spiderwasm - fn0 = sig0 u0:0 + fn0 = u0:0 sig0 ebb0(v0: i64, v1: i64, v2: i64, v3: i64, v4: i64, v5: i64, v6: i64, v7: i64, v8: i64, v9: i64, v10: i64, v11: i64, v12: i64, v13: i64, v14: i64, v15: i64, v16: i64, v17: i64, v18: i64, v19: i64, v20: i64): call fn0(v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20) diff --git a/cranelift/filetests/isa/intel/allones_funcaddrs32.cton b/cranelift/filetests/isa/x86/allones_funcaddrs32.cton similarity index 77% rename from cranelift/filetests/isa/intel/allones_funcaddrs32.cton rename to cranelift/filetests/isa/x86/allones_funcaddrs32.cton index 90af70fe5b..c4c078470b 100644 --- a/cranelift/filetests/isa/intel/allones_funcaddrs32.cton +++ b/cranelift/filetests/isa/x86/allones_funcaddrs32.cton @@ -2,17 +2,17 @@ test binemit set is_compressed set allones_funcaddrs -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/allones_funcaddrs32.cton | llvm-mc -show-encoding -triple=i386 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/allones_funcaddrs32.cton | llvm-mc -show-encoding -triple=i386 ; ; Tests from binary32.cton affected by allones_funcaddrs. function %I32() { sig0 = () - fn0 = function %foo() + fn0 = %foo() ebb0: diff --git a/cranelift/filetests/isa/intel/allones_funcaddrs64.cton b/cranelift/filetests/isa/x86/allones_funcaddrs64.cton similarity index 81% rename from cranelift/filetests/isa/intel/allones_funcaddrs64.cton rename to cranelift/filetests/isa/x86/allones_funcaddrs64.cton index 7be06c3963..ca3cf1ab69 100644 --- a/cranelift/filetests/isa/intel/allones_funcaddrs64.cton +++ b/cranelift/filetests/isa/x86/allones_funcaddrs64.cton @@ -3,17 +3,17 @@ test binemit set is_64bit set is_compressed set allones_funcaddrs -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/allones_funcaddrs64.cton | llvm-mc -show-encoding -triple=x86_64 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/allones_funcaddrs64.cton | llvm-mc -show-encoding -triple=x86_64 ; ; Tests from binary64.cton affected by allones_funcaddrs. function %I64() { sig0 = () - fn0 = function %foo() + fn0 = %foo() ebb0: diff --git a/cranelift/filetests/isa/intel/baseline_clz_ctz_popcount.cton b/cranelift/filetests/isa/x86/baseline_clz_ctz_popcount.cton similarity index 98% rename from cranelift/filetests/isa/intel/baseline_clz_ctz_popcount.cton rename to cranelift/filetests/isa/x86/baseline_clz_ctz_popcount.cton index b87815aa12..c79de42317 100644 --- a/cranelift/filetests/isa/intel/baseline_clz_ctz_popcount.cton +++ b/cranelift/filetests/isa/x86/baseline_clz_ctz_popcount.cton @@ -1,7 +1,7 @@ test compile set is_64bit -isa intel baseline +isa x86 baseline ; clz/ctz on 64 bit operands diff --git a/cranelift/filetests/isa/intel/baseline_clz_ctz_popcount_encoding.cton b/cranelift/filetests/isa/x86/baseline_clz_ctz_popcount_encoding.cton similarity index 94% rename from cranelift/filetests/isa/intel/baseline_clz_ctz_popcount_encoding.cton rename to cranelift/filetests/isa/x86/baseline_clz_ctz_popcount_encoding.cton index 2e552b7145..f69efd573a 100644 --- a/cranelift/filetests/isa/intel/baseline_clz_ctz_popcount_encoding.cton +++ b/cranelift/filetests/isa/x86/baseline_clz_ctz_popcount_encoding.cton @@ -2,11 +2,11 @@ test binemit set is_64bit set is_compressed -isa intel baseline +isa x86 baseline ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/baseline_clz_ctz_popcount_encoding.cton | llvm-mc -show-encoding -triple=x86_64 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/baseline_clz_ctz_popcount_encoding.cton | llvm-mc -show-encoding -triple=x86_64 ; function %Foo() { diff --git a/cranelift/filetests/isa/intel/binary32-float.cton b/cranelift/filetests/isa/x86/binary32-float.cton similarity index 99% rename from cranelift/filetests/isa/intel/binary32-float.cton rename to cranelift/filetests/isa/x86/binary32-float.cton index 4477c4d8d3..a94fff71c1 100644 --- a/cranelift/filetests/isa/intel/binary32-float.cton +++ b/cranelift/filetests/isa/x86/binary32-float.cton @@ -1,10 +1,10 @@ ; Binary emission of 32-bit floating point code. test binemit -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary32-float.cton | llvm-mc -show-encoding -triple=i386 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/binary32-float.cton | llvm-mc -show-encoding -triple=i386 ; function %F32() { diff --git a/cranelift/filetests/isa/intel/binary32.cton b/cranelift/filetests/isa/x86/binary32.cton similarity index 99% rename from cranelift/filetests/isa/intel/binary32.cton rename to cranelift/filetests/isa/x86/binary32.cton index 2567fbe88c..842f941779 100644 --- a/cranelift/filetests/isa/intel/binary32.cton +++ b/cranelift/filetests/isa/x86/binary32.cton @@ -1,16 +1,16 @@ ; binary emission of x86-32 code. test binemit set is_compressed -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary32.cton | llvm-mc -show-encoding -triple=i386 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/binary32.cton | llvm-mc -show-encoding -triple=i386 ; function %I32() { sig0 = () - fn0 = function %foo() + fn0 = %foo() gv0 = globalsym %some_gv @@ -352,7 +352,7 @@ ebb0: [-,%rsi] v351 = bint.i32 v301 ; bin: 0f b6 f2 ; asm: call foo - call fn0() ; bin: e8 PCRel4(%foo) 00000000 + call fn0() ; bin: e8 PCRel4(%foo-4) 00000000 ; asm: movl $0, %ecx [-,%rcx] v400 = func_addr.i32 fn0 ; bin: b9 Abs4(%foo) 00000000 diff --git a/cranelift/filetests/isa/intel/binary64-float.cton b/cranelift/filetests/isa/x86/binary64-float.cton similarity index 99% rename from cranelift/filetests/isa/intel/binary64-float.cton rename to cranelift/filetests/isa/x86/binary64-float.cton index 7053a1809e..df910941cd 100644 --- a/cranelift/filetests/isa/intel/binary64-float.cton +++ b/cranelift/filetests/isa/x86/binary64-float.cton @@ -2,11 +2,11 @@ test binemit set is_64bit set is_compressed -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary64-float.cton | llvm-mc -show-encoding -triple=x86_64 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/binary64-float.cton | llvm-mc -show-encoding -triple=x86_64 ; function %F32() { diff --git a/cranelift/filetests/isa/x86/binary64-pic.cton b/cranelift/filetests/isa/x86/binary64-pic.cton new file mode 100644 index 0000000000..cc592e0188 --- /dev/null +++ b/cranelift/filetests/isa/x86/binary64-pic.cton @@ -0,0 +1,84 @@ +; binary emission of 64-bit code. +test binemit +set is_64bit +set is_compressed +set is_pic +isa x86 haswell + +; The binary encodings can be verified with the command: +; +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/binary64-pic.cton | llvm-mc -show-encoding -triple=x86_64 +; + +; Tests for i64 instructions. +function %I64() { + sig0 = () + fn0 = %foo() + fn1 = colocated %bar() + + gv0 = globalsym %some_gv + gv1 = globalsym colocated %some_gv + + ; Use incoming_arg stack slots because they won't be relocated by the frame + ; layout. + ss0 = incoming_arg 8, offset 0 + ss1 = incoming_arg 1024, offset -1024 + ss2 = incoming_arg 1024, offset -2048 + ss3 = incoming_arg 8, offset -2056 + +ebb0: + + ; Colocated functions. + + ; asm: call foo + call fn1() ; bin: e8 PCRel4(%bar-4) 00000000 + + ; asm: lea 0x0(%rip), %rax + [-,%rax] v0 = func_addr.i64 fn1 ; bin: 48 8d 05 PCRel4(%bar-4) 00000000 + ; asm: lea 0x0(%rip), %rsi + [-,%rsi] v1 = func_addr.i64 fn1 ; bin: 48 8d 35 PCRel4(%bar-4) 00000000 + ; asm: lea 0x0(%rip), %r10 + [-,%r10] v2 = func_addr.i64 fn1 ; bin: 4c 8d 15 PCRel4(%bar-4) 00000000 + + ; asm: call *%rax + call_indirect sig0, v0() ; bin: ff d0 + ; asm: call *%rsi + call_indirect sig0, v1() ; bin: ff d6 + ; asm: call *%r10 + call_indirect sig0, v2() ; bin: 41 ff d2 + + ; Non-colocated functions. + + ; asm: call foo@PLT + call fn0() ; bin: e8 PLTRel4(%foo-4) 00000000 + + ; asm: mov 0x0(%rip), %rax + [-,%rax] v100 = func_addr.i64 fn0 ; bin: 48 8b 05 GOTPCRel4(%foo-4) 00000000 + ; asm: mov 0x0(%rip), %rsi + [-,%rsi] v101 = func_addr.i64 fn0 ; bin: 48 8b 35 GOTPCRel4(%foo-4) 00000000 + ; asm: mov 0x0(%rip), %r10 + [-,%r10] v102 = func_addr.i64 fn0 ; bin: 4c 8b 15 GOTPCRel4(%foo-4) 00000000 + + ; asm: call *%rax + call_indirect sig0, v100() ; bin: ff d0 + ; asm: call *%rsi + call_indirect sig0, v101() ; bin: ff d6 + ; asm: call *%r10 + call_indirect sig0, v102() ; bin: 41 ff d2 + + ; asm: mov 0x0(%rip), %rcx + [-,%rcx] v3 = globalsym_addr.i64 gv0 ; bin: 48 8b 0d GOTPCRel4(%some_gv-4) 00000000 + ; asm: mov 0x0(%rip), %rsi + [-,%rsi] v4 = globalsym_addr.i64 gv0 ; bin: 48 8b 35 GOTPCRel4(%some_gv-4) 00000000 + ; asm: mov 0x0(%rip), %r10 + [-,%r10] v5 = globalsym_addr.i64 gv0 ; bin: 4c 8b 15 GOTPCRel4(%some_gv-4) 00000000 + + ; asm: lea 0x0(%rip), %rcx + [-,%rcx] v6 = globalsym_addr.i64 gv1 ; bin: 48 8d 0d PCRel4(%some_gv-4) 00000000 + ; asm: lea 0x0(%rip), %rsi + [-,%rsi] v7 = globalsym_addr.i64 gv1 ; bin: 48 8d 35 PCRel4(%some_gv-4) 00000000 + ; asm: lea 0x0(%rip), %r10 + [-,%r10] v8 = globalsym_addr.i64 gv1 ; bin: 4c 8d 15 PCRel4(%some_gv-4) 00000000 + + return +} diff --git a/cranelift/filetests/isa/intel/binary64.cton b/cranelift/filetests/isa/x86/binary64.cton similarity index 97% rename from cranelift/filetests/isa/intel/binary64.cton rename to cranelift/filetests/isa/x86/binary64.cton index 1a47dc1cba..faf4fe99ac 100644 --- a/cranelift/filetests/isa/intel/binary64.cton +++ b/cranelift/filetests/isa/x86/binary64.cton @@ -2,17 +2,18 @@ test binemit set is_64bit set is_compressed -isa intel haswell +isa x86 haswell ; The binary encodings can be verified with the command: ; -; sed -ne 's/^ *; asm: *//p' filetests/isa/intel/binary64.cton | llvm-mc -show-encoding -triple=x86_64 +; sed -ne 's/^ *; asm: *//p' filetests/isa/x86/binary64.cton | llvm-mc -show-encoding -triple=x86_64 ; ; Tests for i64 instructions. function %I64() { sig0 = () - fn0 = function %foo() + fn0 = %foo() + fn1 = colocated %bar() gv0 = globalsym %some_gv @@ -473,15 +474,17 @@ ebb0: ; asm: movzbq %dl, %rsi [-,%rsi] v351 = bint.i64 v301 ; bin: 0f b6 f2 - ; asm: call foo - call fn0() ; bin: e8 PCRel4(%foo) 00000000 + ; Colocated functions. - ; asm: movabsq $0, %rcx - [-,%rcx] v400 = func_addr.i64 fn0 ; bin: 48 b9 Abs8(%foo) 0000000000000000 - ; asm: movabsq $0, %rsi - [-,%rsi] v401 = func_addr.i64 fn0 ; bin: 48 be Abs8(%foo) 0000000000000000 - ; asm: movabsq $0, %r10 - [-,%r10] v402 = func_addr.i64 fn0 ; bin: 49 ba Abs8(%foo) 0000000000000000 + ; asm: call bar + ; call fn1() ; bin: e8 PCRel4(%bar-4) 00000000 + + ; asm: lea 0x0(%rip), %rcx + [-,%rcx] v400 = func_addr.i64 fn1 ; bin: 48 8d 0d PCRel4(%bar-4) 00000000 + ; asm: lea 0x0(%rip), %rsi + [-,%rsi] v401 = func_addr.i64 fn1 ; bin: 48 8d 35 PCRel4(%bar-4) 00000000 + ; asm: lea 0x0(%rip), %r10 + [-,%r10] v402 = func_addr.i64 fn1 ; bin: 4c 8d 15 PCRel4(%bar-4) 00000000 ; asm: call *%rcx call_indirect sig0, v400() ; bin: ff d1 @@ -490,6 +493,22 @@ ebb0: ; asm: call *%r10 call_indirect sig0, v402() ; bin: 41 ff d2 + ; Non-colocated functions. Note that there is no non-colocated non-PIC call. + + ; asm: movabsq $0, %rcx + [-,%rcx] v410 = func_addr.i64 fn0 ; bin: 48 b9 Abs8(%foo) 0000000000000000 + ; asm: movabsq $0, %rsi + [-,%rsi] v411 = func_addr.i64 fn0 ; bin: 48 be Abs8(%foo) 0000000000000000 + ; asm: movabsq $0, %r10 + [-,%r10] v412 = func_addr.i64 fn0 ; bin: 49 ba Abs8(%foo) 0000000000000000 + + ; asm: call *%rcx + call_indirect sig0, v410() ; bin: ff d1 + ; asm: call *%rsi + call_indirect sig0, v411() ; bin: ff d6 + ; asm: call *%r10 + call_indirect sig0, v412() ; bin: 41 ff d2 + ; asm: movabsq $-1, %rcx [-,%rcx] v450 = globalsym_addr.i64 gv0 ; bin: 48 b9 Abs8(%some_gv) 0000000000000000 ; asm: movabsq $-1, %rsi @@ -551,9 +570,9 @@ ebb0: [-,%rsi] v517 = sshr_imm v2, 32 ; bin: 48 c1 fe 20 ; asm: sarq $33, %r8 [-,%r8] v518 = sshr_imm v4, 33 ; bin: 49 c1 f8 21 - ; asm: shrl $62, %rsi + ; asm: shrq $62, %rsi [-,%rsi] v519 = ushr_imm v2, 62 ; bin: 48 c1 ee 3e - ; asm: shrl $63, %r8 + ; asm: shrq $63, %r8 [-,%r8] v520 = ushr_imm v4, 63 ; bin: 49 c1 e8 3f @@ -710,7 +729,7 @@ ebb0: ; be done by an instruction shrinking pass. function %I32() { sig0 = () - fn0 = function %foo() + fn0 = %foo() ss0 = incoming_arg 8, offset 0 ss1 = incoming_arg 1024, offset -1024 @@ -1043,7 +1062,7 @@ ebb0: ; asm: setl %bl [-,%rbx] v320 = icmp_imm slt v1, 37 ; bin: 83 f9 25 0f 9c c3 - ; asm: cmpq $100000, %ecx + ; asm: cmpl $100000, %ecx ; asm: setl %bl [-,%rbx] v321 = icmp_imm slt v1, 100000 ; bin: 81 f9 000186a0 0f 9c c3 diff --git a/cranelift/filetests/isa/intel/legalize-custom.cton b/cranelift/filetests/isa/x86/legalize-custom.cton similarity index 98% rename from cranelift/filetests/isa/intel/legalize-custom.cton rename to cranelift/filetests/isa/x86/legalize-custom.cton index 5cb5ac0462..8f719056cd 100644 --- a/cranelift/filetests/isa/intel/legalize-custom.cton +++ b/cranelift/filetests/isa/x86/legalize-custom.cton @@ -1,8 +1,8 @@ ; Test the custom legalizations. test legalizer -isa intel +isa x86 set is_64bit -isa intel +isa x86 ; regex: V=v\d+ ; regex: EBB=ebb\d+ diff --git a/cranelift/filetests/isa/intel/legalize-div-traps.cton b/cranelift/filetests/isa/x86/legalize-div-traps.cton similarity index 99% rename from cranelift/filetests/isa/intel/legalize-div-traps.cton rename to cranelift/filetests/isa/x86/legalize-div-traps.cton index 3869e66325..4d7beb59b8 100644 --- a/cranelift/filetests/isa/intel/legalize-div-traps.cton +++ b/cranelift/filetests/isa/x86/legalize-div-traps.cton @@ -3,7 +3,7 @@ test legalizer set is_64bit ; See also legalize-div.cton. set avoid_div_traps=1 -isa intel +isa x86 ; regex: V=v\d+ ; regex: EBB=ebb\d+ diff --git a/cranelift/filetests/isa/intel/legalize-div.cton b/cranelift/filetests/isa/x86/legalize-div.cton similarity index 99% rename from cranelift/filetests/isa/intel/legalize-div.cton rename to cranelift/filetests/isa/x86/legalize-div.cton index d6179b2611..3777be659e 100644 --- a/cranelift/filetests/isa/intel/legalize-div.cton +++ b/cranelift/filetests/isa/x86/legalize-div.cton @@ -3,7 +3,7 @@ test legalizer set is_64bit ; See also legalize-div-traps.cton. set avoid_div_traps=0 -isa intel +isa x86 ; regex: V=v\d+ ; regex: EBB=ebb\d+ diff --git a/cranelift/filetests/isa/intel/legalize-libcall.cton b/cranelift/filetests/isa/x86/legalize-libcall.cton similarity index 87% rename from cranelift/filetests/isa/intel/legalize-libcall.cton rename to cranelift/filetests/isa/x86/legalize-libcall.cton index c15587fc7f..70d392e6e4 100644 --- a/cranelift/filetests/isa/intel/legalize-libcall.cton +++ b/cranelift/filetests/isa/x86/legalize-libcall.cton @@ -2,7 +2,8 @@ test legalizer ; Pre-SSE 4.1, we need to use runtime library calls for floating point rounding operations. set is_64bit -isa intel +set is_pic +isa x86 function %floor(f32) -> f32 { ebb0(v0: f32): @@ -11,5 +12,5 @@ ebb0(v0: f32): } ; check: function %floor(f32 [%xmm0]) -> f32 [%xmm0] system_v { ; check: sig0 = (f32) -> f32 system_v -; check: fn0 = sig0 %FloorF32 +; check: fn0 = %FloorF32 sig0 ; check: v1 = call fn0(v0) diff --git a/cranelift/filetests/isa/intel/legalize-memory.cton b/cranelift/filetests/isa/x86/legalize-memory.cton similarity index 99% rename from cranelift/filetests/isa/intel/legalize-memory.cton rename to cranelift/filetests/isa/x86/legalize-memory.cton index 1ba979deb1..9cb8661873 100644 --- a/cranelift/filetests/isa/intel/legalize-memory.cton +++ b/cranelift/filetests/isa/x86/legalize-memory.cton @@ -1,7 +1,7 @@ ; Test the legalization of memory objects. test legalizer set is_64bit -isa intel +isa x86 ; regex: V=v\d+ ; regex: EBB=ebb\d+ diff --git a/cranelift/filetests/isa/intel/legalize-mulhi.cton b/cranelift/filetests/isa/x86/legalize-mulhi.cton similarity index 97% rename from cranelift/filetests/isa/intel/legalize-mulhi.cton rename to cranelift/filetests/isa/x86/legalize-mulhi.cton index 673a19db3b..a588f25d4e 100644 --- a/cranelift/filetests/isa/intel/legalize-mulhi.cton +++ b/cranelift/filetests/isa/x86/legalize-mulhi.cton @@ -1,7 +1,7 @@ test compile set is_64bit -isa intel baseline +isa x86 baseline ; umulhi/smulhi on 64 bit operands diff --git a/cranelift/filetests/isa/x86/prologue-epilogue.cton b/cranelift/filetests/isa/x86/prologue-epilogue.cton new file mode 100644 index 0000000000..9ed37274ca --- /dev/null +++ b/cranelift/filetests/isa/x86/prologue-epilogue.cton @@ -0,0 +1,231 @@ +test compile +set is_64bit +set is_compressed +set is_pic +isa x86 haswell + +; An empty function. + +function %empty() { +ebb0: + return +} + +; check: function %empty(i64 fp [%rbp]) -> i64 fp [%rbp] system_v { +; nextln: ss0 = incoming_arg 16, offset -16 +; nextln: +; nextln: ebb0(v0: i64 [%rbp]): +; nextln: x86_push v0 +; nextln: copy_special %rsp -> %rbp +; nextln: v1 = x86_pop.i64 +; nextln: return v1 +; nextln: } + +; A function with a single stack slot. + +function %one_stack_slot() { + ss0 = explicit_slot 168 +ebb0: + return +} + +; check: function %one_stack_slot(i64 fp [%rbp]) -> i64 fp [%rbp] system_v { +; nextln: ss0 = explicit_slot 168, offset -184 +; nextln: ss1 = incoming_arg 16, offset -16 +; nextln: +; nextln: ebb0(v0: i64 [%rbp]): +; nextln: x86_push v0 +; nextln: copy_special %rsp -> %rbp +; nextln: adjust_sp_imm -176 +; nextln: adjust_sp_imm 176 +; nextln: v1 = x86_pop.i64 +; nextln: return v1 +; nextln: } + +; A function performing a call. + +function %call() { + fn0 = %foo() + +ebb0: + call fn0() + return +} + +; check: function %call(i64 fp [%rbp]) -> i64 fp [%rbp] system_v { +; nextln: ss0 = incoming_arg 16, offset -16 +; nextln: sig0 = () system_v +; nextln: fn0 = %foo sig0 +; nextln: +; nextln: ebb0(v0: i64 [%rbp]): +; nextln: x86_push v0 +; nextln: copy_special %rsp -> %rbp +; nextln: call fn0() +; nextln: v1 = x86_pop.i64 +; nextln: return v1 +; nextln: } + +; A function that uses a lot of registers but doesn't quite need to spill. + +function %no_spill(i64, i64) { +ebb0(v0: i64, v1: i64): + v2 = load.i32 v0+0 + v3 = load.i32 v0+8 + v4 = load.i32 v0+16 + v5 = load.i32 v0+24 + v6 = load.i32 v0+32 + v7 = load.i32 v0+40 + v8 = load.i32 v0+48 + v9 = load.i32 v0+56 + v10 = load.i32 v0+64 + v11 = load.i32 v0+72 + v12 = load.i32 v0+80 + v13 = load.i32 v0+88 + v14 = load.i32 v0+96 + store.i32 v2, v1+0 + store.i32 v3, v1+8 + store.i32 v4, v1+16 + store.i32 v5, v1+24 + store.i32 v6, v1+32 + store.i32 v7, v1+40 + store.i32 v8, v1+48 + store.i32 v9, v1+56 + store.i32 v10, v1+64 + store.i32 v11, v1+72 + store.i32 v12, v1+80 + store.i32 v13, v1+88 + store.i32 v14, v1+96 + return +} + +; check: function %no_spill(i64 [%rdi], i64 [%rsi], i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v { +; nextln: ss0 = incoming_arg 56, offset -56 +; nextln: +; nextln: ebb0(v0: i64 [%rdi], v1: i64 [%rsi], v15: i64 [%rbp], v16: i64 [%rbx], v17: i64 [%r12], v18: i64 [%r13], v19: i64 [%r14], v20: i64 [%r15]): +; nextln: x86_push v15 +; nextln: copy_special %rsp -> %rbp +; nextln: x86_push v16 +; nextln: x86_push v17 +; nextln: x86_push v18 +; nextln: x86_push v19 +; nextln: x86_push v20 +; nextln: adjust_sp_imm -8 +; nextln: v2 = load.i32 v0 +; nextln: v3 = load.i32 v0+8 +; nextln: v4 = load.i32 v0+16 +; nextln: v5 = load.i32 v0+24 +; nextln: v6 = load.i32 v0+32 +; nextln: v7 = load.i32 v0+40 +; nextln: v8 = load.i32 v0+48 +; nextln: v9 = load.i32 v0+56 +; nextln: v10 = load.i32 v0+64 +; nextln: v11 = load.i32 v0+72 +; nextln: v12 = load.i32 v0+80 +; nextln: v13 = load.i32 v0+88 +; nextln: v14 = load.i32 v0+96 +; nextln: store v2, v1 +; nextln: store v3, v1+8 +; nextln: store v4, v1+16 +; nextln: store v5, v1+24 +; nextln: store v6, v1+32 +; nextln: store v7, v1+40 +; nextln: store v8, v1+48 +; nextln: store v9, v1+56 +; nextln: store v10, v1+64 +; nextln: store v11, v1+72 +; nextln: store v12, v1+80 +; nextln: store v13, v1+88 +; nextln: store v14, v1+96 +; nextln: adjust_sp_imm 8 +; nextln: v26 = x86_pop.i64 +; nextln: v25 = x86_pop.i64 +; nextln: v24 = x86_pop.i64 +; nextln: v23 = x86_pop.i64 +; nextln: v22 = x86_pop.i64 +; nextln: v21 = x86_pop.i64 +; nextln: return v21, v22, v23, v24, v25, v26 +; nextln: } + +; This function requires too many registers and must spill. + +function %yes_spill(i64, i64) { +ebb0(v0: i64, v1: i64): + v2 = load.i32 v0+0 + v3 = load.i32 v0+8 + v4 = load.i32 v0+16 + v5 = load.i32 v0+24 + v6 = load.i32 v0+32 + v7 = load.i32 v0+40 + v8 = load.i32 v0+48 + v9 = load.i32 v0+56 + v10 = load.i32 v0+64 + v11 = load.i32 v0+72 + v12 = load.i32 v0+80 + v13 = load.i32 v0+88 + v14 = load.i32 v0+96 + v15 = load.i32 v0+104 + store.i32 v2, v1+0 + store.i32 v3, v1+8 + store.i32 v4, v1+16 + store.i32 v5, v1+24 + store.i32 v6, v1+32 + store.i32 v7, v1+40 + store.i32 v8, v1+48 + store.i32 v9, v1+56 + store.i32 v10, v1+64 + store.i32 v11, v1+72 + store.i32 v12, v1+80 + store.i32 v13, v1+88 + store.i32 v14, v1+96 + store.i32 v15, v1+104 + return +} + +; check: function %yes_spill(i64 [%rdi], i64 [%rsi], i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15]) -> i64 fp [%rbp], i64 csr [%rbx], i64 csr [%r12], i64 csr [%r13], i64 csr [%r14], i64 csr [%r15] system_v { +; check: ss0 = spill_slot + +; check: ebb0(v16: i64 [%rdi], v17: i64 [%rsi], v48: i64 [%rbp], v49: i64 [%rbx], v50: i64 [%r12], v51: i64 [%r13], v52: i64 [%r14], v53: i64 [%r15]): +; nextln: x86_push v48 +; nextln: copy_special %rsp -> %rbp +; nextln: x86_push v49 +; nextln: x86_push v50 +; nextln: x86_push v51 +; nextln: x86_push v52 +; nextln: x86_push v53 +; nextln: adjust_sp_imm + +; check: spill + +; check: fill + +; check: adjust_sp_imm +; nextln: v59 = x86_pop.i64 +; nextln: v58 = x86_pop.i64 +; nextln: v57 = x86_pop.i64 +; nextln: v56 = x86_pop.i64 +; nextln: v55 = x86_pop.i64 +; nextln: v54 = x86_pop.i64 +; nextln: return v54, v55, v56, v57, v58, v59 +; nextln: } + +; A function which uses diverted registers. + +function %divert(i32) -> i32 system_v { +ebb0(v0: i32): + v2 = iconst.i32 0 + v3 = iconst.i32 1 + jump ebb3(v0, v3, v2) + +ebb3(v4: i32, v5: i32, v6: i32): + brz v4, ebb4 + v7 = iadd v5, v6 + v8 = iadd_imm v4, -1 + jump ebb3(v8, v7, v5) + +ebb4: + return v5 +} + +; check: function %divert +; check: regmove v5, %rcx -> %rbx +; check: [RexOp1popq#58,%rbx] v15 = x86_pop.i64 diff --git a/cranelift/filetests/parser/call.cton b/cranelift/filetests/parser/call.cton index 3413696caf..9d1e8def02 100644 --- a/cranelift/filetests/parser/call.cton +++ b/cranelift/filetests/parser/call.cton @@ -26,22 +26,22 @@ ebb1: function %signatures() { sig10 = () sig11 = (i32, f64) -> i32, b1 spiderwasm - fn5 = sig11 %foo - fn8 = function %bar(i32) -> b1 + fn5 = %foo sig11 + fn8 = %bar(i32) -> b1 } ; sameln: function %signatures() system_v { ; check: sig10 = () system_v ; check: sig11 = (i32, f64) -> i32, b1 spiderwasm ; check: sig12 = (i32) -> b1 system_v ; not: fn0 -; check: fn5 = sig11 %foo -; check: fn8 = sig12 %bar +; check: fn5 = %foo sig11 +; check: fn8 = %bar sig12 ; check: } function %direct() { - fn0 = function %none() - fn1 = function %one() -> i32 - fn2 = function %two() -> i32, f32 + fn0 = %none() + fn1 = %one() -> i32 + fn2 = %two() -> i32, f32 ebb0: call fn0() @@ -72,7 +72,7 @@ ebb0(v0: i64): function %long_call() { sig0 = () - fn0 = sig0 %none + fn0 = %none sig0 ebb0: v0 = func_addr.i32 fn0 diff --git a/cranelift/filetests/postopt/basic.cton b/cranelift/filetests/postopt/basic.cton index 218d4dfee4..48b6b66007 100644 --- a/cranelift/filetests/postopt/basic.cton +++ b/cranelift/filetests/postopt/basic.cton @@ -1,5 +1,5 @@ test postopt -isa intel +isa x86 ; Test that compare+branch sequences are folded effectively on x86. diff --git a/cranelift/filetests/preopt/div_by_const_indirect.cton b/cranelift/filetests/preopt/div_by_const_indirect.cton index ccc83cd49b..5d3f9475fc 100644 --- a/cranelift/filetests/preopt/div_by_const_indirect.cton +++ b/cranelift/filetests/preopt/div_by_const_indirect.cton @@ -1,6 +1,6 @@ test preopt -isa intel baseline +isa x86 baseline ; Cases where the denominator is created by an iconst diff --git a/cranelift/filetests/preopt/div_by_const_non_power_of_2.cton b/cranelift/filetests/preopt/div_by_const_non_power_of_2.cton index 18811fcd82..fa3f7fa96a 100644 --- a/cranelift/filetests/preopt/div_by_const_non_power_of_2.cton +++ b/cranelift/filetests/preopt/div_by_const_non_power_of_2.cton @@ -1,6 +1,6 @@ test preopt -isa intel baseline +isa x86 baseline ; -------- U32 -------- diff --git a/cranelift/filetests/preopt/div_by_const_power_of_2.cton b/cranelift/filetests/preopt/div_by_const_power_of_2.cton index dc51c5395d..2318aa1f81 100644 --- a/cranelift/filetests/preopt/div_by_const_power_of_2.cton +++ b/cranelift/filetests/preopt/div_by_const_power_of_2.cton @@ -1,6 +1,6 @@ test preopt -isa intel baseline +isa x86 baseline ; -------- U32 -------- diff --git a/cranelift/filetests/preopt/rem_by_const_non_power_of_2.cton b/cranelift/filetests/preopt/rem_by_const_non_power_of_2.cton index c142a16359..3d4b986213 100644 --- a/cranelift/filetests/preopt/rem_by_const_non_power_of_2.cton +++ b/cranelift/filetests/preopt/rem_by_const_non_power_of_2.cton @@ -1,6 +1,6 @@ test preopt -isa intel baseline +isa x86 baseline ; -------- U32 -------- diff --git a/cranelift/filetests/preopt/rem_by_const_power_of_2.cton b/cranelift/filetests/preopt/rem_by_const_power_of_2.cton index 931623d2e7..7b537fdbb4 100644 --- a/cranelift/filetests/preopt/rem_by_const_power_of_2.cton +++ b/cranelift/filetests/preopt/rem_by_const_power_of_2.cton @@ -1,6 +1,6 @@ test preopt -isa intel baseline +isa x86 baseline ; -------- U32 -------- diff --git a/cranelift/filetests/preopt/simplify.cton b/cranelift/filetests/preopt/simplify.cton index a2e67caf31..32f19f4f03 100644 --- a/cranelift/filetests/preopt/simplify.cton +++ b/cranelift/filetests/preopt/simplify.cton @@ -1,5 +1,5 @@ test preopt -isa intel +isa x86 function %iadd_imm(i32) -> i32 { ebb0(v0: i32): @@ -75,6 +75,6 @@ ebb0(v0: i32): ; sameln: function %irsub_imm ; nextln: ebb0(v0: i32): ; nextln: v1 = iconst.i32 2 -; nextln: v2 = irsub_imm v1, 2 +; nextln: v2 = irsub_imm v0, 2 ; nextln: return v2 ; nextln: } diff --git a/cranelift/filetests/regalloc/aliases.cton b/cranelift/filetests/regalloc/aliases.cton index a16fe7231b..096ba99c2a 100644 --- a/cranelift/filetests/regalloc/aliases.cton +++ b/cranelift/filetests/regalloc/aliases.cton @@ -1,6 +1,6 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell function %value_aliases(i32, f32, i64 vmctx) spiderwasm { gv0 = vmctx diff --git a/cranelift/filetests/regalloc/basic.cton b/cranelift/filetests/regalloc/basic.cton index b9399f464d..c24f87c1f9 100644 --- a/cranelift/filetests/regalloc/basic.cton +++ b/cranelift/filetests/regalloc/basic.cton @@ -53,7 +53,7 @@ ebb1(v10: i32): ; Pass an EBB argument as a function argument. function %callebb(i32, i32) -> i32 { - fn0 = function %foo(i32) -> i32 + fn0 = %foo(i32) -> i32 ebb0(v1: i32, v2: i32): brnz v1, ebb1(v1) @@ -66,7 +66,7 @@ ebb1(v10: i32): ; Pass an EBB argument as a jump argument. function %jumpebb(i32, i32) -> i32 { - fn0 = function %foo(i32) -> i32 + fn0 = %foo(i32) -> i32 ebb0(v1: i32, v2: i32): brnz v1, ebb1(v1, v2) diff --git a/cranelift/filetests/regalloc/coalescing-207.cton b/cranelift/filetests/regalloc/coalescing-207.cton index c4d348e10b..d8af887da3 100644 --- a/cranelift/filetests/regalloc/coalescing-207.cton +++ b/cranelift/filetests/regalloc/coalescing-207.cton @@ -1,8 +1,8 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell -; Reported as https://github.com/Cretonne/cretonne/issues/207 +; Reported as https://github.com/cretonne/cretonne/issues/207 ; ; The coalescer creates a virtual register with two interfering values. function %pr207(i64 vmctx, i32, i32) -> i32 system_v { @@ -11,9 +11,9 @@ function %pr207(i64 vmctx, i32, i32) -> i32 system_v { sig0 = (i64 vmctx, i32, i32) -> i32 system_v sig1 = (i64 vmctx, i32, i32, i32) -> i32 system_v sig2 = (i64 vmctx, i32, i32, i32) -> i32 system_v - fn0 = sig0 u0:2 - fn1 = sig1 u0:0 - fn2 = sig2 u0:1 + fn0 = u0:2 sig0 + fn1 = u0:0 sig1 + fn2 = u0:1 sig2 ebb0(v0: i64, v1: i32, v2: i32): v3 = iconst.i32 0 @@ -1038,7 +1038,7 @@ function %musl(f64 [%xmm0], i64 vmctx [%rdi]) -> f64 [%xmm0] system_v { gv0 = vmctx heap0 = static gv0, min 0, bound 0x0001_0000_0000, guard 0x8000_0000 sig0 = (f64 [%xmm0], i32 [%rdi], i64 vmctx [%rsi]) -> f64 [%xmm0] system_v - fn0 = sig0 u0:517 + fn0 = u0:517 sig0 ebb0(v0: f64, v1: i64): v3 = iconst.i64 0 diff --git a/cranelift/filetests/regalloc/coalescing-216.cton b/cranelift/filetests/regalloc/coalescing-216.cton index a6cf7b3b42..fc986f7fec 100644 --- a/cranelift/filetests/regalloc/coalescing-216.cton +++ b/cranelift/filetests/regalloc/coalescing-216.cton @@ -1,8 +1,8 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell -; Reported as https://github.com/Cretonne/cretonne/issues/216 from the Binaryen fuzzer. +; Reported as https://github.com/cretonne/cretonne/issues/216 from the Binaryen fuzzer. ; ; The (old) coalescer creates a virtual register with two identical values. function %pr216(i32 [%rdi], i64 vmctx [%rsi]) -> i64 [%rax] system_v { diff --git a/cranelift/filetests/regalloc/coloring-227.cton b/cranelift/filetests/regalloc/coloring-227.cton index accfb3528b..8144bba62e 100644 --- a/cranelift/filetests/regalloc/coloring-227.cton +++ b/cranelift/filetests/regalloc/coloring-227.cton @@ -1,6 +1,6 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell function %pr227(i32 [%rdi], i32 [%rsi], i32 [%rdx], i32 [%rcx], i64 vmctx [%r8]) system_v { gv0 = vmctx diff --git a/cranelift/filetests/regalloc/constraints.cton b/cranelift/filetests/regalloc/constraints.cton index bda37df149..e4db3bf9da 100644 --- a/cranelift/filetests/regalloc/constraints.cton +++ b/cranelift/filetests/regalloc/constraints.cton @@ -1,5 +1,5 @@ test regalloc -isa intel +isa x86 ; regex: V=v\d+ ; regex: REG=%r([abcd]x|[sd]i) diff --git a/cranelift/filetests/regalloc/ghost-param.cton b/cranelift/filetests/regalloc/ghost-param.cton index c4ce229360..2064231318 100644 --- a/cranelift/filetests/regalloc/ghost-param.cton +++ b/cranelift/filetests/regalloc/ghost-param.cton @@ -1,6 +1,6 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell ; This test case would create an EBB parameter that was a ghost value. ; The coalescer would insert a copy of the ghost value, leading to verifier errors. diff --git a/cranelift/filetests/regalloc/global-constraints.cton b/cranelift/filetests/regalloc/global-constraints.cton index b2a3fc0a7e..4975adeac5 100644 --- a/cranelift/filetests/regalloc/global-constraints.cton +++ b/cranelift/filetests/regalloc/global-constraints.cton @@ -1,11 +1,11 @@ test regalloc -isa intel +isa x86 ; This test covers the troubles when values with global live ranges are defined ; by instructions with constrained register classes. ; ; The icmp_imm instrutions write their b1 result to the ABCD register class on -; 32-bit Intel. So if we define 5 live values, they can't all fit. +; 32-bit x86. So if we define 5 live values, they can't all fit. function %global_constraints(i32) { ebb0(v0: i32): v1 = icmp_imm eq v0, 1 diff --git a/cranelift/filetests/regalloc/global-fixed.cton b/cranelift/filetests/regalloc/global-fixed.cton index 14b9d8fecc..61d4928806 100644 --- a/cranelift/filetests/regalloc/global-fixed.cton +++ b/cranelift/filetests/regalloc/global-fixed.cton @@ -1,6 +1,6 @@ test regalloc set is_64bit=1 -isa intel haswell +isa x86 haswell function %foo() system_v { ebb4: diff --git a/cranelift/filetests/regalloc/iterate.cton b/cranelift/filetests/regalloc/iterate.cton index 2c585e941d..acb97a31af 100644 --- a/cranelift/filetests/regalloc/iterate.cton +++ b/cranelift/filetests/regalloc/iterate.cton @@ -1,6 +1,6 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell function u0:9(i64 [%rdi], f32 [%xmm0], f64 [%xmm1], i32 [%rsi], i32 [%rdx], i64 vmctx [%r14]) -> i64 [%rax] spiderwasm { ebb0(v0: i64, v1: f32, v2: f64, v3: i32, v4: i32, v5: i64): diff --git a/cranelift/filetests/regalloc/multi-constraints.cton b/cranelift/filetests/regalloc/multi-constraints.cton index afbbf6fc2b..590d93eb38 100644 --- a/cranelift/filetests/regalloc/multi-constraints.cton +++ b/cranelift/filetests/regalloc/multi-constraints.cton @@ -1,10 +1,10 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell ; Test combinations of constraints. ; -; The Intel ushr instruction requires its second operand to be passed in %rcx and its output is +; The x86 ushr instruction requires its second operand to be passed in %rcx and its output is ; tied to the first input operand. ; ; If we pass the same value to both operands, both constraints must be satisfied. diff --git a/cranelift/filetests/regalloc/output-interference.cton b/cranelift/filetests/regalloc/output-interference.cton index 4a5b90c856..ac2bb537c7 100644 --- a/cranelift/filetests/regalloc/output-interference.cton +++ b/cranelift/filetests/regalloc/output-interference.cton @@ -1,11 +1,11 @@ test regalloc set is_64bit=1 -isa intel haswell +isa x86 haswell function %test(i64) -> i64 system_v { ebb0(v0: i64): v2 = iconst.i64 12 - ; This division clobbers two of its fixed input registers on Intel. + ; This division clobbers two of its fixed input registers on x86. ; These are FixedTied constraints that the spiller needs to resolve. v5 = udiv v0, v2 v6 = iconst.i64 13 diff --git a/cranelift/filetests/regalloc/reload-208.cton b/cranelift/filetests/regalloc/reload-208.cton index 70dc1c4523..259c4a169b 100644 --- a/cranelift/filetests/regalloc/reload-208.cton +++ b/cranelift/filetests/regalloc/reload-208.cton @@ -1,10 +1,10 @@ test regalloc set is_64bit -isa intel haswell +isa x86 haswell ; regex: V=v\d+ -; Filed as https://github.com/Cretonne/cretonne/issues/208 +; Filed as https://github.com/cretonne/cretonne/issues/208 ; ; The verifier complains about a branch argument that is not in the same virtual register as the ; corresponding EBB argument. @@ -16,8 +16,8 @@ function %pr208(i64 vmctx [%rdi]) system_v { heap0 = static gv0, min 0, bound 0x5000, guard 0x0040_0000 sig0 = (i64 vmctx [%rdi]) -> i32 [%rax] system_v sig1 = (i64 vmctx [%rdi], i32 [%rsi]) system_v - fn0 = sig0 u0:1 - fn1 = sig1 u0:3 + fn0 = u0:1 sig0 + fn1 = u0:3 sig1 ebb0(v0: i64): v1 = iconst.i32 0 diff --git a/cranelift/filetests/regalloc/reload.cton b/cranelift/filetests/regalloc/reload.cton index 5e62db3213..d0a9646808 100644 --- a/cranelift/filetests/regalloc/reload.cton +++ b/cranelift/filetests/regalloc/reload.cton @@ -5,7 +5,7 @@ isa riscv enable_e ; Check that we can handle a function return value that got spilled. function %spill_return() -> i32 { - fn0 = function %foo() -> i32 system_v + fn0 = %foo() -> i32 system_v ebb0: v0 = call fn0() diff --git a/cranelift/filetests/regalloc/schedule-moves.cton b/cranelift/filetests/regalloc/schedule-moves.cton index 6ba78db893..946bcc9cf3 100644 --- a/cranelift/filetests/regalloc/schedule-moves.cton +++ b/cranelift/filetests/regalloc/schedule-moves.cton @@ -1,5 +1,5 @@ test regalloc -isa intel haswell +isa x86 haswell function %pr165() system_v { ebb0: diff --git a/cranelift/filetests/regalloc/spill-noregs.cton b/cranelift/filetests/regalloc/spill-noregs.cton index 733606b828..ffb9f041c1 100644 --- a/cranelift/filetests/regalloc/spill-noregs.cton +++ b/cranelift/filetests/regalloc/spill-noregs.cton @@ -1,12 +1,12 @@ test regalloc set is_64bit -isa intel +isa x86 ; Test case found by the Binaryen fuzzer. ; ; The spiller panics with a ; 'Ran out of GPR registers when inserting copy before v68 = icmp.i32 eq v66, v67', -; lib/cretonne/src/regalloc/spilling.rs:425:28 message. +; lib/codegen/src/regalloc/spilling.rs:425:28 message. ; ; The process_reg_uses() function is trying to insert a copy before the icmp instruction in ebb4 ; and runs out of registers to spill. Note that ebb7 has a lot of dead parameter values. diff --git a/cranelift/filetests/regalloc/spill.cton b/cranelift/filetests/regalloc/spill.cton index fb822e1a6f..7205d6a851 100644 --- a/cranelift/filetests/regalloc/spill.cton +++ b/cranelift/filetests/regalloc/spill.cton @@ -70,7 +70,7 @@ ebb0(v1: i32): ; All values live across a call must be spilled function %across_call(i32) { - fn0 = function %foo(i32) + fn0 = %foo(i32) ebb0(v1: i32): ; check: v1 = spill call fn0(v1) @@ -83,7 +83,7 @@ ebb0(v1: i32): ; The same value used for two function arguments. function %doubleuse(i32) { - fn0 = function %xx(i32, i32) + fn0 = %xx(i32, i32) ebb0(v0: i32): ; check: $(c=$V) = copy v0 call fn0(v0, v0) diff --git a/cranelift/filetests/regalloc/unreachable_code.cton b/cranelift/filetests/regalloc/unreachable_code.cton index ac667e7721..4b4896f4a8 100644 --- a/cranelift/filetests/regalloc/unreachable_code.cton +++ b/cranelift/filetests/regalloc/unreachable_code.cton @@ -2,7 +2,7 @@ test compile set is_64bit -isa intel haswell +isa x86 haswell ; This function contains unreachable blocks which trip up the register ; allocator if they don't get cleared out. diff --git a/cranelift/filetests/regalloc/intel-regres.cton b/cranelift/filetests/regalloc/x86-regres.cton similarity index 99% rename from cranelift/filetests/regalloc/intel-regres.cton rename to cranelift/filetests/regalloc/x86-regres.cton index 0f76e8f2d0..e396fb1022 100644 --- a/cranelift/filetests/regalloc/intel-regres.cton +++ b/cranelift/filetests/regalloc/x86-regres.cton @@ -1,6 +1,6 @@ test regalloc -isa intel +isa x86 ; regex: V=v\d+ diff --git a/cranelift/filetests/verifier/flags.cton b/cranelift/filetests/verifier/flags.cton index b4a01621c4..55d9bdf4e1 100644 --- a/cranelift/filetests/verifier/flags.cton +++ b/cranelift/filetests/verifier/flags.cton @@ -1,5 +1,5 @@ test verifier -isa intel +isa x86 ; Simple, correct use of CPU flags. function %simple(i32) -> i32 { diff --git a/cranelift/filetests/verifier/type_check.cton b/cranelift/filetests/verifier/type_check.cton index 4bd386efbf..8783c4aced 100644 --- a/cranelift/filetests/verifier/type_check.cton +++ b/cranelift/filetests/verifier/type_check.cton @@ -42,14 +42,14 @@ function %type_mismatch_controlling_variable() { } function %fn_call_too_few_args() { - fn2 = function %great_fn(i32, f32) + fn2 = %great_fn(i32, f32) ebb0: call fn2() ; error: mismatched argument count, got 0, expected 2 return } function %fn_call_too_many_args() { - fn5 = function %best_fn() + fn5 = %best_fn() ebb0: v0 = iconst.i64 56 v1 = f32const 0.0 diff --git a/cranelift/filetests/wasm/control.cton b/cranelift/filetests/wasm/control.cton index 1d12aeff3d..30d4240490 100644 --- a/cranelift/filetests/wasm/control.cton +++ b/cranelift/filetests/wasm/control.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell function %br_if(i32) -> i32 { ebb0(v0: i32): diff --git a/cranelift/filetests/wasm/conversions.cton b/cranelift/filetests/wasm/conversions.cton index 4ce70ee583..5ca8072067 100644 --- a/cranelift/filetests/wasm/conversions.cton +++ b/cranelift/filetests/wasm/conversions.cton @@ -2,7 +2,7 @@ test compile set is_64bit=1 -isa intel haswell +isa x86 haswell function %i32_wrap_i64(i64) -> i32 { ebb0(v0: i64): diff --git a/cranelift/filetests/wasm/f32-arith.cton b/cranelift/filetests/wasm/f32-arith.cton index 331f9c7fad..d21316d293 100644 --- a/cranelift/filetests/wasm/f32-arith.cton +++ b/cranelift/filetests/wasm/f32-arith.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell ; Constants. diff --git a/cranelift/filetests/wasm/f32-compares.cton b/cranelift/filetests/wasm/f32-compares.cton index 560b86ebcb..0cdee58ef3 100644 --- a/cranelift/filetests/wasm/f32-compares.cton +++ b/cranelift/filetests/wasm/f32-compares.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell function %f32_eq(f32, f32) -> i32 { ebb0(v0: f32, v1: f32): diff --git a/cranelift/filetests/wasm/f32-memory64.cton b/cranelift/filetests/wasm/f32-memory64.cton index 7125e66d3b..a6e0d54af7 100644 --- a/cranelift/filetests/wasm/f32-memory64.cton +++ b/cranelift/filetests/wasm/f32-memory64.cton @@ -4,7 +4,7 @@ test compile ; We only test on 64-bit since the heap_addr instructions and vmctx parameters ; explicitly mention the pointer width. set is_64bit=1 -isa intel haswell +isa x86 haswell function %f32_load(i32, i64 vmctx) -> f32 { gv0 = vmctx diff --git a/cranelift/filetests/wasm/f64-arith.cton b/cranelift/filetests/wasm/f64-arith.cton index 4f39fb6a5f..7b870ab2cb 100644 --- a/cranelift/filetests/wasm/f64-arith.cton +++ b/cranelift/filetests/wasm/f64-arith.cton @@ -2,7 +2,7 @@ test compile set is_64bit=1 -isa intel haswell +isa x86 haswell ; Constants. diff --git a/cranelift/filetests/wasm/f64-compares.cton b/cranelift/filetests/wasm/f64-compares.cton index 78a260ef27..ff1b9526d0 100644 --- a/cranelift/filetests/wasm/f64-compares.cton +++ b/cranelift/filetests/wasm/f64-compares.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell function %f64_eq(f64, f64) -> i32 { ebb0(v0: f64, v1: f64): diff --git a/cranelift/filetests/wasm/f64-memory64.cton b/cranelift/filetests/wasm/f64-memory64.cton index 1f61749e51..0a15e69a37 100644 --- a/cranelift/filetests/wasm/f64-memory64.cton +++ b/cranelift/filetests/wasm/f64-memory64.cton @@ -4,7 +4,7 @@ test compile ; We only test on 64-bit since the heap_addr instructions and vmctx parameters ; explicitly mention the pointer width. set is_64bit=1 -isa intel haswell +isa x86 haswell function %f64_load(i32, i64 vmctx) -> f64 { gv0 = vmctx diff --git a/cranelift/filetests/wasm/i32-arith.cton b/cranelift/filetests/wasm/i32-arith.cton index fe9cf19883..7fb388054f 100644 --- a/cranelift/filetests/wasm/i32-arith.cton +++ b/cranelift/filetests/wasm/i32-arith.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell ; Constants. diff --git a/cranelift/filetests/wasm/i32-compares.cton b/cranelift/filetests/wasm/i32-compares.cton index 228258d279..a36df1b28a 100644 --- a/cranelift/filetests/wasm/i32-compares.cton +++ b/cranelift/filetests/wasm/i32-compares.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell function %i32_eqz(i32) -> i32 { ebb0(v0: i32): diff --git a/cranelift/filetests/wasm/i32-memory64.cton b/cranelift/filetests/wasm/i32-memory64.cton index 0fbffa4fb8..319609e9d3 100644 --- a/cranelift/filetests/wasm/i32-memory64.cton +++ b/cranelift/filetests/wasm/i32-memory64.cton @@ -4,7 +4,7 @@ test compile ; We only test on 64-bit since the heap_addr instructions and vmctx parameters ; explicitly mention the pointer width. set is_64bit=1 -isa intel haswell +isa x86 haswell function %i32_load(i32, i64 vmctx) -> i32 { gv0 = vmctx diff --git a/cranelift/filetests/wasm/i64-arith.cton b/cranelift/filetests/wasm/i64-arith.cton index 4e8cdc06df..6cf6f2e4a2 100644 --- a/cranelift/filetests/wasm/i64-arith.cton +++ b/cranelift/filetests/wasm/i64-arith.cton @@ -2,7 +2,7 @@ test compile set is_64bit=1 -isa intel haswell +isa x86 haswell ; Constants. diff --git a/cranelift/filetests/wasm/i64-compares.cton b/cranelift/filetests/wasm/i64-compares.cton index 3406463f0d..4679268018 100644 --- a/cranelift/filetests/wasm/i64-compares.cton +++ b/cranelift/filetests/wasm/i64-compares.cton @@ -2,7 +2,7 @@ test compile set is_64bit=1 -isa intel haswell +isa x86 haswell function %i64_eqz(i64) -> i32 { ebb0(v0: i64): diff --git a/cranelift/filetests/wasm/i64-memory64.cton b/cranelift/filetests/wasm/i64-memory64.cton index bc44a2bbea..7c9836dbf3 100644 --- a/cranelift/filetests/wasm/i64-memory64.cton +++ b/cranelift/filetests/wasm/i64-memory64.cton @@ -4,7 +4,7 @@ test compile ; We only test on 64-bit since the heap_addr instructions and vmctx parameters ; explicitly mention the pointer width. set is_64bit=1 -isa intel haswell +isa x86 haswell function %i64_load(i32, i64 vmctx) -> i64 { gv0 = vmctx diff --git a/cranelift/filetests/wasm/select.cton b/cranelift/filetests/wasm/select.cton index fc08c92a8a..7f1c26e724 100644 --- a/cranelift/filetests/wasm/select.cton +++ b/cranelift/filetests/wasm/select.cton @@ -2,10 +2,10 @@ test compile set is_64bit=0 -isa intel haswell +isa x86 haswell set is_64bit=1 -isa intel haswell +isa x86 haswell function %select_i32(i32, i32, i32) -> i32 { ebb0(v0: i32, v1: i32, v2: i32): diff --git a/cranelift/publish-all.sh b/cranelift/publish-all.sh index a29f308929..ba539f2f26 100755 --- a/cranelift/publish-all.sh +++ b/cranelift/publish-all.sh @@ -4,7 +4,7 @@ cd $(dirname "$0") topdir="$(pwd)" # All the cretonne-* crates have the same version number -version="0.4.1" +version="0.5.0" # Update all of the Cargo.toml files. # @@ -27,8 +27,14 @@ cargo update echo git commit -a -m "\"Bump version to $version"\" echo git push -for crate in cretonne frontend native reader wasm; do +for crate in entity codegen frontend native reader wasm module simplejit faerie umbrella ; do + if [ "$crate" == "umbrella" ]; then + dir="cretonne" + else + dir="$crate" + fi + echo cargo publish --manifest-path "lib/$crate/Cargo.toml" done echo -echo Then, go to https://github.com/Cretonne/cretonne/releases/ and define a new release. +echo Then, go to https://github.com/cretonne/cretonne/releases/ and define a new release. diff --git a/cranelift/src/cat.rs b/cranelift/src/cat.rs index e82af42624..c4890ffb24 100644 --- a/cranelift/src/cat.rs +++ b/cranelift/src/cat.rs @@ -4,7 +4,7 @@ //! normalizing formatting and removing comments. use CommandResult; -use cton_reader::parse_functions; +use cretonne_reader::parse_functions; use utils::read_to_string; pub fn run(files: &[String]) -> CommandResult { diff --git a/cranelift/src/compile.rs b/cranelift/src/compile.rs index 6bab77e0d2..ae8cd1e30c 100644 --- a/cranelift/src/compile.rs +++ b/cranelift/src/compile.rs @@ -1,10 +1,10 @@ //! CLI tool to read Cretonne IR files and compile them into native code. -use cretonne::Context; -use cretonne::print_errors::pretty_error; -use cretonne::settings::FlagsOrIsa; -use cretonne::{binemit, ir}; -use cton_reader::parse_test; +use cretonne_codegen::Context; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_codegen::settings::FlagsOrIsa; +use cretonne_codegen::{binemit, ir}; +use cretonne_reader::parse_test; use std::path::Path; use std::path::PathBuf; use utils::{parse_sets_and_isa, read_to_string}; diff --git a/cranelift/src/cton-util.rs b/cranelift/src/cton-util.rs index 3968030709..20743d923b 100644 --- a/cranelift/src/cton-util.rs +++ b/cranelift/src/cton-util.rs @@ -1,7 +1,7 @@ -extern crate cretonne; -extern crate cton_filetests; -extern crate cton_reader; -extern crate cton_wasm; +extern crate cretonne_codegen; +extern crate cretonne_filetests; +extern crate cretonne_reader; +extern crate cretonne_wasm; extern crate docopt; extern crate filecheck; #[macro_use] @@ -9,7 +9,7 @@ extern crate serde_derive; extern crate tempdir; extern crate term; -use cretonne::{timing, VERSION}; +use cretonne_codegen::{timing, VERSION}; use docopt::Docopt; use std::io::{self, Write}; use std::process; @@ -86,7 +86,7 @@ fn cton_util() -> CommandResult { // Find the sub-command to execute. let result = if args.cmd_test { - cton_filetests::run(args.flag_verbose, &args.arg_file).map(|_time| ()) + cretonne_filetests::run(args.flag_verbose, &args.arg_file).map(|_time| ()) } else if args.cmd_cat { cat::run(&args.arg_file) } else if args.cmd_filecheck { diff --git a/cranelift/src/print_cfg.rs b/cranelift/src/print_cfg.rs index 846ee3e8fa..f078c7ee54 100644 --- a/cranelift/src/print_cfg.rs +++ b/cranelift/src/print_cfg.rs @@ -4,8 +4,8 @@ //! in graphviz format. use CommandResult; -use cretonne::cfg_printer::CFGPrinter; -use cton_reader::parse_functions; +use cretonne_codegen::cfg_printer::CFGPrinter; +use cretonne_reader::parse_functions; use utils::read_to_string; pub fn run(files: &[String]) -> CommandResult { diff --git a/cranelift/src/utils.rs b/cranelift/src/utils.rs index 8a2994a7ab..4d54cf118a 100644 --- a/cranelift/src/utils.rs +++ b/cranelift/src/utils.rs @@ -1,9 +1,9 @@ //! Utility functions. -use cretonne::isa; -use cretonne::isa::TargetIsa; -use cretonne::settings::{self, FlagsOrIsa}; -use cton_reader::{parse_options, Location}; +use cretonne_codegen::isa; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::settings::{self, FlagsOrIsa}; +use cretonne_reader::{parse_options, Location}; use std::fs::File; use std::io::{self, Read}; use std::path::Path; diff --git a/cranelift/src/wasm.rs b/cranelift/src/wasm.rs index 029c7ad5c0..5ef8e21f2e 100644 --- a/cranelift/src/wasm.rs +++ b/cranelift/src/wasm.rs @@ -1,12 +1,13 @@ -//! CLI tool to use the functions provided by the [cretonne-wasm](../cton_wasm/index.html) crate. +//! CLI tool to use the functions provided by the [cretonne-wasm](../cretonne_wasm/index.html) +//! crate. //! //! Reads Wasm binary files, translates the functions' code to Cretonne IR. #![cfg_attr(feature = "cargo-clippy", allow(too_many_arguments, cyclomatic_complexity))] -use cretonne::Context; -use cretonne::print_errors::{pretty_error, pretty_verifier_error}; -use cretonne::settings::FlagsOrIsa; -use cton_wasm::{translate_module, DummyEnvironment, ModuleEnvironment}; +use cretonne_codegen::Context; +use cretonne_codegen::print_errors::{pretty_error, pretty_verifier_error}; +use cretonne_codegen::settings::FlagsOrIsa; +use cretonne_wasm::{translate_module, DummyEnvironment, ModuleEnvironment}; use std::error::Error; use std::fs::File; use std::io; diff --git a/cranelift/test-all.sh b/cranelift/test-all.sh index 572bf5de7b..ba3faf70b0 100755 --- a/cranelift/test-all.sh +++ b/cranelift/test-all.sh @@ -31,13 +31,13 @@ fi # Check if any Python files have changed since we last checked them. tsfile=$topdir/target/meta-checked if [ -f $tsfile ]; then - needcheck=$(find $topdir/lib/cretonne/meta -name '*.py' -newer $tsfile) + needcheck=$(find $topdir/lib/codegen/meta -name '*.py' -newer $tsfile) else needcheck=yes fi if [ -n "$needcheck" ]; then banner "$(python --version 2>&1), $(python3 --version 2>&1)" - $topdir/lib/cretonne/meta/check.sh + $topdir/lib/codegen/meta/check.sh touch $tsfile || echo no target directory fi diff --git a/cranelift/test-no_std.sh b/cranelift/test-no_std.sh index c2857ff756..800c712402 100755 --- a/cranelift/test-no_std.sh +++ b/cranelift/test-no_std.sh @@ -15,7 +15,7 @@ function banner() { } # Test those packages which have no_std support. -LIBS="cretonne frontend wasm native" +LIBS="codegen frontend wasm native" cd "$topdir" for LIB in $LIBS do diff --git a/cranelift/tests/filetests.rs b/cranelift/tests/filetests.rs index 6b5e392c76..d99f168b61 100644 --- a/cranelift/tests/filetests.rs +++ b/cranelift/tests/filetests.rs @@ -1,7 +1,7 @@ -extern crate cton_filetests; +extern crate cretonne_filetests; #[test] fn filetests() { // Run all the filetests in the following directories. - cton_filetests::run(false, &["filetests".into(), "docs".into()]).expect("test harness"); + cretonne_filetests::run(false, &["filetests".into(), "docs".into()]).expect("test harness"); } diff --git a/lib/cretonne/Cargo.toml b/lib/codegen/Cargo.toml similarity index 76% rename from lib/cretonne/Cargo.toml rename to lib/codegen/Cargo.toml index e0fe112009..63a1566007 100644 --- a/lib/cretonne/Cargo.toml +++ b/lib/codegen/Cargo.toml @@ -1,20 +1,18 @@ [package] authors = ["The Cretonne Project Developers"] -name = "cretonne" -version = "0.4.1" +name = "cretonne-codegen" +version = "0.5.0" description = "Low-level code generator library" license = "Apache-2.0" documentation = "https://cretonne.readthedocs.io/" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" readme = "README.md" keywords = ["compile", "compiler", "jit"] build = "build.rs" -[lib] -name = "cretonne" - [dependencies] -# It is a goal of the cretonne crate to have minimal external dependencies. +cretonne-entity = { path = "../entity", version = "0.5.0" } +# It is a goal of the cretonne-codegen crate to have minimal external dependencies. # Please don't add any unless they are essential to the task of creating binary # machine code. Integration tests that need external dependencies can be # accomodated in `tests`. @@ -35,4 +33,4 @@ core = ["hashmap_core"] [badges] maintenance = { status = "experimental" } -travis-ci = { repository = "Cretonne/cretonne" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/cretonne/README.md b/lib/codegen/README.md similarity index 100% rename from lib/cretonne/README.md rename to lib/codegen/README.md diff --git a/lib/cretonne/build.rs b/lib/codegen/build.rs similarity index 93% rename from lib/cretonne/build.rs rename to lib/codegen/build.rs index e13e9349a5..69100ef00f 100644 --- a/lib/cretonne/build.rs +++ b/lib/codegen/build.rs @@ -1,7 +1,7 @@ // Build script. // -// This program is run by Cargo when building lib/cretonne. It is used to generate Rust code from -// the language definitions in the lib/cretonne/meta directory. +// This program is run by Cargo when building lib/codegen. It is used to generate Rust code from +// the language definitions in the lib/codegen/meta directory. // // Environment: // @@ -77,7 +77,7 @@ fn main() { #[derive(Copy, Clone)] enum Isa { Riscv, - Intel, + X86, Arm32, Arm64, } @@ -103,14 +103,14 @@ impl Isa { /// Returns all supported isa targets. fn all() -> [Isa; 4] { - [Isa::Riscv, Isa::Intel, Isa::Arm32, Isa::Arm64] + [Isa::Riscv, Isa::X86, Isa::Arm32, Isa::Arm64] } /// Returns name of the isa target. fn name(&self) -> &'static str { match *self { Isa::Riscv => "riscv", - Isa::Intel => "intel", + Isa::X86 => "x86", Isa::Arm32 => "arm32", Isa::Arm64 => "arm64", } @@ -120,7 +120,7 @@ impl Isa { fn is_arch_applicable(&self, arch: &str) -> bool { match *self { Isa::Riscv => arch == "riscv", - Isa::Intel => ["x86_64", "i386", "i586", "i686"].contains(&arch), + Isa::X86 => ["x86_64", "i386", "i586", "i686"].contains(&arch), Isa::Arm32 => arch.starts_with("arm") || arch.starts_with("thumb"), Isa::Arm64 => arch == "aarch64", } diff --git a/lib/cretonne/meta/base/__init__.py b/lib/codegen/meta/base/__init__.py similarity index 100% rename from lib/cretonne/meta/base/__init__.py rename to lib/codegen/meta/base/__init__.py diff --git a/lib/cretonne/meta/base/entities.py b/lib/codegen/meta/base/entities.py similarity index 94% rename from lib/cretonne/meta/base/entities.py rename to lib/codegen/meta/base/entities.py index 614b4d6284..996913471b 100644 --- a/lib/cretonne/meta/base/entities.py +++ b/lib/codegen/meta/base/entities.py @@ -20,7 +20,7 @@ stack_slot = EntityRefKind('stack_slot', 'A stack slot.') global_var = EntityRefKind('global_var', 'A global variable.') #: A reference to a function sugnature declared in the function preamble. -#: Tbis is used to provide the call signature in an indirect call instruction. +#: This is used to provide the call signature in a call_indirect instruction. sig_ref = EntityRefKind('sig_ref', 'A function signature.') #: A reference to an external function declared in the function preamble. diff --git a/lib/cretonne/meta/base/formats.py b/lib/codegen/meta/base/formats.py similarity index 98% rename from lib/cretonne/meta/base/formats.py rename to lib/codegen/meta/base/formats.py index 595f09b9fa..89ef30881f 100644 --- a/lib/cretonne/meta/base/formats.py +++ b/lib/codegen/meta/base/formats.py @@ -53,7 +53,7 @@ BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS) BranchTable = InstructionFormat(VALUE, entities.jump_table) Call = InstructionFormat(func_ref, VARIABLE_ARGS) -IndirectCall = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS) +CallIndirect = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS) FuncAddr = InstructionFormat(func_ref) Load = InstructionFormat(memflags, VALUE, offset32) diff --git a/lib/cretonne/meta/base/immediates.py b/lib/codegen/meta/base/immediates.py similarity index 100% rename from lib/cretonne/meta/base/immediates.py rename to lib/codegen/meta/base/immediates.py diff --git a/lib/cretonne/meta/base/instructions.py b/lib/codegen/meta/base/instructions.py similarity index 100% rename from lib/cretonne/meta/base/instructions.py rename to lib/codegen/meta/base/instructions.py diff --git a/lib/cretonne/meta/base/legalize.py b/lib/codegen/meta/base/legalize.py similarity index 99% rename from lib/cretonne/meta/base/legalize.py rename to lib/codegen/meta/base/legalize.py index c2392269df..95a58987d3 100644 --- a/lib/cretonne/meta/base/legalize.py +++ b/lib/codegen/meta/base/legalize.py @@ -65,6 +65,9 @@ expand_flags = XFormGroup('expand_flags', """ expand.custom_legalize(insts.global_addr, 'expand_global_addr') expand.custom_legalize(insts.heap_addr, 'expand_heap_addr') +# Custom expansions for calls. +expand.custom_legalize(insts.call, 'expand_call') + # Custom expansions that need to change the CFG. # TODO: Add sufficient XForm syntax that we don't need to hand-code these. expand.custom_legalize(insts.trapz, 'expand_cond_trap') diff --git a/lib/codegen/meta/base/predicates.py b/lib/codegen/meta/base/predicates.py new file mode 100644 index 0000000000..1a6b4c2c75 --- /dev/null +++ b/lib/codegen/meta/base/predicates.py @@ -0,0 +1,35 @@ +""" +Cretonne predicates that consider `Function` fields. +""" +from cdsl.predicates import FieldPredicate +from .formats import UnaryGlobalVar + +try: + from typing import TYPE_CHECKING + if TYPE_CHECKING: + from cdsl.formats import FormatField # noqa +except ImportError: + pass + + +class IsColocatedFunc(FieldPredicate): + """ + An instruction predicate that checks the referenced function is colocated. + """ + + def __init__(self, field): + # type: (FormatField) -> None + super(IsColocatedFunc, self).__init__( + field, 'is_colocated_func', ('func',)) + + +class IsColocatedData(FieldPredicate): + """ + An instruction predicate that checks the referenced data object is + colocated. + """ + + def __init__(self): + # type: () -> None + super(IsColocatedData, self).__init__( + UnaryGlobalVar.global_var, 'is_colocated_data', ('func',)) diff --git a/lib/cretonne/meta/base/semantics.py b/lib/codegen/meta/base/semantics.py similarity index 100% rename from lib/cretonne/meta/base/semantics.py rename to lib/codegen/meta/base/semantics.py diff --git a/lib/cretonne/meta/base/settings.py b/lib/codegen/meta/base/settings.py similarity index 92% rename from lib/cretonne/meta/base/settings.py rename to lib/codegen/meta/base/settings.py index 3bd90f107b..ff1551c151 100644 --- a/lib/cretonne/meta/base/settings.py +++ b/lib/codegen/meta/base/settings.py @@ -29,6 +29,9 @@ enable_verifier = BoolSetting( is_64bit = BoolSetting("Enable 64-bit code generation") +# Note that Cretonne doesn't currently need an is_pie flag, because PIE is just +# PIC where symbols can't be pre-empted, which can be expressed with the +# `colocated` flag on external functions and global variables. is_pic = BoolSetting("Enable Position-Independent Code generation") return_at_end = BoolSetting( @@ -85,7 +88,7 @@ spiderwasm_prologue_words = NumSetting( This setting configures the number of pointer-sized words pushed on the stack when the Cretonne-generated code is entered. This includes the - pushed return address on Intel ISAs. + pushed return address on x86. """) # diff --git a/lib/cretonne/meta/base/types.py b/lib/codegen/meta/base/types.py similarity index 100% rename from lib/cretonne/meta/base/types.py rename to lib/codegen/meta/base/types.py diff --git a/lib/cretonne/meta/build.py b/lib/codegen/meta/build.py similarity index 92% rename from lib/cretonne/meta/build.py rename to lib/codegen/meta/build.py index 8c83300604..d7ad4cdba2 100644 --- a/lib/cretonne/meta/build.py +++ b/lib/codegen/meta/build.py @@ -1,6 +1,6 @@ # Second-level build script. # -# This script is run from lib/cretonne/build.rs to generate Rust files. +# This script is run from lib/codegen/build.rs to generate Rust files. from __future__ import absolute_import import argparse diff --git a/lib/cretonne/meta/cdsl/__init__.py b/lib/codegen/meta/cdsl/__init__.py similarity index 100% rename from lib/cretonne/meta/cdsl/__init__.py rename to lib/codegen/meta/cdsl/__init__.py diff --git a/lib/cretonne/meta/cdsl/ast.py b/lib/codegen/meta/cdsl/ast.py similarity index 100% rename from lib/cretonne/meta/cdsl/ast.py rename to lib/codegen/meta/cdsl/ast.py diff --git a/lib/cretonne/meta/cdsl/formats.py b/lib/codegen/meta/cdsl/formats.py similarity index 100% rename from lib/cretonne/meta/cdsl/formats.py rename to lib/codegen/meta/cdsl/formats.py diff --git a/lib/cretonne/meta/cdsl/instructions.py b/lib/codegen/meta/cdsl/instructions.py similarity index 100% rename from lib/cretonne/meta/cdsl/instructions.py rename to lib/codegen/meta/cdsl/instructions.py diff --git a/lib/cretonne/meta/cdsl/isa.py b/lib/codegen/meta/cdsl/isa.py similarity index 100% rename from lib/cretonne/meta/cdsl/isa.py rename to lib/codegen/meta/cdsl/isa.py diff --git a/lib/cretonne/meta/cdsl/operands.py b/lib/codegen/meta/cdsl/operands.py similarity index 100% rename from lib/cretonne/meta/cdsl/operands.py rename to lib/codegen/meta/cdsl/operands.py diff --git a/lib/cretonne/meta/cdsl/predicates.py b/lib/codegen/meta/cdsl/predicates.py similarity index 98% rename from lib/cretonne/meta/cdsl/predicates.py rename to lib/codegen/meta/cdsl/predicates.py index 9a28fd9945..13957c5d02 100644 --- a/lib/cretonne/meta/cdsl/predicates.py +++ b/lib/codegen/meta/cdsl/predicates.py @@ -370,9 +370,9 @@ class TypePredicate(object): """ Return Rust code for evaluating this predicate. - It is assumed that the context has `dfg` and `args` variables. + It is assumed that the context has `func` and `args` variables. """ - return 'dfg.value_type(args[{}]) == {}'.format( + return 'func.dfg.value_type(args[{}]) == {}'.format( self.value_arg, self.value_type.rust_name()) @@ -409,7 +409,7 @@ class CtrlTypePredicate(object): """ Return Rust code for evaluating this predicate. - It is assumed that the context has `dfg` and `inst` variables. + It is assumed that the context has `func` and `inst` variables. """ - return 'dfg.ctrl_typevar(inst) == {}'.format( + return 'func.dfg.ctrl_typevar(inst) == {}'.format( self.value_type.rust_name()) diff --git a/lib/cretonne/meta/cdsl/registers.py b/lib/codegen/meta/cdsl/registers.py similarity index 100% rename from lib/cretonne/meta/cdsl/registers.py rename to lib/codegen/meta/cdsl/registers.py diff --git a/lib/cretonne/meta/cdsl/settings.py b/lib/codegen/meta/cdsl/settings.py similarity index 100% rename from lib/cretonne/meta/cdsl/settings.py rename to lib/codegen/meta/cdsl/settings.py diff --git a/lib/cretonne/meta/cdsl/test_ast.py b/lib/codegen/meta/cdsl/test_ast.py similarity index 100% rename from lib/cretonne/meta/cdsl/test_ast.py rename to lib/codegen/meta/cdsl/test_ast.py diff --git a/lib/cretonne/meta/cdsl/test_package.py b/lib/codegen/meta/cdsl/test_package.py similarity index 100% rename from lib/cretonne/meta/cdsl/test_package.py rename to lib/codegen/meta/cdsl/test_package.py diff --git a/lib/cretonne/meta/cdsl/test_ti.py b/lib/codegen/meta/cdsl/test_ti.py similarity index 100% rename from lib/cretonne/meta/cdsl/test_ti.py rename to lib/codegen/meta/cdsl/test_ti.py diff --git a/lib/cretonne/meta/cdsl/test_typevar.py b/lib/codegen/meta/cdsl/test_typevar.py similarity index 100% rename from lib/cretonne/meta/cdsl/test_typevar.py rename to lib/codegen/meta/cdsl/test_typevar.py diff --git a/lib/cretonne/meta/cdsl/test_xform.py b/lib/codegen/meta/cdsl/test_xform.py similarity index 100% rename from lib/cretonne/meta/cdsl/test_xform.py rename to lib/codegen/meta/cdsl/test_xform.py diff --git a/lib/cretonne/meta/cdsl/ti.py b/lib/codegen/meta/cdsl/ti.py similarity index 100% rename from lib/cretonne/meta/cdsl/ti.py rename to lib/codegen/meta/cdsl/ti.py diff --git a/lib/cretonne/meta/cdsl/types.py b/lib/codegen/meta/cdsl/types.py similarity index 100% rename from lib/cretonne/meta/cdsl/types.py rename to lib/codegen/meta/cdsl/types.py diff --git a/lib/cretonne/meta/cdsl/typevar.py b/lib/codegen/meta/cdsl/typevar.py similarity index 100% rename from lib/cretonne/meta/cdsl/typevar.py rename to lib/codegen/meta/cdsl/typevar.py diff --git a/lib/cretonne/meta/cdsl/xform.py b/lib/codegen/meta/cdsl/xform.py similarity index 100% rename from lib/cretonne/meta/cdsl/xform.py rename to lib/codegen/meta/cdsl/xform.py diff --git a/lib/cretonne/meta/check.sh b/lib/codegen/meta/check.sh similarity index 100% rename from lib/cretonne/meta/check.sh rename to lib/codegen/meta/check.sh diff --git a/lib/cretonne/meta/constant_hash.py b/lib/codegen/meta/constant_hash.py similarity index 100% rename from lib/cretonne/meta/constant_hash.py rename to lib/codegen/meta/constant_hash.py diff --git a/lib/cretonne/meta/gen_binemit.py b/lib/codegen/meta/gen_binemit.py similarity index 100% rename from lib/cretonne/meta/gen_binemit.py rename to lib/codegen/meta/gen_binemit.py diff --git a/lib/cretonne/meta/gen_build_deps.py b/lib/codegen/meta/gen_build_deps.py similarity index 94% rename from lib/cretonne/meta/gen_build_deps.py rename to lib/codegen/meta/gen_build_deps.py index 5e1419284c..03d9ee72d0 100644 --- a/lib/cretonne/meta/gen_build_deps.py +++ b/lib/codegen/meta/gen_build_deps.py @@ -1,7 +1,7 @@ """ Generate build dependencies for Cargo. -The `build.py` script is invoked by cargo when building lib/cretonne to +The `build.py` script is invoked by cargo when building lib/codegen to generate Rust code from the instruction descriptions. Cargo needs to know when it is necessary to rerun the build script. diff --git a/lib/cretonne/meta/gen_encoding.py b/lib/codegen/meta/gen_encoding.py similarity index 98% rename from lib/cretonne/meta/gen_encoding.py rename to lib/codegen/meta/gen_encoding.py index 61ceb8d498..e3915100a2 100644 --- a/lib/cretonne/meta/gen_encoding.py +++ b/lib/codegen/meta/gen_encoding.py @@ -74,7 +74,7 @@ except ImportError: pass -def emit_instp(instp, fmt, has_dfg=False): +def emit_instp(instp, fmt, has_func=False): # type: (PredNode, srcgen.Formatter, bool) -> None """ Emit code for matching an instruction predicate against an @@ -87,7 +87,7 @@ def emit_instp(instp, fmt, has_dfg=False): # Deal with pure type check predicates which apply to any instruction. if iform == instruction_context: - fmt.line('let args = inst.arguments(&dfg.value_lists);') + fmt.line('let args = inst.arguments(&func.dfg.value_lists);') fmt.line(instp.rust_predicate(0)) return @@ -114,11 +114,11 @@ def emit_instp(instp, fmt, has_dfg=False): .format(iform.name, fields), '}'): if has_type_check: # We could implement this if we need to. - assert has_dfg, "Recipe predicates can't check type variables." - fmt.line('let args = inst.arguments(&dfg.value_lists);') - elif has_dfg: + assert has_func, "Recipe predicates can't check type variables." + fmt.line('let args = inst.arguments(&func.dfg.value_lists);') + elif has_func: # Silence dead argument warning. - fmt.line('let _ = dfg;') + fmt.line('let _ = func;') fmt.format('return {};', instp.rust_predicate(0)) fmt.line('unreachable!();') @@ -132,9 +132,9 @@ def emit_inst_predicates(instps, fmt): for instp, number in instps.items(): name = 'inst_predicate_{}'.format(number) with fmt.indented( - 'fn {}(dfg: &ir::DataFlowGraph, inst: &ir::InstructionData)' + 'fn {}(func: &ir::Function, inst: &ir::InstructionData)' '-> bool {{'.format(name), '}'): - emit_instp(instp, fmt, has_dfg=True) + emit_instp(instp, fmt, has_func=True) # Generate the static table. with fmt.indented( diff --git a/lib/cretonne/meta/gen_instr.py b/lib/codegen/meta/gen_instr.py similarity index 100% rename from lib/cretonne/meta/gen_instr.py rename to lib/codegen/meta/gen_instr.py diff --git a/lib/cretonne/meta/gen_legalizer.py b/lib/codegen/meta/gen_legalizer.py similarity index 98% rename from lib/cretonne/meta/gen_legalizer.py rename to lib/codegen/meta/gen_legalizer.py index 9051337238..104574b7b6 100644 --- a/lib/cretonne/meta/gen_legalizer.py +++ b/lib/codegen/meta/gen_legalizer.py @@ -185,9 +185,9 @@ def unwrap_inst(iref, node, fmt): fmt.line('ref args,') fmt.line('..') fmt.outdented_line('} = pos.func.dfg[inst] {') - fmt.line('let dfg = &pos.func.dfg;') + fmt.line('let func = &pos.func;') if iform.has_value_list: - fmt.line('let args = args.as_slice(&dfg.value_lists);') + fmt.line('let args = args.as_slice(&func.dfg.value_lists);') elif nvops == 1: fmt.line('let args = [arg];') # Generate the values for the tuple. @@ -198,7 +198,7 @@ def unwrap_inst(iref, node, fmt): fmt.format('{},', iform.imm_fields[n].member) elif op.is_value(): n = expr.inst.value_opnums.index(opnum) - fmt.format('dfg.resolve_aliases(args[{}]),', n) + fmt.format('func.dfg.resolve_aliases(args[{}]),', n) # Evaluate the instruction predicate, if any. instp = expr.inst_predicate_with_ctrl_typevar() fmt.line(instp.rust_predicate(0) if instp else 'true') diff --git a/lib/cretonne/meta/gen_registers.py b/lib/codegen/meta/gen_registers.py similarity index 100% rename from lib/cretonne/meta/gen_registers.py rename to lib/codegen/meta/gen_registers.py diff --git a/lib/cretonne/meta/gen_settings.py b/lib/codegen/meta/gen_settings.py similarity index 100% rename from lib/cretonne/meta/gen_settings.py rename to lib/codegen/meta/gen_settings.py diff --git a/lib/cretonne/meta/gen_types.py b/lib/codegen/meta/gen_types.py similarity index 95% rename from lib/cretonne/meta/gen_types.py rename to lib/codegen/meta/gen_types.py index bc912e78f7..4199efa51f 100644 --- a/lib/cretonne/meta/gen_types.py +++ b/lib/codegen/meta/gen_types.py @@ -2,7 +2,7 @@ Generate sources with type info. This generates a `types.rs` file which is included in -`lib/cretonne/ir/types.rs`. The file provides constant definitions for the most +`lib/codegen/ir/types.rs`. The file provides constant definitions for the most commonly used types, including all of the scalar types. This ensures that Python and Rust use the same type numbering. diff --git a/lib/cretonne/meta/isa/__init__.py b/lib/codegen/meta/isa/__init__.py similarity index 84% rename from lib/cretonne/meta/isa/__init__.py rename to lib/codegen/meta/isa/__init__.py index bad91c5c90..1add6e033f 100644 --- a/lib/cretonne/meta/isa/__init__.py +++ b/lib/codegen/meta/isa/__init__.py @@ -7,7 +7,7 @@ architecture supported by Cretonne. """ from __future__ import absolute_import from cdsl.isa import TargetISA # noqa -from . import riscv, intel, arm32, arm64 +from . import riscv, x86, arm32, arm64 try: from typing import List # noqa @@ -21,4 +21,4 @@ def all_isas(): Get a list of all the supported target ISAs. Each target ISA is represented as a :py:class:`cretonne.TargetISA` instance. """ - return [riscv.ISA, intel.ISA, arm32.ISA, arm64.ISA] + return [riscv.ISA, x86.ISA, arm32.ISA, arm64.ISA] diff --git a/lib/cretonne/meta/isa/arm32/__init__.py b/lib/codegen/meta/isa/arm32/__init__.py similarity index 100% rename from lib/cretonne/meta/isa/arm32/__init__.py rename to lib/codegen/meta/isa/arm32/__init__.py diff --git a/lib/cretonne/meta/isa/arm32/defs.py b/lib/codegen/meta/isa/arm32/defs.py similarity index 100% rename from lib/cretonne/meta/isa/arm32/defs.py rename to lib/codegen/meta/isa/arm32/defs.py diff --git a/lib/cretonne/meta/isa/arm32/registers.py b/lib/codegen/meta/isa/arm32/registers.py similarity index 100% rename from lib/cretonne/meta/isa/arm32/registers.py rename to lib/codegen/meta/isa/arm32/registers.py diff --git a/lib/cretonne/meta/isa/arm32/settings.py b/lib/codegen/meta/isa/arm32/settings.py similarity index 100% rename from lib/cretonne/meta/isa/arm32/settings.py rename to lib/codegen/meta/isa/arm32/settings.py diff --git a/lib/cretonne/meta/isa/arm64/__init__.py b/lib/codegen/meta/isa/arm64/__init__.py similarity index 100% rename from lib/cretonne/meta/isa/arm64/__init__.py rename to lib/codegen/meta/isa/arm64/__init__.py diff --git a/lib/cretonne/meta/isa/arm64/defs.py b/lib/codegen/meta/isa/arm64/defs.py similarity index 100% rename from lib/cretonne/meta/isa/arm64/defs.py rename to lib/codegen/meta/isa/arm64/defs.py diff --git a/lib/cretonne/meta/isa/arm64/registers.py b/lib/codegen/meta/isa/arm64/registers.py similarity index 100% rename from lib/cretonne/meta/isa/arm64/registers.py rename to lib/codegen/meta/isa/arm64/registers.py diff --git a/lib/cretonne/meta/isa/arm64/settings.py b/lib/codegen/meta/isa/arm64/settings.py similarity index 100% rename from lib/cretonne/meta/isa/arm64/settings.py rename to lib/codegen/meta/isa/arm64/settings.py diff --git a/lib/cretonne/meta/isa/riscv/__init__.py b/lib/codegen/meta/isa/riscv/__init__.py similarity index 100% rename from lib/cretonne/meta/isa/riscv/__init__.py rename to lib/codegen/meta/isa/riscv/__init__.py diff --git a/lib/cretonne/meta/isa/riscv/defs.py b/lib/codegen/meta/isa/riscv/defs.py similarity index 100% rename from lib/cretonne/meta/isa/riscv/defs.py rename to lib/codegen/meta/isa/riscv/defs.py diff --git a/lib/cretonne/meta/isa/riscv/encodings.py b/lib/codegen/meta/isa/riscv/encodings.py similarity index 100% rename from lib/cretonne/meta/isa/riscv/encodings.py rename to lib/codegen/meta/isa/riscv/encodings.py diff --git a/lib/cretonne/meta/isa/riscv/recipes.py b/lib/codegen/meta/isa/riscv/recipes.py similarity index 96% rename from lib/cretonne/meta/isa/riscv/recipes.py rename to lib/codegen/meta/isa/riscv/recipes.py index c657c7de47..170dd914d3 100644 --- a/lib/cretonne/meta/isa/riscv/recipes.py +++ b/lib/codegen/meta/isa/riscv/recipes.py @@ -14,7 +14,7 @@ from cdsl.predicates import IsSignedInt from cdsl.registers import Stack from base.formats import Binary, BinaryImm, MultiAry, IntCompare, IntCompareImm from base.formats import Unary, UnaryImm, BranchIcmp, Branch, Jump -from base.formats import Call, IndirectCall, RegMove +from base.formats import Call, CallIndirect, RegMove from .registers import GPR # The low 7 bits of a RISC-V instruction is the base opcode. All 32-bit @@ -140,11 +140,11 @@ Iret = EncRecipe( ); ''') -# I-type encoding for `jalr` as an indirect call. +# I-type encoding for `jalr` as a call_indirect. Icall = EncRecipe( - 'Icall', IndirectCall, size=4, ins=GPR, outs=(), + 'Icall', CallIndirect, size=4, ins=GPR, outs=(), emit=''' - // Indirect instructions are jalr with rd=%x1. + // call_indirect instructions are jalr with rd=%x1. put_i( bits, in_reg0, diff --git a/lib/cretonne/meta/isa/riscv/registers.py b/lib/codegen/meta/isa/riscv/registers.py similarity index 100% rename from lib/cretonne/meta/isa/riscv/registers.py rename to lib/codegen/meta/isa/riscv/registers.py diff --git a/lib/cretonne/meta/isa/riscv/settings.py b/lib/codegen/meta/isa/riscv/settings.py similarity index 100% rename from lib/cretonne/meta/isa/riscv/settings.py rename to lib/codegen/meta/isa/riscv/settings.py diff --git a/lib/codegen/meta/isa/x86/__init__.py b/lib/codegen/meta/isa/x86/__init__.py new file mode 100644 index 0000000000..d87b95964a --- /dev/null +++ b/lib/codegen/meta/isa/x86/__init__.py @@ -0,0 +1,21 @@ +""" +x86 Target Architecture +------------------------- + +This target ISA generates code for x86 CPUs with two separate CPU modes: + +`I32` + 32-bit x86 architecture, also known as 'IA-32', also sometimes referred + to as 'i386', however note that Cretonne depends on instructions not + in the original `i386`, such as SSE2, CMOVcc, and UD2. + +`I64` + x86-64 architecture, also known as 'AMD64`, `Intel 64`, and 'x64'. +""" + +from __future__ import absolute_import +from . import defs +from . import encodings, settings, registers # noqa + +# Re-export the primary target ISA definition. +ISA = defs.ISA.finish() diff --git a/lib/cretonne/meta/isa/intel/defs.py b/lib/codegen/meta/isa/x86/defs.py similarity index 88% rename from lib/cretonne/meta/isa/intel/defs.py rename to lib/codegen/meta/isa/x86/defs.py index b6a4d37206..32c54ab620 100644 --- a/lib/cretonne/meta/isa/intel/defs.py +++ b/lib/codegen/meta/isa/x86/defs.py @@ -1,5 +1,5 @@ """ -Intel definitions. +x86 definitions. Commonly used definitions. """ @@ -9,7 +9,7 @@ import base.instructions from . import instructions as x86 from base.immediates import floatcc -ISA = TargetISA('intel', [base.instructions.GROUP, x86.GROUP]) +ISA = TargetISA('x86', [base.instructions.GROUP, x86.GROUP]) # CPU modes for 32-bit and 64-bit operation. X86_64 = CPUMode('I64', ISA) diff --git a/lib/cretonne/meta/isa/intel/encodings.py b/lib/codegen/meta/isa/x86/encodings.py similarity index 92% rename from lib/cretonne/meta/isa/intel/encodings.py rename to lib/codegen/meta/isa/x86/encodings.py index 0fc507bac5..5ab6636a44 100644 --- a/lib/cretonne/meta/isa/intel/encodings.py +++ b/lib/codegen/meta/isa/x86/encodings.py @@ -1,15 +1,16 @@ """ -Intel Encodings. +x86 Encodings. """ from __future__ import absolute_import from cdsl.predicates import IsUnsignedInt, Not, And +from base.predicates import IsColocatedFunc, IsColocatedData from base import instructions as base -from base.formats import UnaryImm +from base.formats import UnaryImm, FuncAddr, Call from .defs import X86_64, X86_32 from . import recipes as r from . import settings as cfg from . import instructions as x86 -from .legalize import intel_expand +from .legalize import x86_expand from base.legalize import narrow, expand_flags from base.settings import allones_funcaddrs, is_pic from .settings import use_sse41 @@ -26,18 +27,18 @@ X86_32.legalize_monomorphic(expand_flags) X86_32.legalize_type( default=narrow, b1=expand_flags, - i32=intel_expand, - f32=intel_expand, - f64=intel_expand) + i32=x86_expand, + f32=x86_expand, + f64=x86_expand) X86_64.legalize_monomorphic(expand_flags) X86_64.legalize_type( default=narrow, b1=expand_flags, - i32=intel_expand, - i64=intel_expand, - f32=intel_expand, - f64=intel_expand) + i32=x86_expand, + i64=x86_expand, + f32=x86_expand, + f64=x86_expand) # @@ -292,16 +293,24 @@ enc_both(base.regspill.f64, r.fregspill32, 0xf2, 0x0f, 0x11) # Function addresses. # +# Non-PIC, all-ones funcaddresses. X86_32.enc(base.func_addr.i32, *r.fnaddr4(0xb8), - isap=Not(allones_funcaddrs)) + isap=And(Not(allones_funcaddrs), Not(is_pic))) X86_64.enc(base.func_addr.i64, *r.fnaddr8.rex(0xb8, w=1), isap=And(Not(allones_funcaddrs), Not(is_pic))) +# Non-PIC, all-zeros funcaddresses. X86_32.enc(base.func_addr.i32, *r.allones_fnaddr4(0xb8), - isap=allones_funcaddrs) + isap=And(allones_funcaddrs, Not(is_pic))) X86_64.enc(base.func_addr.i64, *r.allones_fnaddr8.rex(0xb8, w=1), isap=And(allones_funcaddrs, Not(is_pic))) +# 64-bit, colocated, both PIC and non-PIC. Use the lea instruction's +# pc-relative field. +X86_64.enc(base.func_addr.i64, *r.pcrel_fnaddr8.rex(0x8d, w=1), + instp=IsColocatedFunc(FuncAddr.func_ref)) + +# 64-bit, non-colocated, PIC. X86_64.enc(base.func_addr.i64, *r.got_fnaddr8.rex(0x8b, w=1), isap=is_pic) @@ -309,18 +318,36 @@ X86_64.enc(base.func_addr.i64, *r.got_fnaddr8.rex(0x8b, w=1), # Global addresses. # -X86_32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8)) +# Non-PIC +X86_32.enc(base.globalsym_addr.i32, *r.gvaddr4(0xb8), + isap=Not(is_pic)) X86_64.enc(base.globalsym_addr.i64, *r.gvaddr8.rex(0xb8, w=1), isap=Not(is_pic)) +# PIC, colocated +X86_64.enc(base.globalsym_addr.i64, *r.pcrel_gvaddr8.rex(0x8d, w=1), + isap=is_pic, + instp=IsColocatedData()) + +# PIC, non-colocated X86_64.enc(base.globalsym_addr.i64, *r.got_gvaddr8.rex(0x8b, w=1), isap=is_pic) # # Call/return # + +# 32-bit, both PIC and non-PIC. X86_32.enc(base.call, *r.call_id(0xe8)) -X86_64.enc(base.call, *r.call_id(0xe8), isap=Not(is_pic)) + +# 64-bit, colocated, both PIC and non-PIC. Use the call instruction's +# pc-relative field. +X86_64.enc(base.call, *r.call_id(0xe8), + instp=IsColocatedFunc(Call.func_ref)) + +# 64-bit, non-colocated, PIC. There is no 64-bit non-colocated non-PIC version, +# since non-PIC is currently using the large model, which requires calls be +# lowered to func_addr+call_indirect. X86_64.enc(base.call, *r.call_plt_id(0xe8), isap=is_pic) X86_32.enc(base.call_indirect.i32, *r.call_r(0xff, rrr=2)) diff --git a/lib/cretonne/meta/isa/intel/instructions.py b/lib/codegen/meta/isa/x86/instructions.py similarity index 95% rename from lib/cretonne/meta/isa/intel/instructions.py rename to lib/codegen/meta/isa/x86/instructions.py index 1fe75ff984..6adc2ad689 100644 --- a/lib/cretonne/meta/isa/intel/instructions.py +++ b/lib/codegen/meta/isa/x86/instructions.py @@ -1,7 +1,7 @@ """ -Supplementary instruction definitions for Intel. +Supplementary instruction definitions for x86. -This module defines additional instructions that are useful only to the Intel +This module defines additional instructions that are useful only to the x86 target ISA. """ @@ -11,7 +11,7 @@ from cdsl.typevar import TypeVar from cdsl.instructions import Instruction, InstructionGroup -GROUP = InstructionGroup("x86", "Intel-specific instruction set") +GROUP = InstructionGroup("x86", "x86-specific instruction set") iWord = TypeVar('iWord', 'A scalar integer machine word', ints=(32, 64)) @@ -98,7 +98,7 @@ y = Operand('y', Float) fmin = Instruction( 'x86_fmin', r""" - Floating point minimum with Intel semantics. + Floating point minimum with x86 semantics. This is equivalent to the C ternary operator `x < y ? x : y` which differs from :inst:`fmin` when either operand is NaN or when comparing @@ -111,7 +111,7 @@ fmin = Instruction( fmax = Instruction( 'x86_fmax', r""" - Floating point maximum with Intel semantics. + Floating point maximum with x86 semantics. This is equivalent to the C ternary operator `x > y ? x : y` which differs from :inst:`fmax` when either operand is NaN or when comparing diff --git a/lib/cretonne/meta/isa/intel/legalize.py b/lib/codegen/meta/isa/x86/legalize.py similarity index 85% rename from lib/cretonne/meta/isa/intel/legalize.py rename to lib/codegen/meta/isa/x86/legalize.py index 5806bb9284..6da7d53340 100644 --- a/lib/cretonne/meta/isa/intel/legalize.py +++ b/lib/codegen/meta/isa/x86/legalize.py @@ -1,5 +1,5 @@ """ -Custom legalization patterns for Intel. +Custom legalization patterns for x86. """ from __future__ import absolute_import from cdsl.ast import Var @@ -10,12 +10,12 @@ from base import instructions as insts from . import instructions as x86 from .defs import ISA -intel_expand = XFormGroup( - 'intel_expand', +x86_expand = XFormGroup( + 'x86_expand', """ Legalize instructions by expansion. - Use Intel-specific instructions if needed. + Use x86-specific instructions if needed. """, isa=ISA, chain=shared.expand_flags) @@ -32,23 +32,23 @@ a2 = Var('a2') # # The srem expansion requires custom code because srem INT_MIN, -1 is not # allowed to trap. The other ops need to check avoid_div_traps. -intel_expand.custom_legalize(insts.sdiv, 'expand_sdivrem') -intel_expand.custom_legalize(insts.srem, 'expand_sdivrem') -intel_expand.custom_legalize(insts.udiv, 'expand_udivrem') -intel_expand.custom_legalize(insts.urem, 'expand_udivrem') +x86_expand.custom_legalize(insts.sdiv, 'expand_sdivrem') +x86_expand.custom_legalize(insts.srem, 'expand_sdivrem') +x86_expand.custom_legalize(insts.udiv, 'expand_udivrem') +x86_expand.custom_legalize(insts.urem, 'expand_udivrem') # # Double length (widening) multiplication # resLo = Var('resLo') resHi = Var('resHi') -intel_expand.legalize( +x86_expand.legalize( resHi << insts.umulhi(x, y), Rtl( (resLo, resHi) << x86.umulx(x, y) )) -intel_expand.legalize( +x86_expand.legalize( resHi << insts.smulhi(x, y), Rtl( (resLo, resHi) << x86.smulx(x, y) @@ -61,14 +61,14 @@ intel_expand.legalize( # patterns. # Equality needs an explicit `ord` test which checks the parity bit. -intel_expand.legalize( +x86_expand.legalize( a << insts.fcmp(floatcc.eq, x, y), Rtl( a1 << insts.fcmp(floatcc.ord, x, y), a2 << insts.fcmp(floatcc.ueq, x, y), a << insts.band(a1, a2) )) -intel_expand.legalize( +x86_expand.legalize( a << insts.fcmp(floatcc.ne, x, y), Rtl( a1 << insts.fcmp(floatcc.uno, x, y), @@ -82,21 +82,21 @@ for cc, rev_cc in [ (floatcc.le, floatcc.ge), (floatcc.ugt, floatcc.ult), (floatcc.uge, floatcc.ule)]: - intel_expand.legalize( + x86_expand.legalize( a << insts.fcmp(cc, x, y), Rtl( a << insts.fcmp(rev_cc, y, x) )) # We need to modify the CFG for min/max legalization. -intel_expand.custom_legalize(insts.fmin, 'expand_minmax') -intel_expand.custom_legalize(insts.fmax, 'expand_minmax') +x86_expand.custom_legalize(insts.fmin, 'expand_minmax') +x86_expand.custom_legalize(insts.fmax, 'expand_minmax') # Conversions from unsigned need special handling. -intel_expand.custom_legalize(insts.fcvt_from_uint, 'expand_fcvt_from_uint') +x86_expand.custom_legalize(insts.fcvt_from_uint, 'expand_fcvt_from_uint') # Conversions from float to int can trap. -intel_expand.custom_legalize(insts.fcvt_to_sint, 'expand_fcvt_to_sint') -intel_expand.custom_legalize(insts.fcvt_to_uint, 'expand_fcvt_to_uint') +x86_expand.custom_legalize(insts.fcvt_to_sint, 'expand_fcvt_to_sint') +x86_expand.custom_legalize(insts.fcvt_to_uint, 'expand_fcvt_to_uint') # Count leading and trailing zeroes, for baseline x86_64 c_minus_one = Var('c_minus_one') @@ -108,7 +108,7 @@ index1 = Var('index1') r2flags = Var('r2flags') index2 = Var('index2') -intel_expand.legalize( +x86_expand.legalize( a << insts.clz.i64(x), Rtl( c_minus_one << insts.iconst(imm64(-1)), @@ -118,7 +118,7 @@ intel_expand.legalize( a << insts.isub(c_sixty_three, index2), )) -intel_expand.legalize( +x86_expand.legalize( a << insts.clz.i32(x), Rtl( c_minus_one << insts.iconst(imm64(-1)), @@ -128,7 +128,7 @@ intel_expand.legalize( a << insts.isub(c_thirty_one, index2), )) -intel_expand.legalize( +x86_expand.legalize( a << insts.ctz.i64(x), Rtl( c_sixty_four << insts.iconst(imm64(64)), @@ -136,7 +136,7 @@ intel_expand.legalize( a << insts.selectif(intcc.eq, r2flags, c_sixty_four, index1), )) -intel_expand.legalize( +x86_expand.legalize( a << insts.ctz.i32(x), Rtl( c_thirty_two << insts.iconst(imm64(32)), @@ -164,7 +164,7 @@ qv16 = Var('qv16') qc77 = Var('qc77') qc0F = Var('qc0F') qc01 = Var('qc01') -intel_expand.legalize( +x86_expand.legalize( qv16 << insts.popcnt.i64(qv1), Rtl( qv3 << insts.ushr_imm(qv1, imm64(1)), @@ -204,7 +204,7 @@ lv16 = Var('lv16') lc77 = Var('lc77') lc0F = Var('lc0F') lc01 = Var('lc01') -intel_expand.legalize( +x86_expand.legalize( lv16 << insts.popcnt.i32(lv1), Rtl( lv3 << insts.ushr_imm(lv1, imm64(1)), diff --git a/lib/cretonne/meta/isa/intel/recipes.py b/lib/codegen/meta/isa/x86/recipes.py similarity index 95% rename from lib/cretonne/meta/isa/intel/recipes.py rename to lib/codegen/meta/isa/x86/recipes.py index 54df437c67..ea0da832b7 100644 --- a/lib/cretonne/meta/isa/intel/recipes.py +++ b/lib/codegen/meta/isa/x86/recipes.py @@ -1,5 +1,5 @@ """ -Intel Encoding recipes. +x86 Encoding recipes. """ from __future__ import absolute_import from cdsl.isa import EncRecipe @@ -7,7 +7,7 @@ from cdsl.predicates import IsSignedInt, IsEqual, Or from cdsl.registers import RegClass from base.formats import Unary, UnaryImm, UnaryBool, Binary, BinaryImm from base.formats import MultiAry, NullAry -from base.formats import Trap, Call, IndirectCall, Store, Load +from base.formats import Trap, Call, CallIndirect, Store, Load from base.formats import IntCompare, IntCompareImm, FloatCompare from base.formats import IntCond, FloatCond from base.formats import IntSelect, IntCondTrap, FloatCondTrap @@ -31,7 +31,7 @@ except ImportError: # Opcode representation. # # Cretonne requires each recipe to have a single encoding size in bytes, and -# Intel opcodes are variable length, so we use separate recipes for different +# x86 opcodes are variable length, so we use separate recipes for different # styles of opcodes and prefixes. The opcode format is indicated by the recipe # name prefix: @@ -124,7 +124,7 @@ class TailRecipe: """ Generate encoding recipes on demand. - Intel encodings are somewhat orthogonal with the opcode representation on + x86 encodings are somewhat orthogonal with the opcode representation on one side and the ModR/M, SIB and immediate fields on the other side. A `TailRecipe` represents the part of an encoding that follow the opcode. @@ -144,7 +144,7 @@ class TailRecipe: The `emit` parameter contains Rust code to actually emit an encoding, like `EncRecipe` does it. Additionally, the text `PUT_OP` is substituted with - the proper `put_*` function from the `intel/binemit.rs` module. + the proper `put_*` function from the `x86/binemit.rs` module. """ def __init__( @@ -590,7 +590,7 @@ fnaddr4 = TailRecipe( 'fnaddr4', FuncAddr, size=4, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs4, + sink.reloc_external(Reloc::Abs4, &func.dfg.ext_funcs[func_ref].name, 0); sink.put4(0); @@ -601,7 +601,7 @@ fnaddr8 = TailRecipe( 'fnaddr8', FuncAddr, size=8, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs8, + sink.reloc_external(Reloc::Abs8, &func.dfg.ext_funcs[func_ref].name, 0); sink.put8(0); @@ -612,7 +612,7 @@ allones_fnaddr4 = TailRecipe( 'allones_fnaddr4', FuncAddr, size=4, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs4, + sink.reloc_external(Reloc::Abs4, &func.dfg.ext_funcs[func_ref].name, 0); // Write the immediate as `!0` for the benefit of BaldrMonkey. @@ -624,13 +624,28 @@ allones_fnaddr8 = TailRecipe( 'allones_fnaddr8', FuncAddr, size=8, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs8, + sink.reloc_external(Reloc::Abs8, &func.dfg.ext_funcs[func_ref].name, 0); // Write the immediate as `!0` for the benefit of BaldrMonkey. sink.put8(!0); ''') +pcrel_fnaddr8 = TailRecipe( + 'pcrel_fnaddr8', FuncAddr, size=5, ins=(), outs=GPR, + # rex2 gets passed 0 for r/m register because the upper bit of + # r/m doesnt get decoded when in rip-relative addressing mode. + emit=''' + PUT_OP(bits, rex2(0, out_reg0), sink); + modrm_riprel(out_reg0, sink); + // The addend adjusts for the difference between the end of the + // instruction and the beginning of the immediate field. + sink.reloc_external(Reloc::X86PCRel4, + &func.dfg.ext_funcs[func_ref].name, + -4); + sink.put4(0); + ''') + got_fnaddr8 = TailRecipe( 'got_fnaddr8', FuncAddr, size=5, ins=(), outs=GPR, # rex2 gets passed 0 for r/m register because the upper bit of @@ -640,7 +655,7 @@ got_fnaddr8 = TailRecipe( modrm_riprel(out_reg0, sink); // The addend adjusts for the difference between the end of the // instruction and the beginning of the immediate field. - sink.reloc_external(Reloc::IntelGOTPCRel4, + sink.reloc_external(Reloc::X86GOTPCRel4, &func.dfg.ext_funcs[func_ref].name, -4); sink.put4(0); @@ -652,7 +667,7 @@ gvaddr4 = TailRecipe( 'gvaddr4', UnaryGlobalVar, size=4, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs4, + sink.reloc_external(Reloc::Abs4, &func.global_vars[global_var].symbol_name(), 0); sink.put4(0); @@ -663,12 +678,26 @@ gvaddr8 = TailRecipe( 'gvaddr8', UnaryGlobalVar, size=8, ins=(), outs=GPR, emit=''' PUT_OP(bits | (out_reg0 & 7), rex1(out_reg0), sink); - sink.reloc_external(Reloc::IntelAbs8, + sink.reloc_external(Reloc::Abs8, &func.global_vars[global_var].symbol_name(), 0); sink.put8(0); ''') +# XX+rd iq with PCRel4 globalsym relocation. +pcrel_gvaddr8 = TailRecipe( + 'pcrel_gvaddr8', UnaryGlobalVar, size=5, ins=(), outs=GPR, + emit=''' + PUT_OP(bits, rex2(0, out_reg0), sink); + modrm_rm(5, out_reg0, sink); + // The addend adjusts for the difference between the end of the + // instruction and the beginning of the immediate field. + sink.reloc_external(Reloc::X86PCRel4, + &func.global_vars[global_var].symbol_name(), + -4); + sink.put4(0); + ''') + # XX+rd iq with Abs8 globalsym relocation. got_gvaddr8 = TailRecipe( 'got_gvaddr8', UnaryGlobalVar, size=5, ins=(), outs=GPR, @@ -677,7 +706,7 @@ got_gvaddr8 = TailRecipe( modrm_rm(5, out_reg0, sink); // The addend adjusts for the difference between the end of the // instruction and the beginning of the immediate field. - sink.reloc_external(Reloc::IntelGOTPCRel4, + sink.reloc_external(Reloc::X86GOTPCRel4, &func.global_vars[global_var].symbol_name(), -4); sink.put4(0); @@ -1007,9 +1036,11 @@ call_id = TailRecipe( 'call_id', Call, size=4, ins=(), outs=(), emit=''' PUT_OP(bits, BASE_REX, sink); - sink.reloc_external(Reloc::IntelPCRel4, + // The addend adjusts for the difference between the end of the + // instruction and the beginning of the immediate field. + sink.reloc_external(Reloc::X86PCRel4, &func.dfg.ext_funcs[func_ref].name, - 0); + -4); sink.put4(0); ''') @@ -1017,14 +1048,14 @@ call_plt_id = TailRecipe( 'call_plt_id', Call, size=4, ins=(), outs=(), emit=''' PUT_OP(bits, BASE_REX, sink); - sink.reloc_external(Reloc::IntelPLTRel4, + sink.reloc_external(Reloc::X86PLTRel4, &func.dfg.ext_funcs[func_ref].name, -4); sink.put4(0); ''') call_r = TailRecipe( - 'call_r', IndirectCall, size=1, ins=GPR, outs=(), + 'call_r', CallIndirect, size=1, ins=GPR, outs=(), emit=''' PUT_OP(bits, rex1(in_reg0), sink); modrm_r_bits(in_reg0, bits, sink); diff --git a/lib/cretonne/meta/isa/intel/registers.py b/lib/codegen/meta/isa/x86/registers.py similarity index 94% rename from lib/cretonne/meta/isa/intel/registers.py rename to lib/codegen/meta/isa/x86/registers.py index a4832640cd..f463b93a46 100644 --- a/lib/cretonne/meta/isa/intel/registers.py +++ b/lib/codegen/meta/isa/x86/registers.py @@ -1,9 +1,9 @@ """ -Intel register banks. +x86 register banks. While the floating-point registers are straight-forward, the general purpose -register bank has a few quirks on Intel architectures. We have these encodings -of the 8-bit registers: +register bank has a few quirks on x86. We have these encodings of the 8-bit +registers: I32 I64 | 16b 32b 64b 000 AL AL | AX EAX RAX diff --git a/lib/cretonne/meta/isa/intel/settings.py b/lib/codegen/meta/isa/x86/settings.py similarity index 92% rename from lib/cretonne/meta/isa/intel/settings.py rename to lib/codegen/meta/isa/x86/settings.py index c62012e0c1..70da674fc0 100644 --- a/lib/cretonne/meta/isa/intel/settings.py +++ b/lib/codegen/meta/isa/x86/settings.py @@ -1,5 +1,5 @@ """ -Intel settings. +x86 settings. """ from __future__ import absolute_import from cdsl.settings import SettingGroup, BoolSetting, Preset @@ -7,7 +7,7 @@ from cdsl.predicates import And import base.settings as shared from .defs import ISA -ISA.settings = SettingGroup('intel', parent=shared.group) +ISA.settings = SettingGroup('x86', parent=shared.group) # The has_* settings here correspond to CPUID bits. @@ -35,7 +35,7 @@ use_popcnt = And(has_popcnt, has_sse42) use_bmi1 = And(has_bmi1) use_lzcnt = And(has_lzcnt) -# Presets corresponding to Intel CPUs. +# Presets corresponding to x86 CPUs. baseline = Preset() nehalem = Preset( diff --git a/lib/cretonne/meta/mypy.ini b/lib/codegen/meta/mypy.ini similarity index 100% rename from lib/cretonne/meta/mypy.ini rename to lib/codegen/meta/mypy.ini diff --git a/lib/cretonne/meta/semantics/__init__.py b/lib/codegen/meta/semantics/__init__.py similarity index 100% rename from lib/cretonne/meta/semantics/__init__.py rename to lib/codegen/meta/semantics/__init__.py diff --git a/lib/cretonne/meta/semantics/elaborate.py b/lib/codegen/meta/semantics/elaborate.py similarity index 100% rename from lib/cretonne/meta/semantics/elaborate.py rename to lib/codegen/meta/semantics/elaborate.py diff --git a/lib/cretonne/meta/semantics/macros.py b/lib/codegen/meta/semantics/macros.py similarity index 100% rename from lib/cretonne/meta/semantics/macros.py rename to lib/codegen/meta/semantics/macros.py diff --git a/lib/cretonne/meta/semantics/primitives.py b/lib/codegen/meta/semantics/primitives.py similarity index 100% rename from lib/cretonne/meta/semantics/primitives.py rename to lib/codegen/meta/semantics/primitives.py diff --git a/lib/cretonne/meta/semantics/smtlib.py b/lib/codegen/meta/semantics/smtlib.py similarity index 100% rename from lib/cretonne/meta/semantics/smtlib.py rename to lib/codegen/meta/semantics/smtlib.py diff --git a/lib/cretonne/meta/semantics/test_elaborate.py b/lib/codegen/meta/semantics/test_elaborate.py similarity index 100% rename from lib/cretonne/meta/semantics/test_elaborate.py rename to lib/codegen/meta/semantics/test_elaborate.py diff --git a/lib/cretonne/meta/srcgen.py b/lib/codegen/meta/srcgen.py similarity index 100% rename from lib/cretonne/meta/srcgen.py rename to lib/codegen/meta/srcgen.py diff --git a/lib/cretonne/meta/stubs/z3/__init__.pyi b/lib/codegen/meta/stubs/z3/__init__.pyi similarity index 100% rename from lib/cretonne/meta/stubs/z3/__init__.pyi rename to lib/codegen/meta/stubs/z3/__init__.pyi diff --git a/lib/cretonne/meta/stubs/z3/z3core.pyi b/lib/codegen/meta/stubs/z3/z3core.pyi similarity index 100% rename from lib/cretonne/meta/stubs/z3/z3core.pyi rename to lib/codegen/meta/stubs/z3/z3core.pyi diff --git a/lib/cretonne/meta/stubs/z3/z3types.pyi b/lib/codegen/meta/stubs/z3/z3types.pyi similarity index 100% rename from lib/cretonne/meta/stubs/z3/z3types.pyi rename to lib/codegen/meta/stubs/z3/z3types.pyi diff --git a/lib/cretonne/meta/test_constant_hash.py b/lib/codegen/meta/test_constant_hash.py similarity index 100% rename from lib/cretonne/meta/test_constant_hash.py rename to lib/codegen/meta/test_constant_hash.py diff --git a/lib/cretonne/meta/test_gen_legalizer.py b/lib/codegen/meta/test_gen_legalizer.py similarity index 100% rename from lib/cretonne/meta/test_gen_legalizer.py rename to lib/codegen/meta/test_gen_legalizer.py diff --git a/lib/cretonne/meta/test_srcgen.py b/lib/codegen/meta/test_srcgen.py similarity index 100% rename from lib/cretonne/meta/test_srcgen.py rename to lib/codegen/meta/test_srcgen.py diff --git a/lib/cretonne/meta/unique_table.py b/lib/codegen/meta/unique_table.py similarity index 100% rename from lib/cretonne/meta/unique_table.py rename to lib/codegen/meta/unique_table.py diff --git a/lib/cretonne/src/abi.rs b/lib/codegen/src/abi.rs similarity index 100% rename from lib/cretonne/src/abi.rs rename to lib/codegen/src/abi.rs diff --git a/lib/cretonne/src/bforest/map.rs b/lib/codegen/src/bforest/map.rs similarity index 100% rename from lib/cretonne/src/bforest/map.rs rename to lib/codegen/src/bforest/map.rs diff --git a/lib/cretonne/src/bforest/mod.rs b/lib/codegen/src/bforest/mod.rs similarity index 100% rename from lib/cretonne/src/bforest/mod.rs rename to lib/codegen/src/bforest/mod.rs diff --git a/lib/cretonne/src/bforest/node.rs b/lib/codegen/src/bforest/node.rs similarity index 100% rename from lib/cretonne/src/bforest/node.rs rename to lib/codegen/src/bforest/node.rs diff --git a/lib/cretonne/src/bforest/path.rs b/lib/codegen/src/bforest/path.rs similarity index 100% rename from lib/cretonne/src/bforest/path.rs rename to lib/codegen/src/bforest/path.rs diff --git a/lib/cretonne/src/bforest/pool.rs b/lib/codegen/src/bforest/pool.rs similarity index 100% rename from lib/cretonne/src/bforest/pool.rs rename to lib/codegen/src/bforest/pool.rs diff --git a/lib/cretonne/src/bforest/set.rs b/lib/codegen/src/bforest/set.rs similarity index 100% rename from lib/cretonne/src/bforest/set.rs rename to lib/codegen/src/bforest/set.rs diff --git a/lib/cretonne/src/binemit/memorysink.rs b/lib/codegen/src/binemit/memorysink.rs similarity index 94% rename from lib/cretonne/src/binemit/memorysink.rs rename to lib/codegen/src/binemit/memorysink.rs index bed34cd1ac..34380d2464 100644 --- a/lib/cretonne/src/binemit/memorysink.rs +++ b/lib/codegen/src/binemit/memorysink.rs @@ -123,3 +123,11 @@ impl<'a> CodeSink for MemoryCodeSink<'a> { self.traps.trap(ofs, srcloc, code); } } + +/// A `TrapSink` implementation that does nothing, which is convenient when +/// compiling code that does not rely on trapping semantics. +pub struct NullTrapSink {} + +impl TrapSink for NullTrapSink { + fn trap(&mut self, _offset: CodeOffset, _srcloc: SourceLoc, _code: TrapCode) {} +} diff --git a/lib/cretonne/src/binemit/mod.rs b/lib/codegen/src/binemit/mod.rs similarity index 83% rename from lib/cretonne/src/binemit/mod.rs rename to lib/codegen/src/binemit/mod.rs index ea31abaae5..fbe88cc61f 100644 --- a/lib/cretonne/src/binemit/mod.rs +++ b/lib/codegen/src/binemit/mod.rs @@ -6,7 +6,7 @@ mod memorysink; mod relaxation; -pub use self::memorysink::{MemoryCodeSink, RelocSink, TrapSink}; +pub use self::memorysink::{MemoryCodeSink, RelocSink, TrapSink, NullTrapSink}; pub use self::relaxation::relax_branches; pub use regalloc::RegDiversions; @@ -23,18 +23,18 @@ pub type CodeOffset = u32; pub type Addend = i64; /// Relocation kinds for every ISA -#[derive(Debug)] +#[derive(Copy, Clone, Debug)] pub enum Reloc { - /// Intel PC-relative 4-byte - IntelPCRel4, - /// Intel absolute 4-byte - IntelAbs4, - /// Intel absolute 8-byte - IntelAbs8, - /// Intel GOT PC-relative 4-byte - IntelGOTPCRel4, - /// Intel PLT-relative 4-byte - IntelPLTRel4, + /// absolute 4-byte + Abs4, + /// absolute 8-byte + Abs8, + /// x86 PC-relative 4-byte + X86PCRel4, + /// x86 GOT PC-relative 4-byte + X86GOTPCRel4, + /// x86 PLT-relative 4-byte + X86PLTRel4, /// Arm32 call target Arm32Call, /// Arm64 call target @@ -48,11 +48,11 @@ impl fmt::Display for Reloc { /// already unambigious, e.g. cton syntax with isa specified. In other contexts, use Debug. fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - Reloc::IntelPCRel4 => write!(f, "{}", "PCRel4"), - Reloc::IntelAbs4 => write!(f, "{}", "Abs4"), - Reloc::IntelAbs8 => write!(f, "{}", "Abs8"), - Reloc::IntelGOTPCRel4 => write!(f, "{}", "GOTPCRel4"), - Reloc::IntelPLTRel4 => write!(f, "{}", "PLTRel4"), + Reloc::Abs4 => write!(f, "{}", "Abs4"), + Reloc::Abs8 => write!(f, "{}", "Abs8"), + Reloc::X86PCRel4 => write!(f, "{}", "PCRel4"), + Reloc::X86GOTPCRel4 => write!(f, "{}", "GOTPCRel4"), + Reloc::X86PLTRel4 => write!(f, "{}", "PLTRel4"), Reloc::Arm32Call | Reloc::Arm64Call | Reloc::RiscvCall => write!(f, "{}", "Call"), } } diff --git a/lib/cretonne/src/binemit/relaxation.rs b/lib/codegen/src/binemit/relaxation.rs similarity index 97% rename from lib/cretonne/src/binemit/relaxation.rs rename to lib/codegen/src/binemit/relaxation.rs index 8123c5b92f..93c6afedec 100644 --- a/lib/cretonne/src/binemit/relaxation.rs +++ b/lib/codegen/src/binemit/relaxation.rs @@ -10,7 +10,7 @@ //! //! Branch relaxation is the process of ensuring that all branches in the function have enough //! range to encode their destination. It is common to have multiple branch encodings in an ISA. -//! For example, Intel branches can have either an 8-bit or a 32-bit displacement. +//! For example, x86 branches can have either an 8-bit or a 32-bit displacement. //! //! On RISC architectures, it can happen that conditional branches have a shorter range than //! unconditional branches: @@ -148,7 +148,7 @@ fn relax_branch( // Pick the first encoding that can handle the branch range. let dfg = &cur.func.dfg; let ctrl_type = dfg.ctrl_typevar(inst); - if let Some(enc) = isa.legal_encodings(dfg, &dfg[inst], ctrl_type).find( + if let Some(enc) = isa.legal_encodings(cur.func, &dfg[inst], ctrl_type).find( |&enc| { let range = encinfo.branch_range(enc).expect("Branch with no range"); if !range.contains(offset, dest_offset) { diff --git a/lib/cretonne/src/bitset.rs b/lib/codegen/src/bitset.rs similarity index 100% rename from lib/cretonne/src/bitset.rs rename to lib/codegen/src/bitset.rs diff --git a/lib/cretonne/src/cfg_printer.rs b/lib/codegen/src/cfg_printer.rs similarity index 100% rename from lib/cretonne/src/cfg_printer.rs rename to lib/codegen/src/cfg_printer.rs diff --git a/lib/cretonne/src/constant_hash.rs b/lib/codegen/src/constant_hash.rs similarity index 93% rename from lib/cretonne/src/constant_hash.rs rename to lib/codegen/src/constant_hash.rs index 0dd2895ad3..2bfeaf58c3 100644 --- a/lib/cretonne/src/constant_hash.rs +++ b/lib/codegen/src/constant_hash.rs @@ -1,6 +1,6 @@ //! Runtime support for precomputed constant hash tables. //! -//! The `lib/cretonne/meta/constant_hash.py` Python module can generate constant hash tables using +//! The `lib/codegen/meta/constant_hash.py` Python module can generate constant hash tables using //! open addressing and quadratic probing. The hash tables are arrays that are guaranteed to: //! //! - Have a power-of-two size. @@ -56,7 +56,7 @@ pub fn probe + ?Sized>( } /// A primitive hash function for matching opcodes. -/// Must match `lib/cretonne/meta/constant_hash.py`. +/// Must match `lib/codegen/meta/constant_hash.py`. pub fn simple_hash(s: &str) -> usize { let mut h: u32 = 5381; for c in s.chars() { diff --git a/lib/cretonne/src/context.rs b/lib/codegen/src/context.rs similarity index 100% rename from lib/cretonne/src/context.rs rename to lib/codegen/src/context.rs diff --git a/lib/cretonne/src/cursor.rs b/lib/codegen/src/cursor.rs similarity index 93% rename from lib/cretonne/src/cursor.rs rename to lib/codegen/src/cursor.rs index 082889a693..6842d8b348 100644 --- a/lib/cretonne/src/cursor.rs +++ b/lib/codegen/src/cursor.rs @@ -46,8 +46,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, SourceLoc}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, SourceLoc}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, srcloc: SourceLoc) { /// let mut pos = FuncCursor::new(func).with_srcloc(srcloc); /// @@ -76,8 +76,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, inst: Inst) { /// let mut pos = FuncCursor::new(func).at_inst(inst); /// @@ -99,8 +99,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, ebb: Ebb) { /// let mut pos = FuncCursor::new(func).at_first_insertion_point(ebb); /// @@ -120,8 +120,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, ebb: Ebb) { /// let mut pos = FuncCursor::new(func).at_first_inst(ebb); /// @@ -141,8 +141,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, ebb: Ebb) { /// let mut pos = FuncCursor::new(func).at_last_inst(ebb); /// @@ -162,8 +162,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, inst: Inst) { /// let mut pos = FuncCursor::new(func).after_inst(inst); /// @@ -183,8 +183,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, ebb: Ebb) { /// let mut pos = FuncCursor::new(func).at_top(ebb); /// @@ -204,8 +204,8 @@ pub trait Cursor { /// This is intended to be used as a builder method: /// /// ``` - /// # use cretonne::ir::{Function, Ebb, Inst}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb, Inst}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function, ebb: Ebb) { /// let mut pos = FuncCursor::new(func).at_bottom(ebb); /// @@ -309,8 +309,8 @@ pub trait Cursor { /// The `next_ebb()` method is intended for iterating over the EBBs in layout order: /// /// ``` - /// # use cretonne::ir::{Function, Ebb}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function) { /// let mut cursor = FuncCursor::new(func); /// while let Some(ebb) = cursor.next_ebb() { @@ -342,8 +342,8 @@ pub trait Cursor { /// The `prev_ebb()` method is intended for iterating over the EBBs in backwards layout order: /// /// ``` - /// # use cretonne::ir::{Function, Ebb}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function) { /// let mut cursor = FuncCursor::new(func); /// while let Some(ebb) = cursor.prev_ebb() { @@ -379,8 +379,8 @@ pub trait Cursor { /// this: /// /// ``` - /// # use cretonne::ir::{Function, Ebb}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_ebb(func: &mut Function, ebb: Ebb) { /// let mut cursor = FuncCursor::new(func).at_top(ebb); /// while let Some(inst) = cursor.next_inst() { @@ -393,8 +393,8 @@ pub trait Cursor { /// Iterating over all the instructions in a function looks like this: /// /// ``` - /// # use cretonne::ir::{Function, Ebb}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_func(func: &mut Function) { /// let mut cursor = FuncCursor::new(func); /// while let Some(ebb) = cursor.next_ebb() { @@ -447,8 +447,8 @@ pub trait Cursor { /// EBB like this: /// /// ``` - /// # use cretonne::ir::{Function, Ebb}; - /// # use cretonne::cursor::{Cursor, FuncCursor}; + /// # use cretonne_codegen::ir::{Function, Ebb}; + /// # use cretonne_codegen::cursor::{Cursor, FuncCursor}; /// fn edit_ebb(func: &mut Function, ebb: Ebb) { /// let mut cursor = FuncCursor::new(func).at_bottom(ebb); /// while let Some(inst) = cursor.prev_inst() { @@ -747,7 +747,7 @@ impl<'c, 'f> ir::InstInserterBase<'c> for &'c mut EncCursor<'f> { // XXX Is there a way to describe this error to the user? #[cfg_attr(feature = "cargo-clippy", allow(match_wild_err_arm))] match self.isa.encode( - &self.func.dfg, + &self.func, &self.func.dfg[inst], ctrl_typevar, ) { diff --git a/lib/cretonne/src/dbg.rs b/lib/codegen/src/dbg.rs similarity index 100% rename from lib/cretonne/src/dbg.rs rename to lib/codegen/src/dbg.rs diff --git a/lib/cretonne/src/dce.rs b/lib/codegen/src/dce.rs similarity index 100% rename from lib/cretonne/src/dce.rs rename to lib/codegen/src/dce.rs diff --git a/lib/cretonne/src/divconst_magic_numbers.rs b/lib/codegen/src/divconst_magic_numbers.rs similarity index 100% rename from lib/cretonne/src/divconst_magic_numbers.rs rename to lib/codegen/src/divconst_magic_numbers.rs diff --git a/lib/cretonne/src/dominator_tree.rs b/lib/codegen/src/dominator_tree.rs similarity index 100% rename from lib/cretonne/src/dominator_tree.rs rename to lib/codegen/src/dominator_tree.rs diff --git a/lib/cretonne/src/flowgraph.rs b/lib/codegen/src/flowgraph.rs similarity index 100% rename from lib/cretonne/src/flowgraph.rs rename to lib/codegen/src/flowgraph.rs diff --git a/lib/cretonne/src/ir/builder.rs b/lib/codegen/src/ir/builder.rs similarity index 99% rename from lib/cretonne/src/ir/builder.rs rename to lib/codegen/src/ir/builder.rs index 34f56b9439..e27cda0bcd 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/codegen/src/ir/builder.rs @@ -32,7 +32,7 @@ pub trait InstBuilderBase<'f>: Sized { fn build(self, data: InstructionData, ctrl_typevar: Type) -> (Inst, &'f mut DataFlowGraph); } -// Include trait code generated by `lib/cretonne/meta/gen_instr.py`. +// Include trait code generated by `lib/codegen/meta/gen_instr.py`. // // This file defines the `InstBuilder` trait as an extension of `InstBuilderBase` with methods per // instruction format and per opcode. diff --git a/lib/cretonne/src/ir/condcodes.rs b/lib/codegen/src/ir/condcodes.rs similarity index 100% rename from lib/cretonne/src/ir/condcodes.rs rename to lib/codegen/src/ir/condcodes.rs diff --git a/lib/cretonne/src/ir/dfg.rs b/lib/codegen/src/ir/dfg.rs similarity index 99% rename from lib/cretonne/src/ir/dfg.rs rename to lib/codegen/src/ir/dfg.rs index 24f18ff332..c2f07beb25 100644 --- a/lib/cretonne/src/ir/dfg.rs +++ b/lib/codegen/src/ir/dfg.rs @@ -7,7 +7,7 @@ use ir::extfunc::ExtFuncData; use ir::instructions::{BranchInfo, CallInfo, InstructionData}; use ir::types; use ir::{Ebb, FuncRef, Inst, SigRef, Signature, Type, Value, ValueList, ValueListPool}; -use isa::{Encoding, Legalize, TargetIsa}; +use isa::TargetIsa; use packed_option::ReservedValue; use std::fmt; use std::iter; @@ -660,12 +660,6 @@ impl DataFlowGraph { self.value_type(self.first_result(inst)) } } - - /// Wrapper around `TargetIsa::encode` for encoding an existing instruction - /// in the `DataFlowGraph`. - pub fn encode(&self, inst: Inst, isa: &TargetIsa) -> Result { - isa.encode(&self, &self[inst], self.ctrl_typevar(inst)) - } } /// Allow immutable access to instructions via indexing. diff --git a/lib/cretonne/src/ir/entities.rs b/lib/codegen/src/ir/entities.rs similarity index 100% rename from lib/cretonne/src/ir/entities.rs rename to lib/codegen/src/ir/entities.rs diff --git a/lib/cretonne/src/ir/extfunc.rs b/lib/codegen/src/ir/extfunc.rs similarity index 95% rename from lib/cretonne/src/ir/extfunc.rs rename to lib/codegen/src/ir/extfunc.rs index 45c44c952a..afb32fee81 100644 --- a/lib/cretonne/src/ir/extfunc.rs +++ b/lib/codegen/src/ir/extfunc.rs @@ -19,7 +19,7 @@ use std::vec::Vec; /// /// A signature can optionally include ISA-specific ABI information which specifies exactly how /// arguments and return values are passed. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Signature { /// The arguments passed to the function. pub params: Vec, @@ -123,7 +123,7 @@ impl fmt::Display for Signature { /// /// This describes the value type being passed to or from a function along with flags that affect /// how the argument is passed. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub struct AbiParam { /// Type of the argument value. pub value_type: Type, @@ -225,7 +225,7 @@ impl fmt::Display for AbiParam { /// /// On some architectures, small integer function arguments are extended to the width of a /// general-purpose register. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum ArgumentExtension { /// No extension, high bits are indeterminate. None, @@ -242,7 +242,7 @@ pub enum ArgumentExtension { /// frame pointers and callee-saved registers. /// /// The argument purpose is used to indicate any special meaning of an argument or return value. -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] pub enum ArgumentPurpose { /// A normal user program value passed to or from a function. Normal, @@ -327,11 +327,18 @@ pub struct ExtFuncData { pub name: ExternalName, /// Call signature of function. pub signature: SigRef, + /// Will this function be defined nearby, such that it will always be a certain distance away, + /// after linking? If so, references to it can avoid going through a GOT or PLT. Note that + /// symbols meant to be preemptible cannot be considered colocated. + pub colocated: bool, } impl fmt::Display for ExtFuncData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{} {}", self.signature, self.name) + if self.colocated { + write!(f, "colocated ")?; + } + write!(f, "{} {}", self.name, self.signature) } } @@ -341,7 +348,7 @@ impl fmt::Display for ExtFuncData { /// and how stack frames are managed. Since all of these details depend on both the instruction set /// architecture and possibly the operating system, a function's calling convention is only fully /// determined by a `(TargetIsa, CallConv)` tuple. -#[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] pub enum CallConv { /// The System V-style calling convention. /// diff --git a/lib/cretonne/src/ir/extname.rs b/lib/codegen/src/ir/extname.rs similarity index 96% rename from lib/cretonne/src/ir/extname.rs rename to lib/codegen/src/ir/extname.rs index b37e40086c..f3a69f7e7a 100644 --- a/lib/cretonne/src/ir/extname.rs +++ b/lib/codegen/src/ir/extname.rs @@ -16,7 +16,8 @@ const TESTCASE_NAME_LENGTH: usize = 16; /// to keep track of a sy mbol table. /// /// External names are primarily used as keys by code using Cretonne to map -/// from a `cretonne::ir::FuncRef` or similar to additional associated data. +/// from a `cretonne_codegen::ir::FuncRef` or similar to additional associated +/// data. /// /// External names can also serve as a primitive testing and debugging tool. /// In particular, many `.cton` test files use function names to identify @@ -50,7 +51,7 @@ impl ExternalName { /// # Examples /// /// ```rust - /// # use cretonne::ir::ExternalName; + /// # use cretonne_codegen::ir::ExternalName; /// // Create `ExternalName` from a string. /// let name = ExternalName::testcase("hello"); /// assert_eq!(name.to_string(), "%hello"); @@ -71,7 +72,7 @@ impl ExternalName { /// /// # Examples /// ```rust - /// # use cretonne::ir::ExternalName; + /// # use cretonne_codegen::ir::ExternalName; /// // Create `ExternalName` from integer indicies /// let name = ExternalName::user(123, 456); /// assert_eq!(name.to_string(), "u123:456"); diff --git a/lib/cretonne/src/ir/function.rs b/lib/codegen/src/ir/function.rs similarity index 94% rename from lib/cretonne/src/ir/function.rs rename to lib/codegen/src/ir/function.rs index 19baa16b2b..5e70ff3780 100644 --- a/lib/cretonne/src/ir/function.rs +++ b/lib/codegen/src/ir/function.rs @@ -10,7 +10,7 @@ use ir::{CallConv, DataFlowGraph, ExternalName, Layout, Signature}; use ir::{Ebb, ExtFuncData, FuncRef, GlobalVar, GlobalVarData, Heap, HeapData, JumpTable, JumpTableData, SigRef, StackSlot, StackSlotData}; use ir::{EbbOffsets, InstEncodings, JumpTables, SourceLocs, StackSlots, ValueLocations}; -use isa::{EncInfo, Legalize, TargetIsa}; +use isa::{EncInfo, Legalize, TargetIsa, Encoding}; use std::fmt; use write::write_function; @@ -177,11 +177,15 @@ impl Function { } } - /// Wrapper around `DataFlowGraph::encode` which assigns `inst` the resulting encoding. + /// Wrapper around `encode` which assigns `inst` the resulting encoding. pub fn update_encoding(&mut self, inst: ir::Inst, isa: &TargetIsa) -> Result<(), Legalize> { - self.dfg.encode(inst, isa).map( - |e| { self.encodings[inst] = e; }, - ) + self.encode(inst, isa).map(|e| self.encodings[inst] = e) + } + + /// Wrapper around `TargetIsa::encode` for encoding an existing instruction + /// in the `Function`. + pub fn encode(&self, inst: ir::Inst, isa: &TargetIsa) -> Result { + isa.encode(&self, &self.dfg[inst], self.dfg.ctrl_typevar(inst)) } } diff --git a/lib/cretonne/src/ir/globalvar.rs b/lib/codegen/src/ir/globalvar.rs similarity index 70% rename from lib/cretonne/src/ir/globalvar.rs rename to lib/codegen/src/ir/globalvar.rs index 228f691d84..399f3b7ae4 100644 --- a/lib/cretonne/src/ir/globalvar.rs +++ b/lib/codegen/src/ir/globalvar.rs @@ -9,7 +9,7 @@ use std::fmt; pub enum GlobalVarData { /// Variable is part of the VM context struct, it's address is a constant offset from the VM /// context pointer. - VmCtx { + VMContext { /// Offset from the `vmctx` pointer to this global. offset: Offset32, }, @@ -33,6 +33,11 @@ pub enum GlobalVarData { Sym { /// The symbolic name. name: ExternalName, + + /// Will this variable be defined nearby, such that it will always be a certain distance + /// away, after linking? If so, references to it can avoid going through a GOT. Note that + /// symbols meant to be preemptible cannot be colocated. + colocated: bool, }, } @@ -40,7 +45,7 @@ impl GlobalVarData { /// Assume that `self` is an `GlobalVarData::Sym` and return its name. pub fn symbol_name(&self) -> &ExternalName { match *self { - GlobalVarData::Sym { ref name } => name, + GlobalVarData::Sym { ref name, .. } => name, _ => panic!("only symbols have names"), } } @@ -49,9 +54,17 @@ impl GlobalVarData { impl fmt::Display for GlobalVarData { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match *self { - GlobalVarData::VmCtx { offset } => write!(f, "vmctx{}", offset), + GlobalVarData::VMContext { offset } => write!(f, "vmctx{}", offset), GlobalVarData::Deref { base, offset } => write!(f, "deref({}){}", base, offset), - GlobalVarData::Sym { ref name } => write!(f, "globalsym {}", name), + GlobalVarData::Sym { + ref name, + colocated, + } => { + if colocated { + write!(f, "colocated ")?; + } + write!(f, "globalsym {}", name) + } } } } diff --git a/lib/cretonne/src/ir/heap.rs b/lib/codegen/src/ir/heap.rs similarity index 100% rename from lib/cretonne/src/ir/heap.rs rename to lib/codegen/src/ir/heap.rs diff --git a/lib/cretonne/src/ir/immediates.rs b/lib/codegen/src/ir/immediates.rs similarity index 100% rename from lib/cretonne/src/ir/immediates.rs rename to lib/codegen/src/ir/immediates.rs diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/codegen/src/ir/instructions.rs similarity index 99% rename from lib/cretonne/src/ir/instructions.rs rename to lib/codegen/src/ir/instructions.rs index aa6a35df3f..d4ca4a1396 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/codegen/src/ir/instructions.rs @@ -28,7 +28,7 @@ pub type ValueList = entity::EntityList; /// Memory pool for holding value lists. See `ValueList`. pub type ValueListPool = entity::ListPool; -// Include code generated by `lib/cretonne/meta/gen_instr.py`. This file contains: +// Include code generated by `lib/codegen/meta/gen_instr.py`. This file contains: // // - The `pub enum InstructionFormat` enum with all the instruction formats. // - The `pub enum InstructionData` enum with all the instruction data fields. @@ -248,7 +248,7 @@ impl InstructionData { InstructionData::Call { func_ref, ref args, .. } => { CallInfo::Direct(func_ref, args.as_slice(pool)) } - InstructionData::IndirectCall { sig_ref, ref args, .. } => { + InstructionData::CallIndirect { sig_ref, ref args, .. } => { CallInfo::Indirect(sig_ref, &args.as_slice(pool)[1..]) } _ => { diff --git a/lib/cretonne/src/ir/jumptable.rs b/lib/codegen/src/ir/jumptable.rs similarity index 100% rename from lib/cretonne/src/ir/jumptable.rs rename to lib/codegen/src/ir/jumptable.rs diff --git a/lib/cretonne/src/ir/layout.rs b/lib/codegen/src/ir/layout.rs similarity index 100% rename from lib/cretonne/src/ir/layout.rs rename to lib/codegen/src/ir/layout.rs diff --git a/lib/cretonne/src/ir/libcall.rs b/lib/codegen/src/ir/libcall.rs similarity index 100% rename from lib/cretonne/src/ir/libcall.rs rename to lib/codegen/src/ir/libcall.rs diff --git a/lib/cretonne/src/ir/memflags.rs b/lib/codegen/src/ir/memflags.rs similarity index 100% rename from lib/cretonne/src/ir/memflags.rs rename to lib/codegen/src/ir/memflags.rs diff --git a/lib/cretonne/src/ir/mod.rs b/lib/codegen/src/ir/mod.rs similarity index 100% rename from lib/cretonne/src/ir/mod.rs rename to lib/codegen/src/ir/mod.rs diff --git a/lib/cretonne/src/ir/progpoint.rs b/lib/codegen/src/ir/progpoint.rs similarity index 100% rename from lib/cretonne/src/ir/progpoint.rs rename to lib/codegen/src/ir/progpoint.rs diff --git a/lib/cretonne/src/ir/sourceloc.rs b/lib/codegen/src/ir/sourceloc.rs similarity index 100% rename from lib/cretonne/src/ir/sourceloc.rs rename to lib/codegen/src/ir/sourceloc.rs diff --git a/lib/cretonne/src/ir/stackslot.rs b/lib/codegen/src/ir/stackslot.rs similarity index 98% rename from lib/cretonne/src/ir/stackslot.rs rename to lib/codegen/src/ir/stackslot.rs index 9dfcfa7d21..bdf2c95825 100644 --- a/lib/cretonne/src/ir/stackslot.rs +++ b/lib/codegen/src/ir/stackslot.rs @@ -107,9 +107,8 @@ pub struct StackSlotData { /// Offset of stack slot relative to the stack pointer in the caller. /// - /// On Intel ISAs, the base address is the stack pointer *before* the return address was - /// pushed. On RISC ISAs, the base address is the value of the stack pointer on entry to the - /// function. + /// On x86, the base address is the stack pointer *before* the return address was pushed. On + /// RISC ISAs, the base address is the value of the stack pointer on entry to the function. /// /// For `OutgoingArg` stack slots, the offset is relative to the current function's stack /// pointer immediately before the call. diff --git a/lib/cretonne/src/ir/trapcode.rs b/lib/codegen/src/ir/trapcode.rs similarity index 100% rename from lib/cretonne/src/ir/trapcode.rs rename to lib/codegen/src/ir/trapcode.rs diff --git a/lib/cretonne/src/ir/types.rs b/lib/codegen/src/ir/types.rs similarity index 99% rename from lib/cretonne/src/ir/types.rs rename to lib/codegen/src/ir/types.rs index 496312b1c4..3dc71454de 100644 --- a/lib/cretonne/src/ir/types.rs +++ b/lib/codegen/src/ir/types.rs @@ -30,7 +30,7 @@ const LANE_BASE: u8 = 0x70; /// Start of the 2-lane vector types. const VECTOR_BASE: u8 = LANE_BASE + 16; -// Include code generated by `lib/cretonne/meta/gen_types.py`. This file contains constant +// Include code generated by `lib/codegen/meta/gen_types.py`. This file contains constant // definitions for all the scalar types as well as common vector types for 64, 128, 256, and // 512-bit SIMD vectors. include!(concat!(env!("OUT_DIR"), "/types.rs")); diff --git a/lib/cretonne/src/ir/valueloc.rs b/lib/codegen/src/ir/valueloc.rs similarity index 99% rename from lib/cretonne/src/ir/valueloc.rs rename to lib/codegen/src/ir/valueloc.rs index aecf23d0bb..7f68e09792 100644 --- a/lib/cretonne/src/ir/valueloc.rs +++ b/lib/codegen/src/ir/valueloc.rs @@ -95,7 +95,7 @@ impl<'a> fmt::Display for DisplayValueLoc<'a> { /// outgoing arguments. /// - For register arguments, there is usually no difference, but if we ever add support for a /// register-window ISA like SPARC, register arguments would also need to be translated. -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] pub enum ArgumentLoc { /// This argument has not been assigned to a location yet. Unassigned, diff --git a/lib/cretonne/src/isa/arm32/abi.rs b/lib/codegen/src/isa/arm32/abi.rs similarity index 87% rename from lib/cretonne/src/isa/arm32/abi.rs rename to lib/codegen/src/isa/arm32/abi.rs index 528a396570..1305685825 100644 --- a/lib/cretonne/src/isa/arm32/abi.rs +++ b/lib/codegen/src/isa/arm32/abi.rs @@ -3,7 +3,7 @@ use super::registers::{D, GPR, Q, S}; use ir; use isa::RegClass; -use regalloc::AllocatableSet; +use regalloc::RegisterSet; use settings as shared_settings; /// Legalize `sig`. @@ -30,6 +30,6 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { } /// Get the set of allocatable registers for `func`. -pub fn allocatable_registers(_func: &ir::Function) -> AllocatableSet { +pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet { unimplemented!() } diff --git a/lib/cretonne/src/isa/arm32/binemit.rs b/lib/codegen/src/isa/arm32/binemit.rs similarity index 100% rename from lib/cretonne/src/isa/arm32/binemit.rs rename to lib/codegen/src/isa/arm32/binemit.rs diff --git a/lib/cretonne/src/isa/arm32/enc_tables.rs b/lib/codegen/src/isa/arm32/enc_tables.rs similarity index 100% rename from lib/cretonne/src/isa/arm32/enc_tables.rs rename to lib/codegen/src/isa/arm32/enc_tables.rs diff --git a/lib/cretonne/src/isa/arm32/mod.rs b/lib/codegen/src/isa/arm32/mod.rs similarity index 97% rename from lib/cretonne/src/isa/arm32/mod.rs rename to lib/codegen/src/isa/arm32/mod.rs index 350764a436..967c21a1ba 100644 --- a/lib/cretonne/src/isa/arm32/mod.rs +++ b/lib/codegen/src/isa/arm32/mod.rs @@ -66,14 +66,14 @@ impl TargetIsa for Isa { fn legal_encodings<'a>( &'a self, - dfg: &'a ir::DataFlowGraph, + func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a> { lookup_enclist( ctrl_typevar, inst, - dfg, + func, self.cpumode, &enc_tables::LEVEL2[..], &enc_tables::ENCLISTS[..], @@ -92,7 +92,7 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet { abi::allocatable_registers(func) } diff --git a/lib/cretonne/src/isa/arm32/registers.rs b/lib/codegen/src/isa/arm32/registers.rs similarity index 100% rename from lib/cretonne/src/isa/arm32/registers.rs rename to lib/codegen/src/isa/arm32/registers.rs diff --git a/lib/cretonne/src/isa/arm32/settings.rs b/lib/codegen/src/isa/arm32/settings.rs similarity index 58% rename from lib/cretonne/src/isa/arm32/settings.rs rename to lib/codegen/src/isa/arm32/settings.rs index b502deee40..ed7dd01281 100644 --- a/lib/cretonne/src/isa/arm32/settings.rs +++ b/lib/codegen/src/isa/arm32/settings.rs @@ -3,7 +3,7 @@ use settings::{self, detail, Builder}; use std::fmt; -// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// Include code generated by `lib/codegen/meta/gen_settings.py`. This file contains a public // `Flags` struct with an impl for all of the settings defined in -// `lib/cretonne/meta/isa/arm32/settings.py`. +// `lib/codegen/meta/isa/arm32/settings.py`. include!(concat!(env!("OUT_DIR"), "/settings-arm32.rs")); diff --git a/lib/cretonne/src/isa/arm64/abi.rs b/lib/codegen/src/isa/arm64/abi.rs similarity index 84% rename from lib/cretonne/src/isa/arm64/abi.rs rename to lib/codegen/src/isa/arm64/abi.rs index 0540746afa..4bd9aad7be 100644 --- a/lib/cretonne/src/isa/arm64/abi.rs +++ b/lib/codegen/src/isa/arm64/abi.rs @@ -3,7 +3,7 @@ use super::registers::{FPR, GPR}; use ir; use isa::RegClass; -use regalloc::AllocatableSet; +use regalloc::RegisterSet; use settings as shared_settings; /// Legalize `sig`. @@ -21,6 +21,6 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { } /// Get the set of allocatable registers for `func`. -pub fn allocatable_registers(_func: &ir::Function) -> AllocatableSet { +pub fn allocatable_registers(_func: &ir::Function) -> RegisterSet { unimplemented!() } diff --git a/lib/cretonne/src/isa/arm64/binemit.rs b/lib/codegen/src/isa/arm64/binemit.rs similarity index 100% rename from lib/cretonne/src/isa/arm64/binemit.rs rename to lib/codegen/src/isa/arm64/binemit.rs diff --git a/lib/cretonne/src/isa/arm64/enc_tables.rs b/lib/codegen/src/isa/arm64/enc_tables.rs similarity index 100% rename from lib/cretonne/src/isa/arm64/enc_tables.rs rename to lib/codegen/src/isa/arm64/enc_tables.rs diff --git a/lib/cretonne/src/isa/arm64/mod.rs b/lib/codegen/src/isa/arm64/mod.rs similarity index 97% rename from lib/cretonne/src/isa/arm64/mod.rs rename to lib/codegen/src/isa/arm64/mod.rs index 3b63d56d54..27c95f51b3 100644 --- a/lib/cretonne/src/isa/arm64/mod.rs +++ b/lib/codegen/src/isa/arm64/mod.rs @@ -59,14 +59,14 @@ impl TargetIsa for Isa { fn legal_encodings<'a>( &'a self, - dfg: &'a ir::DataFlowGraph, + func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a> { lookup_enclist( ctrl_typevar, inst, - dfg, + func, &enc_tables::LEVEL1_A64[..], &enc_tables::LEVEL2[..], &enc_tables::ENCLISTS[..], @@ -85,7 +85,7 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet { abi::allocatable_registers(func) } diff --git a/lib/cretonne/src/isa/arm64/registers.rs b/lib/codegen/src/isa/arm64/registers.rs similarity index 100% rename from lib/cretonne/src/isa/arm64/registers.rs rename to lib/codegen/src/isa/arm64/registers.rs diff --git a/lib/cretonne/src/isa/arm64/settings.rs b/lib/codegen/src/isa/arm64/settings.rs similarity index 58% rename from lib/cretonne/src/isa/arm64/settings.rs rename to lib/codegen/src/isa/arm64/settings.rs index b575168361..cdaa129b2d 100644 --- a/lib/cretonne/src/isa/arm64/settings.rs +++ b/lib/codegen/src/isa/arm64/settings.rs @@ -3,7 +3,7 @@ use settings::{self, detail, Builder}; use std::fmt; -// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// Include code generated by `lib/codegen/meta/gen_settings.py`. This file contains a public // `Flags` struct with an impl for all of the settings defined in -// `lib/cretonne/meta/isa/arm64/settings.py`. +// `lib/codegen/meta/isa/arm64/settings.py`. include!(concat!(env!("OUT_DIR"), "/settings-arm64.rs")); diff --git a/lib/cretonne/src/isa/constraints.rs b/lib/codegen/src/isa/constraints.rs similarity index 98% rename from lib/cretonne/src/isa/constraints.rs rename to lib/codegen/src/isa/constraints.rs index b08f635ba4..b9a4838a9d 100644 --- a/lib/cretonne/src/isa/constraints.rs +++ b/lib/codegen/src/isa/constraints.rs @@ -158,7 +158,7 @@ impl RecipeConstraints { /// The origin depends on the ISA and the specific instruction: /// /// - RISC-V and ARM Aarch64 use the address of the branch instruction, `origin = 0`. -/// - Intel uses the address of the instruction following the branch, `origin = 2` for a 2-byte +/// - x86 uses the address of the instruction following the branch, `origin = 2` for a 2-byte /// branch instruction. /// - ARM's A32 encoding uses the address of the branch instruction + 8 bytes, `origin = 8`. #[derive(Clone, Copy, Debug)] diff --git a/lib/cretonne/src/isa/enc_tables.rs b/lib/codegen/src/isa/enc_tables.rs similarity index 96% rename from lib/cretonne/src/isa/enc_tables.rs rename to lib/codegen/src/isa/enc_tables.rs index c987606fa6..b3deb85de1 100644 --- a/lib/cretonne/src/isa/enc_tables.rs +++ b/lib/codegen/src/isa/enc_tables.rs @@ -1,10 +1,10 @@ //! Support types for generated encoding tables. //! //! This module contains types and functions for working with the encoding tables generated by -//! `lib/cretonne/meta/gen_encoding.py`. +//! `lib/codegen/meta/gen_encoding.py`. use constant_hash::{probe, Table}; -use ir::{DataFlowGraph, InstructionData, Opcode, Type}; +use ir::{Function, InstructionData, Opcode, Type}; use isa::{Encoding, Legalize}; use settings::PredicateView; use std::ops::Range; @@ -20,7 +20,7 @@ pub type RecipePredicate = Option bool>; /// /// This is a predicate function that needs to be tested in addition to the recipe predicate. It /// can't depend on ISA settings. -pub type InstPredicate = fn(&DataFlowGraph, &InstructionData) -> bool; +pub type InstPredicate = fn(&Function, &InstructionData) -> bool; /// Legalization action to perform when no encoding can be found for an instruction. /// @@ -106,7 +106,7 @@ impl + Copy> Table for [Level2Entry] { pub fn lookup_enclist<'a, OffT1, OffT2>( ctrl_typevar: Type, inst: &'a InstructionData, - dfg: &'a DataFlowGraph, + func: &'a Function, level1_table: &'static [Level1Entry], level2_table: &'static [Level2Entry], enclist: &'static [EncListEntry], @@ -150,7 +150,7 @@ where offset, legalize, inst, - dfg, + func, enclist, legalize_actions, recipe_preds, @@ -177,7 +177,7 @@ pub struct Encodings<'a> { // Legalization code to use of no encoding is found. legalize: LegalizeCode, inst: &'a InstructionData, - dfg: &'a DataFlowGraph, + func: &'a Function, enclist: &'static [EncListEntry], legalize_actions: &'static [Legalize], recipe_preds: &'static [RecipePredicate], @@ -195,7 +195,7 @@ impl<'a> Encodings<'a> { offset: usize, legalize: LegalizeCode, inst: &'a InstructionData, - dfg: &'a DataFlowGraph, + func: &'a Function, enclist: &'static [EncListEntry], legalize_actions: &'static [Legalize], recipe_preds: &'static [RecipePredicate], @@ -205,7 +205,7 @@ impl<'a> Encodings<'a> { Encodings { offset, inst, - dfg, + func, legalize, isa_preds, recipe_preds, @@ -236,7 +236,7 @@ impl<'a> Encodings<'a> { /// Check an instruction or isa predicate. fn check_pred(&self, pred: usize) -> bool { if let Some(&p) = self.inst_preds.get(pred) { - p(self.dfg, self.inst) + p(self.func, self.inst) } else { let pred = pred - self.inst_preds.len(); self.isa_preds.test(pred) diff --git a/lib/cretonne/src/isa/encoding.rs b/lib/codegen/src/isa/encoding.rs similarity index 100% rename from lib/cretonne/src/isa/encoding.rs rename to lib/codegen/src/isa/encoding.rs diff --git a/lib/cretonne/src/isa/mod.rs b/lib/codegen/src/isa/mod.rs similarity index 97% rename from lib/cretonne/src/isa/mod.rs rename to lib/codegen/src/isa/mod.rs index 39d7d4eb60..a8d8616858 100644 --- a/lib/cretonne/src/isa/mod.rs +++ b/lib/codegen/src/isa/mod.rs @@ -20,8 +20,8 @@ //! appropriate for the requested ISA: //! //! ``` -//! use cretonne::settings::{self, Configurable}; -//! use cretonne::isa; +//! use cretonne_codegen::settings::{self, Configurable}; +//! use cretonne_codegen::isa; //! //! let shared_builder = settings::builder(); //! let shared_flags = settings::Flags::new(&shared_builder); @@ -59,8 +59,8 @@ use timing; #[cfg(build_riscv)] mod riscv; -#[cfg(build_intel)] -mod intel; +#[cfg(build_x86)] +mod x86; #[cfg(build_arm32)] mod arm32; @@ -95,7 +95,7 @@ macro_rules! isa_builder { pub fn lookup(name: &str) -> Result { match name { "riscv" => isa_builder!(riscv, build_riscv), - "intel" => isa_builder!(intel, build_intel), + "x86" => isa_builder!(x86, build_x86), "arm32" => isa_builder!(arm32, build_arm32), "arm64" => isa_builder!(arm64, build_arm64), _ => Err(LookupError::Unknown), @@ -167,7 +167,7 @@ pub trait TargetIsa: fmt::Display { /// Returns an iterartor over legal encodings for the instruction. fn legal_encodings<'a>( &'a self, - dfg: &'a ir::DataFlowGraph, + func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a>; @@ -180,11 +180,11 @@ pub trait TargetIsa: fmt::Display { /// This is also the main entry point for determining if an instruction is legal. fn encode( &self, - dfg: &ir::DataFlowGraph, + func: &ir::Function, inst: &ir::InstructionData, ctrl_typevar: ir::Type, ) -> Result { - let mut iter = self.legal_encodings(dfg, inst, ctrl_typevar); + let mut iter = self.legal_encodings(func, inst, ctrl_typevar); iter.next().ok_or_else(|| iter.legalize()) } @@ -238,7 +238,7 @@ pub trait TargetIsa: fmt::Display { /// /// This set excludes reserved registers like the stack pointer and other special-purpose /// registers. - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet; + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet; /// Compute the stack layout and insert prologue and epilogue code into `func`. /// diff --git a/lib/cretonne/src/isa/registers.rs b/lib/codegen/src/isa/registers.rs similarity index 100% rename from lib/cretonne/src/isa/registers.rs rename to lib/codegen/src/isa/registers.rs diff --git a/lib/cretonne/src/isa/riscv/abi.rs b/lib/codegen/src/isa/riscv/abi.rs similarity index 97% rename from lib/cretonne/src/isa/riscv/abi.rs rename to lib/codegen/src/isa/riscv/abi.rs index 0782fa5e53..96e532e827 100644 --- a/lib/cretonne/src/isa/riscv/abi.rs +++ b/lib/codegen/src/isa/riscv/abi.rs @@ -10,7 +10,7 @@ use super::settings; use abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion}; use ir::{self, AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, Type}; use isa::RegClass; -use regalloc::AllocatableSet; +use regalloc::RegisterSet; use settings as shared_settings; use std::i32; @@ -120,8 +120,8 @@ pub fn regclass_for_abi_type(ty: Type) -> RegClass { if ty.is_float() { FPR } else { GPR } } -pub fn allocatable_registers(_func: &ir::Function, isa_flags: &settings::Flags) -> AllocatableSet { - let mut regs = AllocatableSet::new(); +pub fn allocatable_registers(_func: &ir::Function, isa_flags: &settings::Flags) -> RegisterSet { + let mut regs = RegisterSet::new(); regs.take(GPR, GPR.unit(0)); // Hard-wired 0. // %x1 is the link register which is available for allocation. regs.take(GPR, GPR.unit(2)); // Stack pointer. diff --git a/lib/cretonne/src/isa/riscv/binemit.rs b/lib/codegen/src/isa/riscv/binemit.rs similarity index 100% rename from lib/cretonne/src/isa/riscv/binemit.rs rename to lib/codegen/src/isa/riscv/binemit.rs diff --git a/lib/cretonne/src/isa/riscv/enc_tables.rs b/lib/codegen/src/isa/riscv/enc_tables.rs similarity index 100% rename from lib/cretonne/src/isa/riscv/enc_tables.rs rename to lib/codegen/src/isa/riscv/enc_tables.rs diff --git a/lib/cretonne/src/isa/riscv/mod.rs b/lib/codegen/src/isa/riscv/mod.rs similarity index 84% rename from lib/cretonne/src/isa/riscv/mod.rs rename to lib/codegen/src/isa/riscv/mod.rs index 9c3a498d5e..af993aad0d 100644 --- a/lib/cretonne/src/isa/riscv/mod.rs +++ b/lib/codegen/src/isa/riscv/mod.rs @@ -66,14 +66,14 @@ impl TargetIsa for Isa { fn legal_encodings<'a>( &'a self, - dfg: &'a ir::DataFlowGraph, + func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a> { lookup_enclist( ctrl_typevar, inst, - dfg, + func, self.cpumode, &enc_tables::LEVEL2[..], &enc_tables::ENCLISTS[..], @@ -92,7 +92,7 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet { abi::allocatable_registers(func, &self.isa_flags) } @@ -113,7 +113,7 @@ impl TargetIsa for Isa { #[cfg(test)] mod tests { - use ir::{DataFlowGraph, InstructionData, Opcode}; + use ir::{Function, InstructionData, Opcode}; use ir::{immediates, types}; use isa; use settings::{self, Configurable}; @@ -133,10 +133,10 @@ mod tests { let shared_flags = settings::Flags::new(&shared_builder); let isa = isa::lookup("riscv").unwrap().finish(shared_flags); - let mut dfg = DataFlowGraph::new(); - let ebb = dfg.make_ebb(); - let arg64 = dfg.append_ebb_param(ebb, types::I64); - let arg32 = dfg.append_ebb_param(ebb, types::I32); + let mut func = Function::new(); + let ebb = func.dfg.make_ebb(); + let arg64 = func.dfg.append_ebb_param(ebb, types::I64); + let arg32 = func.dfg.append_ebb_param(ebb, types::I32); // Try to encode iadd_imm.i64 v1, -10. let inst64 = InstructionData::BinaryImm { @@ -147,7 +147,7 @@ mod tests { // ADDI is I/0b00100 assert_eq!( - encstr(&*isa, isa.encode(&dfg, &inst64, types::I64)), + encstr(&*isa, isa.encode(&func, &inst64, types::I64)), "Ii#04" ); @@ -159,7 +159,7 @@ mod tests { }; // Immediate is out of range for ADDI. - assert!(isa.encode(&dfg, &inst64_large, types::I64).is_err()); + assert!(isa.encode(&func, &inst64_large, types::I64).is_err()); // Create an iadd_imm.i32 which is encodable in RV64. let inst32 = InstructionData::BinaryImm { @@ -170,7 +170,7 @@ mod tests { // ADDIW is I/0b00110 assert_eq!( - encstr(&*isa, isa.encode(&dfg, &inst32, types::I32)), + encstr(&*isa, isa.encode(&func, &inst32, types::I32)), "Ii#06" ); } @@ -183,10 +183,10 @@ mod tests { let shared_flags = settings::Flags::new(&shared_builder); let isa = isa::lookup("riscv").unwrap().finish(shared_flags); - let mut dfg = DataFlowGraph::new(); - let ebb = dfg.make_ebb(); - let arg64 = dfg.append_ebb_param(ebb, types::I64); - let arg32 = dfg.append_ebb_param(ebb, types::I32); + let mut func = Function::new(); + let ebb = func.dfg.make_ebb(); + let arg64 = func.dfg.append_ebb_param(ebb, types::I64); + let arg32 = func.dfg.append_ebb_param(ebb, types::I32); // Try to encode iadd_imm.i64 v1, -10. let inst64 = InstructionData::BinaryImm { @@ -196,7 +196,7 @@ mod tests { }; // In 32-bit mode, an i64 bit add should be narrowed. - assert!(isa.encode(&dfg, &inst64, types::I64).is_err()); + assert!(isa.encode(&func, &inst64, types::I64).is_err()); // Try to encode iadd_imm.i64 v1, -10000. let inst64_large = InstructionData::BinaryImm { @@ -206,7 +206,7 @@ mod tests { }; // In 32-bit mode, an i64 bit add should be narrowed. - assert!(isa.encode(&dfg, &inst64_large, types::I64).is_err()); + assert!(isa.encode(&func, &inst64_large, types::I64).is_err()); // Create an iadd_imm.i32 which is encodable in RV32. let inst32 = InstructionData::BinaryImm { @@ -217,7 +217,7 @@ mod tests { // ADDI is I/0b00100 assert_eq!( - encstr(&*isa, isa.encode(&dfg, &inst32, types::I32)), + encstr(&*isa, isa.encode(&func, &inst32, types::I32)), "Ii#04" ); @@ -227,7 +227,7 @@ mod tests { args: [arg32, arg32], }; - assert!(isa.encode(&dfg, &mul32, types::I32).is_err()); + assert!(isa.encode(&func, &mul32, types::I32).is_err()); } #[test] @@ -243,16 +243,19 @@ mod tests { let isa = isa_builder.finish(shared_flags); - let mut dfg = DataFlowGraph::new(); - let ebb = dfg.make_ebb(); - let arg32 = dfg.append_ebb_param(ebb, types::I32); + let mut func = Function::new(); + let ebb = func.dfg.make_ebb(); + let arg32 = func.dfg.append_ebb_param(ebb, types::I32); // Create an imul.i32 which is encodable in RV32M. let mul32 = InstructionData::Binary { opcode: Opcode::Imul, args: [arg32, arg32], }; - assert_eq!(encstr(&*isa, isa.encode(&dfg, &mul32, types::I32)), "R#10c"); + assert_eq!( + encstr(&*isa, isa.encode(&func, &mul32, types::I32)), + "R#10c" + ); } } diff --git a/lib/cretonne/src/isa/riscv/registers.rs b/lib/codegen/src/isa/riscv/registers.rs similarity index 100% rename from lib/cretonne/src/isa/riscv/registers.rs rename to lib/codegen/src/isa/riscv/registers.rs diff --git a/lib/cretonne/src/isa/riscv/settings.rs b/lib/codegen/src/isa/riscv/settings.rs similarity index 91% rename from lib/cretonne/src/isa/riscv/settings.rs rename to lib/codegen/src/isa/riscv/settings.rs index 27cba43f2f..4a127b578a 100644 --- a/lib/cretonne/src/isa/riscv/settings.rs +++ b/lib/codegen/src/isa/riscv/settings.rs @@ -3,9 +3,9 @@ use settings::{self, detail, Builder}; use std::fmt; -// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// Include code generated by `lib/codegen/meta/gen_settings.py`. This file contains a public // `Flags` struct with an impl for all of the settings defined in -// `lib/cretonne/meta/isa/riscv/settings.py`. +// `lib/codegen/meta/isa/riscv/settings.py`. include!(concat!(env!("OUT_DIR"), "/settings-riscv.rs")); #[cfg(test)] diff --git a/lib/cretonne/src/isa/stack.rs b/lib/codegen/src/isa/stack.rs similarity index 100% rename from lib/cretonne/src/isa/stack.rs rename to lib/codegen/src/isa/stack.rs diff --git a/lib/cretonne/src/isa/intel/abi.rs b/lib/codegen/src/isa/x86/abi.rs similarity index 79% rename from lib/cretonne/src/isa/intel/abi.rs rename to lib/codegen/src/isa/x86/abi.rs index e9019291ef..16cea926b8 100644 --- a/lib/cretonne/src/isa/intel/abi.rs +++ b/lib/codegen/src/isa/x86/abi.rs @@ -1,4 +1,4 @@ -//! Intel ABI implementation. +//! x86 ABI implementation. use super::registers::{FPR, GPR, RU}; use abi::{legalize_args, ArgAction, ArgAssigner, ValueConversion}; @@ -6,9 +6,10 @@ use cursor::{Cursor, CursorPosition, EncCursor}; use ir; use ir::immediates::Imm64; use ir::stackslot::{StackOffset, StackSize}; -use ir::{AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, CallConv, InstBuilder}; +use ir::{AbiParam, ArgumentExtension, ArgumentLoc, ArgumentPurpose, CallConv, InstBuilder, + ValueLoc}; use isa::{RegClass, RegUnit, TargetIsa}; -use regalloc::AllocatableSet; +use regalloc::RegisterSet; use result; use settings as shared_settings; use stack_layout::layout_stack; @@ -140,11 +141,8 @@ pub fn regclass_for_abi_type(ty: ir::Type) -> RegClass { } /// Get the set of allocatable registers for `func`. -pub fn allocatable_registers( - _func: &ir::Function, - flags: &shared_settings::Flags, -) -> AllocatableSet { - let mut regs = AllocatableSet::new(); +pub fn allocatable_registers(_func: &ir::Function, flags: &shared_settings::Flags) -> RegisterSet { + let mut regs = RegisterSet::new(); regs.take(GPR, RU::rsp as RegUnit); regs.take(GPR, RU::rbp as RegUnit); @@ -160,7 +158,7 @@ pub fn allocatable_registers( } /// Get the set of callee-saved registers. -pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] { +fn callee_saved_gprs(flags: &shared_settings::Flags) -> &'static [RU] { if flags.is_64bit() { &[RU::rbx, RU::r12, RU::r13, RU::r14, RU::r15] } else { @@ -168,6 +166,48 @@ pub fn callee_saved_registers(flags: &shared_settings::Flags) -> &'static [RU] { } } +fn callee_saved_gprs_used(flags: &shared_settings::Flags, func: &ir::Function) -> RegisterSet { + let mut all_callee_saved = RegisterSet::empty(); + for reg in callee_saved_gprs(flags) { + all_callee_saved.free(GPR, *reg as RegUnit); + } + + let mut used = RegisterSet::empty(); + for value_loc in func.locations.values() { + // Note that `value_loc` here contains only a single unit of a potentially multi-unit + // register. We don't use registers that overlap each other in the x86 ISA, but in others + // we do. So this should not be blindly reused. + if let ValueLoc::Reg(ru) = *value_loc { + if !used.is_avail(GPR, ru) { + used.free(GPR, ru); + } + } + } + + // regmove and regfill instructions may temporarily divert values into other registers, + // and these are not reflected in `func.locations`. Scan the function for such instructions + // and note which callee-saved registers they use. + // + // TODO: Consider re-evaluating how regmove/regfill/regspill work and whether it's possible + // to avoid this step. + for ebb in &func.layout { + for inst in func.layout.ebb_insts(ebb) { + match func.dfg[inst] { + ir::instructions::InstructionData::RegMove { dst, .. } | + ir::instructions::InstructionData::RegFill { dst, .. } => { + if !used.is_avail(GPR, dst) { + used.free(GPR, dst); + } + } + _ => (), + } + } + } + + used.intersect(&all_callee_saved); + return used; +} + pub fn prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> result::CtonResult { match func.signature.call_conv { ir::CallConv::SystemV => system_v_prologue_epilogue(func, isa), @@ -203,7 +243,8 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r } else { ir::types::I32 }; - let csrs = callee_saved_registers(isa.flags()); + + let csrs = callee_saved_gprs_used(isa.flags(), func); // The reserved stack area is composed of: // return address + frame pointer + all callee-saved registers @@ -212,7 +253,7 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r // instruction. Each of the others we will then push explicitly. Then we // will adjust the stack pointer to make room for the rest of the required // space for this frame. - let csr_stack_size = ((csrs.len() + 2) * word_size as usize) as i32; + let csr_stack_size = ((csrs.iter(GPR).len() + 2) * word_size as usize) as i32; func.create_stack_slot(ir::StackSlotData { kind: ir::StackSlotKind::IncomingArg, size: csr_stack_size as u32, @@ -231,9 +272,8 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r func.signature.params.push(fp_arg); func.signature.returns.push(fp_arg); - for csr in csrs.iter() { - let csr_arg = - ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, *csr as RegUnit); + for csr in csrs.iter(GPR) { + let csr_arg = ir::AbiParam::special_reg(csr_type, ir::ArgumentPurpose::CalleeSaved, csr); func.signature.params.push(csr_arg); func.signature.returns.push(csr_arg); } @@ -241,11 +281,11 @@ pub fn system_v_prologue_epilogue(func: &mut ir::Function, isa: &TargetIsa) -> r // Set up the cursor and insert the prologue let entry_ebb = func.layout.entry_block().expect("missing entry block"); let mut pos = EncCursor::new(func, isa).at_first_insertion_point(entry_ebb); - insert_system_v_prologue(&mut pos, local_stack_size, csr_type, csrs); + insert_system_v_prologue(&mut pos, local_stack_size, csr_type, &csrs); // Reset the cursor and insert the epilogue let mut pos = pos.at_position(CursorPosition::Nowhere); - insert_system_v_epilogues(&mut pos, local_stack_size, csr_type, csrs); + insert_system_v_epilogues(&mut pos, local_stack_size, csr_type, &csrs); Ok(()) } @@ -255,7 +295,7 @@ fn insert_system_v_prologue( pos: &mut EncCursor, stack_size: i64, csr_type: ir::types::Type, - csrs: &'static [RU], + csrs: &RegisterSet, ) { // Append param to entry EBB let ebb = pos.current_ebb().expect("missing ebb under cursor"); @@ -268,12 +308,12 @@ fn insert_system_v_prologue( RU::rbp as RegUnit, ); - for reg in csrs.iter() { + for reg in csrs.iter(GPR) { // Append param to entry EBB let csr_arg = pos.func.dfg.append_ebb_param(ebb, csr_type); // Assign it a location - pos.func.locations[csr_arg] = ir::ValueLoc::Reg(*reg as RegUnit); + pos.func.locations[csr_arg] = ir::ValueLoc::Reg(reg); // Remember it so we can push it momentarily pos.ins().x86_push(csr_arg); @@ -289,7 +329,7 @@ fn insert_system_v_epilogues( pos: &mut EncCursor, stack_size: i64, csr_type: ir::types::Type, - csrs: &'static [RU], + csrs: &RegisterSet, ) { while let Some(ebb) = pos.next_ebb() { pos.goto_last_inst(ebb); @@ -307,7 +347,7 @@ fn insert_system_v_epilogue( stack_size: i64, pos: &mut EncCursor, csr_type: ir::types::Type, - csrs: &'static [RU], + csrs: &RegisterSet, ) { if stack_size > 0 { pos.ins().adjust_sp_imm(Imm64::new(stack_size)); @@ -321,11 +361,11 @@ fn insert_system_v_epilogue( pos.func.locations[fp_ret] = ir::ValueLoc::Reg(RU::rbp as RegUnit); pos.func.dfg.append_inst_arg(inst, fp_ret); - for reg in csrs.iter() { + for reg in csrs.iter(GPR) { let csr_ret = pos.ins().x86_pop(csr_type); pos.prev_inst(); - pos.func.locations[csr_ret] = ir::ValueLoc::Reg(*reg as RegUnit); + pos.func.locations[csr_ret] = ir::ValueLoc::Reg(reg); pos.func.dfg.append_inst_arg(inst, csr_ret); } } diff --git a/lib/cretonne/src/isa/intel/binemit.rs b/lib/codegen/src/isa/x86/binemit.rs similarity index 99% rename from lib/cretonne/src/isa/intel/binemit.rs rename to lib/codegen/src/isa/x86/binemit.rs index da14f80d29..3a7c14d7be 100644 --- a/lib/cretonne/src/isa/intel/binemit.rs +++ b/lib/codegen/src/isa/x86/binemit.rs @@ -1,4 +1,4 @@ -//! Emitting binary Intel machine code. +//! Emitting binary x86 machine code. use super::registers::RU; use binemit::{bad_encoding, CodeSink, Reloc}; @@ -7,7 +7,7 @@ use ir::{Ebb, Function, Inst, InstructionData, Opcode, TrapCode}; use isa::{RegUnit, StackBase, StackBaseMask, StackRef}; use regalloc::RegDiversions; -include!(concat!(env!("OUT_DIR"), "/binemit-intel.rs")); +include!(concat!(env!("OUT_DIR"), "/binemit-x86.rs")); // Convert a stack base to the corresponding register. fn stk_base(base: StackBase) -> RegUnit { diff --git a/lib/cretonne/src/isa/intel/enc_tables.rs b/lib/codegen/src/isa/x86/enc_tables.rs similarity index 98% rename from lib/cretonne/src/isa/intel/enc_tables.rs rename to lib/codegen/src/isa/x86/enc_tables.rs index d847eb6d53..01c9ede2f0 100644 --- a/lib/cretonne/src/isa/intel/enc_tables.rs +++ b/lib/codegen/src/isa/x86/enc_tables.rs @@ -1,4 +1,4 @@ -//! Encoding tables for Intel ISAs. +//! Encoding tables for x86 ISAs. use super::registers::*; use bitset::BitSet; @@ -12,8 +12,8 @@ use isa::enc_tables::*; use isa::encoding::RecipeSizing; use predicates; -include!(concat!(env!("OUT_DIR"), "/encoding-intel.rs")); -include!(concat!(env!("OUT_DIR"), "/legalize-intel.rs")); +include!(concat!(env!("OUT_DIR"), "/encoding-x86.rs")); +include!(concat!(env!("OUT_DIR"), "/legalize-x86.rs")); /// Expand the `sdiv` and `srem` instructions using `x86_sdivmodx`. fn expand_sdivrem( @@ -147,7 +147,7 @@ fn expand_udivrem( pos.remove_inst(); } -/// Expand the `fmin` and `fmax` instructions using the Intel `x86_fmin` and `x86_fmax` +/// Expand the `fmin` and `fmax` instructions using the x86 `x86_fmin` and `x86_fmax` /// instructions. fn expand_minmax( inst: ir::Inst, @@ -241,7 +241,7 @@ fn expand_minmax( cfg.recompute_ebb(pos.func, done); } -/// Intel has no unsigned-to-float conversions. We handle the easy case of zero-extending i32 to +/// x86 has no unsigned-to-float conversions. We handle the easy case of zero-extending i32 to /// i64 with a pattern, the rest needs more code. fn expand_fcvt_from_uint( inst: ir::Inst, diff --git a/lib/cretonne/src/isa/intel/mod.rs b/lib/codegen/src/isa/x86/mod.rs similarity index 94% rename from lib/cretonne/src/isa/intel/mod.rs rename to lib/codegen/src/isa/x86/mod.rs index 91d8325a6b..6bbde318a5 100644 --- a/lib/cretonne/src/isa/intel/mod.rs +++ b/lib/codegen/src/isa/x86/mod.rs @@ -1,4 +1,4 @@ -//! Intel Instruction Set Architectures. +//! x86 Instruction Set Architectures. mod abi; mod binemit; @@ -25,7 +25,7 @@ struct Isa { cpumode: &'static [shared_enc_tables::Level1Entry], } -/// Get an ISA builder for creating Intel targets. +/// Get an ISA builder for creating x86 targets. pub fn isa_builder() -> IsaBuilder { IsaBuilder { setup: settings::builder(), @@ -51,7 +51,7 @@ fn isa_constructor( impl TargetIsa for Isa { fn name(&self) -> &'static str { - "intel" + "x86" } fn flags(&self) -> &shared_settings::Flags { @@ -72,14 +72,14 @@ impl TargetIsa for Isa { fn legal_encodings<'a>( &'a self, - dfg: &'a ir::DataFlowGraph, + func: &'a ir::Function, inst: &'a ir::InstructionData, ctrl_typevar: ir::Type, ) -> Encodings<'a> { lookup_enclist( ctrl_typevar, inst, - dfg, + func, self.cpumode, &enc_tables::LEVEL2[..], &enc_tables::ENCLISTS[..], @@ -98,7 +98,7 @@ impl TargetIsa for Isa { abi::regclass_for_abi_type(ty) } - fn allocatable_registers(&self, func: &ir::Function) -> regalloc::AllocatableSet { + fn allocatable_registers(&self, func: &ir::Function) -> regalloc::RegisterSet { abi::allocatable_registers(func, &self.shared_flags) } diff --git a/lib/cretonne/src/isa/intel/registers.rs b/lib/codegen/src/isa/x86/registers.rs similarity index 95% rename from lib/cretonne/src/isa/intel/registers.rs rename to lib/codegen/src/isa/x86/registers.rs index c972c10a13..5ca0c4912c 100644 --- a/lib/cretonne/src/isa/intel/registers.rs +++ b/lib/codegen/src/isa/x86/registers.rs @@ -1,8 +1,8 @@ -//! Intel register descriptions. +//! x86 register descriptions. use isa::registers::{RegBank, RegClass, RegClassData, RegInfo, RegUnit}; -include!(concat!(env!("OUT_DIR"), "/registers-intel.rs")); +include!(concat!(env!("OUT_DIR"), "/registers-x86.rs")); #[cfg(test)] mod tests { diff --git a/lib/cretonne/src/isa/intel/settings.rs b/lib/codegen/src/isa/x86/settings.rs similarity index 86% rename from lib/cretonne/src/isa/intel/settings.rs rename to lib/codegen/src/isa/x86/settings.rs index 147af4c2fa..379f0db493 100644 --- a/lib/cretonne/src/isa/intel/settings.rs +++ b/lib/codegen/src/isa/x86/settings.rs @@ -1,12 +1,12 @@ -//! Intel Settings. +//! x86 Settings. use settings::{self, detail, Builder}; use std::fmt; -// Include code generated by `lib/cretonne/meta/gen_settings.py`. This file contains a public +// Include code generated by `lib/codegen/meta/gen_settings.py`. This file contains a public // `Flags` struct with an impl for all of the settings defined in -// `lib/cretonne/meta/isa/intel/settings.py`. -include!(concat!(env!("OUT_DIR"), "/settings-intel.rs")); +// `lib/codegen/meta/isa/x86/settings.py`. +include!(concat!(env!("OUT_DIR"), "/settings-x86.rs")); #[cfg(test)] mod tests { diff --git a/lib/cretonne/src/iterators.rs b/lib/codegen/src/iterators.rs similarity index 100% rename from lib/cretonne/src/iterators.rs rename to lib/codegen/src/iterators.rs diff --git a/lib/cretonne/src/legalizer/boundary.rs b/lib/codegen/src/legalizer/boundary.rs similarity index 100% rename from lib/cretonne/src/legalizer/boundary.rs rename to lib/codegen/src/legalizer/boundary.rs diff --git a/lib/codegen/src/legalizer/call.rs b/lib/codegen/src/legalizer/call.rs new file mode 100644 index 0000000000..ed499f53f3 --- /dev/null +++ b/lib/codegen/src/legalizer/call.rs @@ -0,0 +1,60 @@ +//! Legalization of calls. +//! +//! This module exports the `expand_call` function which transforms a `call` +//! instruction into `func_addr` and `call_indirect` instructions. + +use cursor::{Cursor, FuncCursor}; +use flowgraph::ControlFlowGraph; +use ir::{self, InstBuilder}; +use isa::TargetIsa; + +/// Expand a `call` instruction. +pub fn expand_call( + inst: ir::Inst, + func: &mut ir::Function, + _cfg: &mut ControlFlowGraph, + isa: &TargetIsa, +) { + // Unpack the instruction. + let (func_ref, old_args) = match func.dfg[inst] { + ir::InstructionData::Call { + opcode, + ref args, + func_ref, + } => { + debug_assert_eq!(opcode, ir::Opcode::Call); + (func_ref, args.clone()) + } + _ => panic!("Wanted call: {}", func.dfg.display_inst(inst, None)), + }; + + let ptr_ty = if isa.flags().is_64bit() { + ir::types::I64 + } else { + ir::types::I32 + }; + + let sig = func.dfg.ext_funcs[func_ref].signature; + + let callee = { + let mut pos = FuncCursor::new(func).at_inst(inst); + pos.use_srcloc(inst); + pos.ins().func_addr(ptr_ty, func_ref) + }; + + let mut new_args = ir::ValueList::default(); + new_args.push(callee, &mut func.dfg.value_lists); + for i in 0..old_args.len(&func.dfg.value_lists) { + new_args.push( + old_args.as_slice(&func.dfg.value_lists)[i], + &mut func.dfg.value_lists, + ); + } + + func.dfg.replace(inst).CallIndirect( + ir::Opcode::CallIndirect, + ptr_ty, + sig, + new_args, + ); +} diff --git a/lib/cretonne/src/legalizer/globalvar.rs b/lib/codegen/src/legalizer/globalvar.rs similarity index 96% rename from lib/cretonne/src/legalizer/globalvar.rs rename to lib/codegen/src/legalizer/globalvar.rs index 27494bfd87..9c6e701cf2 100644 --- a/lib/cretonne/src/legalizer/globalvar.rs +++ b/lib/codegen/src/legalizer/globalvar.rs @@ -25,7 +25,7 @@ pub fn expand_global_addr( }; match func.global_vars[gv] { - ir::GlobalVarData::VmCtx { offset } => vmctx_addr(inst, func, offset.into()), + ir::GlobalVarData::VMContext { offset } => vmctx_addr(inst, func, offset.into()), ir::GlobalVarData::Deref { base, offset } => deref_addr(inst, func, base, offset.into()), ir::GlobalVarData::Sym { .. } => globalsym(inst, func, gv), } diff --git a/lib/cretonne/src/legalizer/heap.rs b/lib/codegen/src/legalizer/heap.rs similarity index 100% rename from lib/cretonne/src/legalizer/heap.rs rename to lib/codegen/src/legalizer/heap.rs diff --git a/lib/cretonne/src/legalizer/libcall.rs b/lib/codegen/src/legalizer/libcall.rs similarity index 96% rename from lib/cretonne/src/legalizer/libcall.rs rename to lib/codegen/src/legalizer/libcall.rs index 1a3da4a9a1..8f69cba18d 100644 --- a/lib/cretonne/src/legalizer/libcall.rs +++ b/lib/codegen/src/legalizer/libcall.rs @@ -54,8 +54,10 @@ fn make_funcref(libcall: ir::LibCall, inst: ir::Inst, func: &mut ir::Function) - } let sigref = func.import_signature(sig); + // TODO: Can libcalls be colocated in some circumstances? func.import_function(ir::ExtFuncData { name: ir::ExternalName::LibCall(libcall), signature: sigref, + colocated: false, }) } diff --git a/lib/cretonne/src/legalizer/mod.rs b/lib/codegen/src/legalizer/mod.rs similarity index 99% rename from lib/cretonne/src/legalizer/mod.rs rename to lib/codegen/src/legalizer/mod.rs index 23b3f56c89..f4f9389390 100644 --- a/lib/cretonne/src/legalizer/mod.rs +++ b/lib/codegen/src/legalizer/mod.rs @@ -21,6 +21,7 @@ use isa::TargetIsa; use timing; mod boundary; +mod call; mod globalvar; mod heap; mod libcall; @@ -28,6 +29,7 @@ mod split; use self::globalvar::expand_global_addr; use self::heap::expand_heap_addr; +use self::call::expand_call; use self::libcall::expand_as_libcall; /// Legalize `func` for `isa`. @@ -103,7 +105,7 @@ pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, is } // Include legalization patterns that were generated by `gen_legalizer.py` from the `XForms` in -// `lib/cretonne/meta/base/legalize.py`. +// `lib/codegen/meta/base/legalize.py`. // // Concretely, this defines private functions `narrow()`, and `expand()`. include!(concat!(env!("OUT_DIR"), "/legalizer.rs")); diff --git a/lib/cretonne/src/legalizer/split.rs b/lib/codegen/src/legalizer/split.rs similarity index 100% rename from lib/cretonne/src/legalizer/split.rs rename to lib/codegen/src/legalizer/split.rs diff --git a/lib/cretonne/src/lib.rs b/lib/codegen/src/lib.rs similarity index 95% rename from lib/cretonne/src/lib.rs rename to lib/codegen/src/lib.rs index cbdd0bae1d..87a86559f9 100644 --- a/lib/cretonne/src/lib.rs +++ b/lib/codegen/src/lib.rs @@ -50,13 +50,14 @@ pub use legalizer::legalize_function; pub use verifier::verify_function; pub use write::write_function; -/// Version number of the cretonne crate. +/// Version number of the cretonne-codegen crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); #[macro_use] -pub mod dbg; +pub extern crate cretonne_entity as entity; + #[macro_use] -pub mod entity; +pub mod dbg; pub mod bforest; pub mod binemit; @@ -67,13 +68,14 @@ pub mod flowgraph; pub mod ir; pub mod isa; pub mod loop_analysis; -pub mod packed_option; pub mod print_errors; pub mod result; pub mod settings; pub mod timing; pub mod verifier; +pub use entity::packed_option; + mod abi; mod bitset; mod constant_hash; diff --git a/lib/cretonne/src/licm.rs b/lib/codegen/src/licm.rs similarity index 100% rename from lib/cretonne/src/licm.rs rename to lib/codegen/src/licm.rs diff --git a/lib/cretonne/src/loop_analysis.rs b/lib/codegen/src/loop_analysis.rs similarity index 100% rename from lib/cretonne/src/loop_analysis.rs rename to lib/codegen/src/loop_analysis.rs diff --git a/lib/cretonne/src/partition_slice.rs b/lib/codegen/src/partition_slice.rs similarity index 100% rename from lib/cretonne/src/partition_slice.rs rename to lib/codegen/src/partition_slice.rs diff --git a/lib/cretonne/src/postopt.rs b/lib/codegen/src/postopt.rs similarity index 100% rename from lib/cretonne/src/postopt.rs rename to lib/codegen/src/postopt.rs diff --git a/lib/cretonne/src/predicates.rs b/lib/codegen/src/predicates.rs similarity index 80% rename from lib/cretonne/src/predicates.rs rename to lib/codegen/src/predicates.rs index 618369291d..e35e7ad179 100644 --- a/lib/cretonne/src/predicates.rs +++ b/lib/codegen/src/predicates.rs @@ -1,7 +1,7 @@ //! Predicate functions for testing instruction fields. //! //! This module defines functions that are used by the instruction predicates defined by -//! `lib/cretonne/meta/cdsl/predicates.py` classes. +//! `lib/codegen/meta/cdsl/predicates.py` classes. //! //! The predicates the operate on integer fields use `Into` as a shared trait bound. This //! bound is implemented by all the native integer types as well as `Imm64`. @@ -9,6 +9,8 @@ //! Some of these predicates may be unused in certain ISA configurations, so we suppress the //! dead code warning. +use ir; + /// Check that `x` is the same as `y`. #[allow(dead_code)] pub fn is_equal + Copy>(x: T, y: O) -> bool { @@ -31,6 +33,19 @@ pub fn is_unsigned_int>(x: T, wd: u8, sc: u8) -> bool { u == (u & m) } +#[allow(dead_code)] +pub fn is_colocated_func(func_ref: ir::FuncRef, func: &ir::Function) -> bool { + func.dfg.ext_funcs[func_ref].colocated +} + +#[allow(dead_code)] +pub fn is_colocated_data(global_var: ir::GlobalVar, func: &ir::Function) -> bool { + match func.global_vars[global_var] { + ir::GlobalVarData::Sym { colocated, .. } => colocated, + _ => panic!("is_colocated_data only makes sense for data with symbolic addresses"), + } +} + #[cfg(test)] mod tests { use super::*; diff --git a/lib/cretonne/src/preopt.rs b/lib/codegen/src/preopt.rs similarity index 99% rename from lib/cretonne/src/preopt.rs rename to lib/codegen/src/preopt.rs index bdd1c445eb..cbe7484fd0 100644 --- a/lib/cretonne/src/preopt.rs +++ b/lib/codegen/src/preopt.rs @@ -493,7 +493,7 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { } else if let ValueDef::Result(iconst_inst, _) = pos.func.dfg.value_def(args[0]) { if let InstructionData::UnaryImm { opcode: Opcode::Iconst, - mut imm, + imm, } = pos.func.dfg[iconst_inst] { let new_opcode = match opcode { @@ -505,7 +505,7 @@ fn simplify(pos: &mut FuncCursor, inst: Inst) { new_opcode, ty, imm, - args[0], + args[1], ); } } diff --git a/lib/cretonne/src/print_errors.rs b/lib/codegen/src/print_errors.rs similarity index 100% rename from lib/cretonne/src/print_errors.rs rename to lib/codegen/src/print_errors.rs diff --git a/lib/cretonne/src/ref_slice.rs b/lib/codegen/src/ref_slice.rs similarity index 100% rename from lib/cretonne/src/ref_slice.rs rename to lib/codegen/src/ref_slice.rs diff --git a/lib/cretonne/src/regalloc/affinity.rs b/lib/codegen/src/regalloc/affinity.rs similarity index 100% rename from lib/cretonne/src/regalloc/affinity.rs rename to lib/codegen/src/regalloc/affinity.rs diff --git a/lib/cretonne/src/regalloc/coalescing.rs b/lib/codegen/src/regalloc/coalescing.rs similarity index 100% rename from lib/cretonne/src/regalloc/coalescing.rs rename to lib/codegen/src/regalloc/coalescing.rs diff --git a/lib/cretonne/src/regalloc/coloring.rs b/lib/codegen/src/regalloc/coloring.rs similarity index 99% rename from lib/cretonne/src/regalloc/coloring.rs rename to lib/codegen/src/regalloc/coloring.rs index b9b1512220..4ddda53e16 100644 --- a/lib/cretonne/src/regalloc/coloring.rs +++ b/lib/codegen/src/regalloc/coloring.rs @@ -51,7 +51,7 @@ use isa::{regs_overlap, RegClass, RegInfo, RegUnit}; use packed_option::PackedOption; use regalloc::RegDiversions; use regalloc::affinity::Affinity; -use regalloc::allocatable_set::AllocatableSet; +use regalloc::register_set::RegisterSet; use regalloc::live_value_tracker::{LiveValue, LiveValueTracker}; use regalloc::liveness::Liveness; use regalloc::liverange::{LiveRange, LiveRangeContext}; @@ -96,7 +96,7 @@ struct Context<'a> { // Pristine set of registers that the allocator can use. // This set remains immutable, we make clones. - usable_regs: AllocatableSet, + usable_regs: RegisterSet, } impl Coloring { @@ -699,7 +699,7 @@ impl<'a> Context<'a> { defs: &[LiveValue], throughs: &[LiveValue], replace_global_defines: &mut bool, - global_regs: &AllocatableSet, + global_regs: &RegisterSet, ) { for (op, lv) in constraints.iter().zip(defs) { match op.kind { @@ -732,7 +732,7 @@ impl<'a> Context<'a> { defs: &[LiveValue], throughs: &[LiveValue], replace_global_defines: &mut bool, - global_regs: &AllocatableSet, + global_regs: &RegisterSet, ) { // It's technically possible for a call instruction to have fixed results before the // variable list of results, but we have no known instances of that. @@ -797,7 +797,7 @@ impl<'a> Context<'a> { constraints: &[OperandConstraint], defs: &[LiveValue], replace_global_defines: &mut bool, - global_regs: &AllocatableSet, + global_regs: &RegisterSet, ) { for (op, lv) in constraints.iter().zip(defs) { match op.kind { @@ -843,9 +843,9 @@ impl<'a> Context<'a> { fn iterate_solution( &mut self, throughs: &[LiveValue], - global_regs: &AllocatableSet, + global_regs: &RegisterSet, replace_global_defines: &mut bool, - ) -> AllocatableSet { + ) -> RegisterSet { // Make sure `try_add_var()` below doesn't create a variable with too loose constraints. self.program_complete_input_constraints(); @@ -923,7 +923,7 @@ impl<'a> Context<'a> { /// inserted before. /// /// The solver needs to be reminded of the available registers before any moves are inserted. - fn shuffle_inputs(&mut self, regs: &mut AllocatableSet) { + fn shuffle_inputs(&mut self, regs: &mut RegisterSet) { use regalloc::solver::Move::*; let spills = self.solver.schedule_moves(regs); @@ -1114,19 +1114,19 @@ fn program_input_abi( struct AvailableRegs { /// The exact set of registers available on the input side of the current instruction. This /// takes into account register diversions, and it includes both local and global live ranges. - input: AllocatableSet, + input: RegisterSet, /// Registers available for allocating globally live values. This set ignores any local values, /// and it does not account for register diversions. /// /// Global values must be allocated out of this set because conflicts with other global values /// can't be resolved with local diversions. - global: AllocatableSet, + global: RegisterSet, } impl AvailableRegs { /// Initialize both the input and global sets from `regs`. - pub fn new(regs: &AllocatableSet) -> AvailableRegs { + pub fn new(regs: &RegisterSet) -> AvailableRegs { AvailableRegs { input: regs.clone(), global: regs.clone(), diff --git a/lib/cretonne/src/regalloc/context.rs b/lib/codegen/src/regalloc/context.rs similarity index 100% rename from lib/cretonne/src/regalloc/context.rs rename to lib/codegen/src/regalloc/context.rs diff --git a/lib/cretonne/src/regalloc/diversion.rs b/lib/codegen/src/regalloc/diversion.rs similarity index 100% rename from lib/cretonne/src/regalloc/diversion.rs rename to lib/codegen/src/regalloc/diversion.rs diff --git a/lib/cretonne/src/regalloc/live_value_tracker.rs b/lib/codegen/src/regalloc/live_value_tracker.rs similarity index 100% rename from lib/cretonne/src/regalloc/live_value_tracker.rs rename to lib/codegen/src/regalloc/live_value_tracker.rs diff --git a/lib/cretonne/src/regalloc/liveness.rs b/lib/codegen/src/regalloc/liveness.rs similarity index 100% rename from lib/cretonne/src/regalloc/liveness.rs rename to lib/codegen/src/regalloc/liveness.rs diff --git a/lib/cretonne/src/regalloc/liverange.rs b/lib/codegen/src/regalloc/liverange.rs similarity index 100% rename from lib/cretonne/src/regalloc/liverange.rs rename to lib/codegen/src/regalloc/liverange.rs diff --git a/lib/cretonne/src/regalloc/mod.rs b/lib/codegen/src/regalloc/mod.rs similarity index 84% rename from lib/cretonne/src/regalloc/mod.rs rename to lib/codegen/src/regalloc/mod.rs index 6868c0a235..1444874b83 100644 --- a/lib/cretonne/src/regalloc/mod.rs +++ b/lib/codegen/src/regalloc/mod.rs @@ -2,7 +2,7 @@ //! //! This module contains data structures and algorithms used for register allocation. -pub mod allocatable_set; +pub mod register_set; pub mod coloring; pub mod live_value_tracker; pub mod liveness; @@ -18,6 +18,6 @@ mod reload; mod solver; mod spilling; -pub use self::allocatable_set::AllocatableSet; +pub use self::register_set::RegisterSet; pub use self::context::Context; pub use self::diversion::RegDiversions; diff --git a/lib/cretonne/src/regalloc/pressure.rs b/lib/codegen/src/regalloc/pressure.rs similarity index 98% rename from lib/cretonne/src/regalloc/pressure.rs rename to lib/codegen/src/regalloc/pressure.rs index 14978f48b8..9f7d64365d 100644 --- a/lib/cretonne/src/regalloc/pressure.rs +++ b/lib/codegen/src/regalloc/pressure.rs @@ -37,7 +37,7 @@ #![allow(dead_code)] use isa::registers::{RegClass, RegClassMask, RegInfo, MAX_TRACKED_TOPRCS}; -use regalloc::AllocatableSet; +use regalloc::RegisterSet; use std::cmp::min; use std::fmt; use std::iter::ExactSizeIterator; @@ -81,7 +81,7 @@ pub struct Pressure { impl Pressure { /// Create a new register pressure tracker. - pub fn new(reginfo: &RegInfo, usable: &AllocatableSet) -> Pressure { + pub fn new(reginfo: &RegInfo, usable: &RegisterSet) -> Pressure { let mut p = Pressure { aliased: 0, toprc: Default::default(), @@ -271,7 +271,7 @@ impl fmt::Display for Pressure { mod tests { use super::Pressure; use isa::{RegClass, TargetIsa}; - use regalloc::AllocatableSet; + use regalloc::RegisterSet; use std::borrow::Borrow; use std::boxed::Box; @@ -302,7 +302,7 @@ mod tests { let gpr = rc_by_name(isa, "GPR"); let s = rc_by_name(isa, "S"); let reginfo = isa.register_info(); - let regs = AllocatableSet::new(); + let regs = RegisterSet::new(); let mut pressure = Pressure::new(®info, ®s); let mut count = 0; @@ -331,7 +331,7 @@ mod tests { let d = rc_by_name(isa, "D"); let q = rc_by_name(isa, "Q"); let reginfo = isa.register_info(); - let regs = AllocatableSet::new(); + let regs = RegisterSet::new(); let mut pressure = Pressure::new(®info, ®s); assert_eq!(pressure.check_avail(s), 0); diff --git a/lib/cretonne/src/regalloc/allocatable_set.rs b/lib/codegen/src/regalloc/register_set.rs similarity index 89% rename from lib/cretonne/src/regalloc/allocatable_set.rs rename to lib/codegen/src/regalloc/register_set.rs index 63b7a297d7..65414dbd9b 100644 --- a/lib/cretonne/src/regalloc/allocatable_set.rs +++ b/lib/codegen/src/regalloc/register_set.rs @@ -13,7 +13,7 @@ use std::mem::size_of_val; /// Set of registers available for allocation. #[derive(Clone)] -pub struct AllocatableSet { +pub struct RegisterSet { avail: RegUnitMask, } @@ -32,7 +32,7 @@ fn bitmask(rc: RegClass, reg: RegUnit) -> (usize, u32) { (word_index, reg_bits) } -impl AllocatableSet { +impl RegisterSet { /// Create a new register set with all registers available. /// /// Note that this includes *all* registers. Query the `TargetIsa` object to get a set of @@ -41,6 +41,11 @@ impl AllocatableSet { Self { avail: [!0; 3] } } + /// Create a new register set with no registers available. + pub fn empty() -> Self { + Self { avail: [0; 3] } + } + /// Returns `true` if the specified register is available. pub fn is_avail(&self, rc: RegClass, reg: RegUnit) -> bool { let (idx, bits) = bitmask(rc, reg); @@ -62,7 +67,7 @@ impl AllocatableSet { self.avail[idx] &= !bits; } - /// Make `reg` available for allocation again. + /// Return `reg` and all of its register units to the set of available registers. pub fn free(&mut self, rc: RegClass, reg: RegUnit) { let (idx, bits) = bitmask(rc, reg); debug_assert!( @@ -98,15 +103,15 @@ impl AllocatableSet { /// of `other`. /// /// This assumes that unused bits are 1. - pub fn interferes_with(&self, other: &AllocatableSet) -> bool { + pub fn interferes_with(&self, other: &RegisterSet) -> bool { self.avail.iter().zip(&other.avail).any( |(&x, &y)| (x | y) != !0, ) } - /// Intersect this set of allocatable registers with `other`. This has the effect of removing - /// any register units from this set that are not in `other`. - pub fn intersect(&mut self, other: &AllocatableSet) { + /// Intersect this set of registers with `other`. This has the effect of removing any register + /// units from this set that are not in `other`. + pub fn intersect(&mut self, other: &RegisterSet) { for (x, &y) in self.avail.iter_mut().zip(&other.avail) { *x &= y; } @@ -114,8 +119,8 @@ impl AllocatableSet { /// Return an object that can display this register set, using the register info from the /// target ISA. - pub fn display<'a, R: Into>>(&self, regs: R) -> DisplayAllocatableSet<'a> { - DisplayAllocatableSet(self.clone(), regs.into()) + pub fn display<'a, R: Into>>(&self, regs: R) -> DisplayRegisterSet<'a> { + DisplayRegisterSet(self.clone(), regs.into()) } } @@ -157,10 +162,10 @@ impl Iterator for RegSetIter { impl ExactSizeIterator for RegSetIter {} -/// Displaying an `AllocatableSet` correctly requires the associated `RegInfo` from the target ISA. -pub struct DisplayAllocatableSet<'a>(AllocatableSet, Option<&'a RegInfo>); +/// Displaying an `RegisterSet` correctly requires the associated `RegInfo` from the target ISA. +pub struct DisplayRegisterSet<'a>(RegisterSet, Option<&'a RegInfo>); -impl<'a> fmt::Display for DisplayAllocatableSet<'a> { +impl<'a> fmt::Display for DisplayRegisterSet<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "[")?; match self.1 { @@ -191,7 +196,7 @@ impl<'a> fmt::Display for DisplayAllocatableSet<'a> { } // Display individual registers as either the second letter of their // name or the last digit of their number. - // This works for Intel (rax, rbx, ...) and for numbered regs. + // This works for x86 (rax, rbx, ...) and for numbered regs. write!( f, "{}", @@ -211,7 +216,7 @@ impl<'a> fmt::Display for DisplayAllocatableSet<'a> { } } -impl fmt::Display for AllocatableSet { +impl fmt::Display for RegisterSet { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { self.display(None).fmt(f) } @@ -255,7 +260,7 @@ mod tests { #[test] fn put_and_take() { - let mut regs = AllocatableSet::new(); + let mut regs = RegisterSet::new(); // `GPR` has units 28-36. assert_eq!(regs.iter(GPR).len(), 8); @@ -302,8 +307,8 @@ mod tests { #[test] fn interference() { - let mut regs1 = AllocatableSet::new(); - let mut regs2 = AllocatableSet::new(); + let mut regs1 = RegisterSet::new(); + let mut regs2 = RegisterSet::new(); assert!(!regs1.interferes_with(®s2)); regs1.take(&GPR, 32); diff --git a/lib/cretonne/src/regalloc/reload.rs b/lib/codegen/src/regalloc/reload.rs similarity index 100% rename from lib/cretonne/src/regalloc/reload.rs rename to lib/codegen/src/regalloc/reload.rs diff --git a/lib/cretonne/src/regalloc/solver.rs b/lib/codegen/src/regalloc/solver.rs similarity index 97% rename from lib/cretonne/src/regalloc/solver.rs rename to lib/codegen/src/regalloc/solver.rs index 4bac41aa99..218f0a2600 100644 --- a/lib/cretonne/src/regalloc/solver.rs +++ b/lib/codegen/src/regalloc/solver.rs @@ -98,12 +98,12 @@ //! appropriate candidate among the set of live register values, add it as a variable and start //! over. -use super::AllocatableSet; +use super::RegisterSet; use dbg::DisplayList; use entity::{SparseMap, SparseMapValue}; use ir::Value; use isa::{RegClass, RegUnit}; -use regalloc::allocatable_set::RegSetIter; +use regalloc::register_set::RegSetIter; use std::cmp; use std::fmt; use std::mem; @@ -184,12 +184,7 @@ impl Variable { /// Get an iterator over possible register choices, given the available registers on the input /// and output sides as well as the available global register set. - fn iter( - &self, - iregs: &AllocatableSet, - oregs: &AllocatableSet, - gregs: &AllocatableSet, - ) -> RegSetIter { + fn iter(&self, iregs: &RegisterSet, oregs: &RegisterSet, gregs: &RegisterSet) -> RegSetIter { if !self.is_output { debug_assert!(!self.is_global, "Global implies output"); debug_assert!(self.is_input, "Missing interference set"); @@ -476,7 +471,7 @@ pub struct Solver { /// - The 'to' registers of fixed input reassignments are marked as unavailable. /// - Input-side variables are marked as available. /// - regs_in: AllocatableSet, + regs_in: RegisterSet, /// Available registers on the output side of the instruction / fixed input scratch space. /// @@ -490,7 +485,7 @@ pub struct Solver { /// - Fixed output assignments are marked as unavailable. /// - Live-through variables are marked as available. /// - regs_out: AllocatableSet, + regs_out: RegisterSet, /// List of register moves scheduled to avoid conflicts. /// @@ -509,8 +504,8 @@ impl Solver { assignments: SparseMap::new(), vars: Vec::new(), inputs_done: false, - regs_in: AllocatableSet::new(), - regs_out: AllocatableSet::new(), + regs_in: RegisterSet::new(), + regs_out: RegisterSet::new(), moves: Vec::new(), fills: Vec::new(), } @@ -521,8 +516,8 @@ impl Solver { self.assignments.clear(); self.vars.clear(); self.inputs_done = false; - self.regs_in = AllocatableSet::new(); - self.regs_out = AllocatableSet::new(); + self.regs_in = RegisterSet::new(); + self.regs_out = RegisterSet::new(); self.moves.clear(); self.fills.clear(); } @@ -531,13 +526,13 @@ impl Solver { /// allocatable registers. /// /// The `regs` set is the allocatable registers before any reassignments are applied. - pub fn reset(&mut self, regs: &AllocatableSet) { + pub fn reset(&mut self, regs: &RegisterSet) { self.assignments.clear(); self.vars.clear(); self.inputs_done = false; self.regs_in = regs.clone(); // Used for tracking fixed input assignments while `!inputs_done`: - self.regs_out = AllocatableSet::new(); + self.regs_out = RegisterSet::new(); self.moves.clear(); self.fills.clear(); } @@ -870,10 +865,7 @@ impl Solver { /// always trivial. /// /// Returns `Ok(regs)` if a solution was found. - pub fn quick_solve( - &mut self, - global_regs: &AllocatableSet, - ) -> Result { + pub fn quick_solve(&mut self, global_regs: &RegisterSet) -> Result { self.find_solution(global_regs) } @@ -884,10 +876,7 @@ impl Solver { /// This may return an error with a register class that has run out of registers. If registers /// can be freed up in the starving class, this method can be called again after adding /// variables for the freed registers. - pub fn real_solve( - &mut self, - global_regs: &AllocatableSet, - ) -> Result { + pub fn real_solve(&mut self, global_regs: &RegisterSet) -> Result { // Compute domain sizes for all the variables given the current register sets. for v in &mut self.vars { let d = v.iter(&self.regs_in, &self.regs_out, global_regs).len(); @@ -933,10 +922,7 @@ impl Solver { /// If a solution was found, returns `Ok(regs)` with the set of available registers on the /// output side after the solution. If no solution could be found, returns `Err(rc)` with the /// constraint register class that needs more available registers. - fn find_solution( - &mut self, - global_regs: &AllocatableSet, - ) -> Result { + fn find_solution(&mut self, global_regs: &RegisterSet) -> Result { // Available registers on the input and output sides respectively. let mut iregs = self.regs_in.clone(); let mut oregs = self.regs_out.clone(); @@ -1025,7 +1011,7 @@ impl Solver { /// a register. /// /// Returns the number of spills that had to be emitted. - pub fn schedule_moves(&mut self, regs: &AllocatableSet) -> usize { + pub fn schedule_moves(&mut self, regs: &RegisterSet) -> usize { self.collect_moves(); debug_assert!(self.fills.is_empty()); @@ -1162,7 +1148,7 @@ mod tests { use entity::EntityRef; use ir::Value; use isa::{RegClass, RegInfo, RegUnit, TargetIsa}; - use regalloc::AllocatableSet; + use regalloc::RegisterSet; use std::boxed::Box; // Make an arm32 `TargetIsa`, if possible. @@ -1219,8 +1205,8 @@ mod tests { let r0 = gpr.unit(0); let r1 = gpr.unit(1); let r2 = gpr.unit(2); - let gregs = AllocatableSet::new(); - let mut regs = AllocatableSet::new(); + let gregs = RegisterSet::new(); + let mut regs = RegisterSet::new(); let mut solver = Solver::new(); let v10 = Value::new(10); let v11 = Value::new(11); @@ -1277,8 +1263,8 @@ mod tests { let s1 = s.unit(1); let s2 = s.unit(2); let s3 = s.unit(3); - let gregs = AllocatableSet::new(); - let mut regs = AllocatableSet::new(); + let gregs = RegisterSet::new(); + let mut regs = RegisterSet::new(); let mut solver = Solver::new(); let v10 = Value::new(10); let v11 = Value::new(11); @@ -1337,8 +1323,8 @@ mod tests { let r3 = gpr.unit(3); let r4 = gpr.unit(4); let r5 = gpr.unit(5); - let gregs = AllocatableSet::new(); - let mut regs = AllocatableSet::new(); + let gregs = RegisterSet::new(); + let mut regs = RegisterSet::new(); let mut solver = Solver::new(); let v10 = Value::new(10); let v11 = Value::new(11); diff --git a/lib/cretonne/src/regalloc/spilling.rs b/lib/codegen/src/regalloc/spilling.rs similarity index 100% rename from lib/cretonne/src/regalloc/spilling.rs rename to lib/codegen/src/regalloc/spilling.rs diff --git a/lib/cretonne/src/regalloc/virtregs.rs b/lib/codegen/src/regalloc/virtregs.rs similarity index 100% rename from lib/cretonne/src/regalloc/virtregs.rs rename to lib/codegen/src/regalloc/virtregs.rs diff --git a/lib/cretonne/src/result.rs b/lib/codegen/src/result.rs similarity index 100% rename from lib/cretonne/src/result.rs rename to lib/codegen/src/result.rs diff --git a/lib/cretonne/src/scoped_hash_map.rs b/lib/codegen/src/scoped_hash_map.rs similarity index 100% rename from lib/cretonne/src/scoped_hash_map.rs rename to lib/codegen/src/scoped_hash_map.rs diff --git a/lib/cretonne/src/settings.rs b/lib/codegen/src/settings.rs similarity index 98% rename from lib/cretonne/src/settings.rs rename to lib/codegen/src/settings.rs index aee441f3ca..6db7ef402e 100644 --- a/lib/cretonne/src/settings.rs +++ b/lib/codegen/src/settings.rs @@ -11,7 +11,7 @@ //! //! # Example //! ``` -//! use cretonne::settings::{self, Configurable}; +//! use cretonne_codegen::settings::{self, Configurable}; //! //! let mut b = settings::builder(); //! b.set("opt_level", "fastest"); @@ -312,7 +312,7 @@ pub mod detail { } // Include code generated by `meta/gen_settings.py`. This file contains a public `Flags` struct -// with an impl for all of the settings defined in `lib/cretonne/meta/base/settings.py`. +// with an impl for all of the settings defined in `lib/codegen/meta/base/settings.py`. include!(concat!(env!("OUT_DIR"), "/settings.rs")); /// Wrapper containing flags and optionally a `TargetIsa` trait object. diff --git a/lib/cretonne/src/simple_gvn.rs b/lib/codegen/src/simple_gvn.rs similarity index 100% rename from lib/cretonne/src/simple_gvn.rs rename to lib/codegen/src/simple_gvn.rs diff --git a/lib/cretonne/src/stack_layout.rs b/lib/codegen/src/stack_layout.rs similarity index 100% rename from lib/cretonne/src/stack_layout.rs rename to lib/codegen/src/stack_layout.rs diff --git a/lib/cretonne/src/timing.rs b/lib/codegen/src/timing.rs similarity index 100% rename from lib/cretonne/src/timing.rs rename to lib/codegen/src/timing.rs diff --git a/lib/cretonne/src/topo_order.rs b/lib/codegen/src/topo_order.rs similarity index 100% rename from lib/cretonne/src/topo_order.rs rename to lib/codegen/src/topo_order.rs diff --git a/lib/cretonne/src/unreachable_code.rs b/lib/codegen/src/unreachable_code.rs similarity index 100% rename from lib/cretonne/src/unreachable_code.rs rename to lib/codegen/src/unreachable_code.rs diff --git a/lib/cretonne/src/verifier/cssa.rs b/lib/codegen/src/verifier/cssa.rs similarity index 100% rename from lib/cretonne/src/verifier/cssa.rs rename to lib/codegen/src/verifier/cssa.rs diff --git a/lib/cretonne/src/verifier/flags.rs b/lib/codegen/src/verifier/flags.rs similarity index 100% rename from lib/cretonne/src/verifier/flags.rs rename to lib/codegen/src/verifier/flags.rs diff --git a/lib/cretonne/src/verifier/liveness.rs b/lib/codegen/src/verifier/liveness.rs similarity index 100% rename from lib/cretonne/src/verifier/liveness.rs rename to lib/codegen/src/verifier/liveness.rs diff --git a/lib/cretonne/src/verifier/locations.rs b/lib/codegen/src/verifier/locations.rs similarity index 100% rename from lib/cretonne/src/verifier/locations.rs rename to lib/codegen/src/verifier/locations.rs diff --git a/lib/cretonne/src/verifier/mod.rs b/lib/codegen/src/verifier/mod.rs similarity index 99% rename from lib/cretonne/src/verifier/mod.rs rename to lib/codegen/src/verifier/mod.rs index 1dcd2b4377..a5d3a8f2cc 100644 --- a/lib/cretonne/src/verifier/mod.rs +++ b/lib/codegen/src/verifier/mod.rs @@ -312,7 +312,7 @@ impl<'a> Verifier<'a> { self.verify_func_ref(inst, func_ref)?; self.verify_value_list(inst, args)?; } - IndirectCall { sig_ref, ref args, .. } => { + CallIndirect { sig_ref, ref args, .. } => { self.verify_sig_ref(inst, sig_ref)?; self.verify_value_list(inst, args)?; } @@ -1018,7 +1018,7 @@ impl<'a> Verifier<'a> { let encoding = self.func.encodings[inst]; if encoding.is_legal() { let mut encodings = isa.legal_encodings( - &self.func.dfg, + &self.func, &self.func.dfg[inst], self.func.dfg.ctrl_typevar(inst), ).peekable(); @@ -1038,7 +1038,7 @@ impl<'a> Verifier<'a> { let mut multiple_encodings = false; for enc in isa.legal_encodings( - &self.func.dfg, + &self.func, &self.func.dfg[inst], self.func.dfg.ctrl_typevar(inst), ) @@ -1092,7 +1092,7 @@ impl<'a> Verifier<'a> { if let Some(text) = needs_enc { // This instruction needs an encoding, so generate an error. // Provide the ISA default encoding as a hint. - match self.func.dfg.encode(inst, isa) { + match self.func.encode(inst, isa) { Ok(enc) => { return err!( inst, diff --git a/lib/cretonne/src/write.rs b/lib/codegen/src/write.rs similarity index 99% rename from lib/cretonne/src/write.rs rename to lib/codegen/src/write.rs index 2ed8da87e9..073ae22f11 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/codegen/src/write.rs @@ -16,6 +16,7 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) - let regs = isa.map(TargetIsa::register_info); let regs = regs.as_ref(); + write!(w, "function ")?; write_spec(w, func, regs)?; writeln!(w, " {{")?; let mut any = write_preamble(w, func, regs)?; @@ -34,7 +35,7 @@ pub fn write_function(w: &mut Write, func: &Function, isa: Option<&TargetIsa>) - // Function spec. fn write_spec(w: &mut Write, func: &Function, regs: Option<&RegInfo>) -> Result { - write!(w, "function {}{}", func.name, func.signature.display(regs)) + write!(w, "{}{}", func.name, func.signature.display(regs)) } fn write_preamble( @@ -348,7 +349,7 @@ pub fn write_operands( Call { func_ref, ref args, .. } => { write!(w, " {}({})", func_ref, DisplayValues(args.as_slice(pool))) } - IndirectCall { sig_ref, ref args, .. } => { + CallIndirect { sig_ref, ref args, .. } => { let args = args.as_slice(pool); write!( w, diff --git a/lib/cretonne/meta/isa/intel/__init__.py b/lib/cretonne/meta/isa/intel/__init__.py deleted file mode 100644 index 0828d790aa..0000000000 --- a/lib/cretonne/meta/isa/intel/__init__.py +++ /dev/null @@ -1,23 +0,0 @@ -""" -Intel Target Architecture -------------------------- - -This target ISA generates code for Intel CPUs with two separate CPU modes: - -`I32` - IA-32 architecture, also known as 'x86'. Generates code for the Intel 386 - and later processors in 32-bit mode. -`I64` - Intel 64 architecture, also known as 'x86-64, 'x64', and 'amd64'. Intel and - AMD CPUs running in 64-bit mode. - -Floating point is supported only on CPUs with support for SSE2 or later. There -is no x87 floating point support. -""" - -from __future__ import absolute_import -from . import defs -from . import encodings, settings, registers # noqa - -# Re-export the primary target ISA definition. -ISA = defs.ISA.finish() diff --git a/lib/entity/Cargo.toml b/lib/entity/Cargo.toml new file mode 100644 index 0000000000..c7c6b0dde0 --- /dev/null +++ b/lib/entity/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Cretonne Project Developers"] +name = "cretonne-entity" +version = "0.5.0" +description = "Data structures using entity references as mapping keys" +license = "Apache-2.0" +documentation = "https://cretonne.readthedocs.io/" +repository = "https://github.com/cretonne/cretonne" +readme = "README.md" +keywords = ["entity", "set", "map"] + +[features] +default = ["std"] +std = [] + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/entity/README.md b/lib/entity/README.md new file mode 100644 index 0000000000..abe3b6210c --- /dev/null +++ b/lib/entity/README.md @@ -0,0 +1,2 @@ +This crate contains array-based data structures used by the core Cretonne code +generator which use densely numbered entity references as mapping keys. diff --git a/lib/cretonne/src/entity/iter.rs b/lib/entity/src/iter.rs similarity index 99% rename from lib/cretonne/src/entity/iter.rs rename to lib/entity/src/iter.rs index 156021ee86..9eeba6c7a6 100644 --- a/lib/cretonne/src/entity/iter.rs +++ b/lib/entity/src/iter.rs @@ -1,6 +1,6 @@ //! A double-ended iterator over entity references and entities. -use entity::EntityRef; +use EntityRef; use std::marker::PhantomData; use std::slice; diff --git a/lib/cretonne/src/entity/keys.rs b/lib/entity/src/keys.rs similarity index 98% rename from lib/cretonne/src/entity/keys.rs rename to lib/entity/src/keys.rs index 3ad5b660b6..52481097cb 100644 --- a/lib/cretonne/src/entity/keys.rs +++ b/lib/entity/src/keys.rs @@ -1,6 +1,6 @@ //! A double-ended iterator over entity references. -use entity::EntityRef; +use EntityRef; use std::marker::PhantomData; /// Iterate over all keys in order. diff --git a/lib/cretonne/src/entity/mod.rs b/lib/entity/src/lib.rs similarity index 71% rename from lib/cretonne/src/entity/mod.rs rename to lib/entity/src/lib.rs index 88c0977cf2..00b6412c0d 100644 --- a/lib/cretonne/src/entity/mod.rs +++ b/lib/entity/src/lib.rs @@ -1,6 +1,6 @@ //! Array-based data structures using densely numbered entity references as mapping keys. //! -//! This module defines a number of data structures based on arrays. The arrays are not indexed by +//! This crate defines a number of data structures based on arrays. The arrays are not indexed by //! `usize` as usual, but by *entity references* which are integers wrapped in new-types. This has //! a couple advantages: //! @@ -29,21 +29,26 @@ //! references allocated from an associated memory pool. It has a much smaller footprint than //! `Vec`. -mod iter; -mod keys; -mod list; -mod map; -mod primary; -mod set; -mod sparse; +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] +#![cfg_attr(feature = "cargo-clippy", + allow(new_without_default, new_without_default_derive, redundant_field_names))] -pub use self::iter::{Iter, IterMut}; -pub use self::keys::Keys; -pub use self::list::{EntityList, ListPool}; -pub use self::map::EntityMap; -pub use self::primary::PrimaryMap; -pub use self::set::EntitySet; -pub use self::sparse::{SparseMap, SparseMapValue, SparseSet}; +// Turns on no_std and alloc features if std is not available. +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(not(feature = "std"), feature(alloc))] + +/// This replaces `std` in builds with `core`. +#[cfg(not(feature = "std"))] +mod std { + extern crate alloc; + pub use self::alloc::{boxed, string, vec}; + pub use core::*; +} + +// Re-export core so that the macros works with both std and no_std crates +#[doc(hidden)] +pub extern crate core as __core; /// A type wrapping a small integer index should implement `EntityRef` so it can be used as the key /// of an `EntityMap` or `SparseMap`. @@ -61,9 +66,9 @@ pub trait EntityRef: Copy + Eq { macro_rules! entity_impl { // Basic traits. ($entity:ident) => { - impl $crate::entity::EntityRef for $entity { + impl $crate::EntityRef for $entity { fn new(index: usize) -> Self { - debug_assert!(index < (::std::u32::MAX as usize)); + debug_assert!(index < ($crate::__core::u32::MAX as usize)); $entity(index as u32) } @@ -74,7 +79,7 @@ macro_rules! entity_impl { impl $crate::packed_option::ReservedValue for $entity { fn reserved_value() -> $entity { - $entity(::std::u32::MAX) + $entity($crate::__core::u32::MAX) } } }; @@ -84,16 +89,34 @@ macro_rules! entity_impl { ($entity:ident, $display_prefix:expr) => { entity_impl!($entity); - impl ::std::fmt::Display for $entity { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + impl $crate::__core::fmt::Display for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { write!(f, "{}{}", $display_prefix, self.0) } } - impl ::std::fmt::Debug for $entity { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - (self as &::std::fmt::Display).fmt(f) + impl $crate::__core::fmt::Debug for $entity { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) -> $crate::__core::fmt::Result { + (self as &$crate::__core::fmt::Display).fmt(f) } } }; } + +pub mod packed_option; + +mod iter; +mod keys; +mod list; +mod map; +mod primary; +mod set; +mod sparse; + +pub use self::iter::{Iter, IterMut}; +pub use self::keys::Keys; +pub use self::list::{EntityList, ListPool}; +pub use self::map::EntityMap; +pub use self::primary::PrimaryMap; +pub use self::set::EntitySet; +pub use self::sparse::{SparseMap, SparseMapValue, SparseSet}; diff --git a/lib/cretonne/src/entity/list.rs b/lib/entity/src/list.rs similarity index 99% rename from lib/cretonne/src/entity/list.rs rename to lib/entity/src/list.rs index 545b1e146b..803504bc76 100644 --- a/lib/cretonne/src/entity/list.rs +++ b/lib/entity/src/list.rs @@ -1,5 +1,5 @@ //! Small lists of entity references. -use entity::EntityRef; +use EntityRef; use std::hash::{Hash, Hasher}; use std::marker::PhantomData; use std::mem; @@ -481,8 +481,12 @@ impl EntityList { mod tests { use super::*; use super::{sclass_for_length, sclass_size}; - use entity::EntityRef; - use ir::Inst; + use EntityRef; + + /// An opaque reference to an instruction in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Inst(u32); + entity_impl!(Inst, "inst"); #[test] fn size_classes() { diff --git a/lib/cretonne/src/entity/map.rs b/lib/entity/src/map.rs similarity index 98% rename from lib/cretonne/src/entity/map.rs rename to lib/entity/src/map.rs index ff402b104f..8256ba9c90 100644 --- a/lib/cretonne/src/entity/map.rs +++ b/lib/entity/src/map.rs @@ -1,6 +1,6 @@ //! Densely numbered entity references as mapping keys. -use entity::{EntityRef, Iter, IterMut, Keys}; +use {EntityRef, Iter, IterMut, Keys}; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; use std::slice; diff --git a/lib/cretonne/src/packed_option.rs b/lib/entity/src/packed_option.rs similarity index 100% rename from lib/cretonne/src/packed_option.rs rename to lib/entity/src/packed_option.rs diff --git a/lib/cretonne/src/entity/primary.rs b/lib/entity/src/primary.rs similarity index 99% rename from lib/cretonne/src/entity/primary.rs rename to lib/entity/src/primary.rs index 5d690a7553..805ccc6866 100644 --- a/lib/cretonne/src/entity/primary.rs +++ b/lib/entity/src/primary.rs @@ -1,5 +1,5 @@ //! Densely numbered entity references as mapping keys. -use entity::{EntityRef, Iter, IterMut, Keys}; +use {EntityRef, Iter, IterMut, Keys}; use std::marker::PhantomData; use std::ops::{Index, IndexMut}; use std::slice; diff --git a/lib/cretonne/src/entity/set.rs b/lib/entity/src/set.rs similarity index 99% rename from lib/cretonne/src/entity/set.rs rename to lib/entity/src/set.rs index e4acf47723..392813401c 100644 --- a/lib/cretonne/src/entity/set.rs +++ b/lib/entity/src/set.rs @@ -1,6 +1,6 @@ //! Densely numbered entity references as set keys. -use entity::{EntityRef, Keys}; +use {EntityRef, Keys}; use std::marker::PhantomData; use std::vec::Vec; diff --git a/lib/cretonne/src/entity/sparse.rs b/lib/entity/src/sparse.rs similarity index 98% rename from lib/cretonne/src/entity/sparse.rs rename to lib/entity/src/sparse.rs index 6894c89498..95d0bba41b 100644 --- a/lib/cretonne/src/entity/sparse.rs +++ b/lib/entity/src/sparse.rs @@ -7,7 +7,7 @@ //! > Briggs, Torczon, *An efficient representation for sparse sets*, //! ACM Letters on Programming Languages and Systems, Volume 2, Issue 1-4, March-Dec. 1993. -use entity::{EntityMap, EntityRef}; +use {EntityMap, EntityRef}; use std::mem; use std::slice; use std::u32; @@ -229,8 +229,12 @@ pub type SparseSet = SparseMap; #[cfg(test)] mod tests { use super::*; - use entity::EntityRef; - use ir::Inst; + use EntityRef; + + /// An opaque reference to an instruction in a function. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] + pub struct Inst(u32); + entity_impl!(Inst, "inst"); // Mock key-value object for testing. #[derive(PartialEq, Eq, Debug)] diff --git a/lib/faerie/Cargo.toml b/lib/faerie/Cargo.toml new file mode 100644 index 0000000000..a0e1effeea --- /dev/null +++ b/lib/faerie/Cargo.toml @@ -0,0 +1,20 @@ +[package] +name = "cretonne-faerie" +version = "0.5.0" +authors = ["The Cretonne Project Developers"] +description = "Emit Cretonne output to native object files with Faerie" +repository = "https://github.com/Cretonne/cretonne" +documentation = "https://cretonne.readthedocs.io/" +license = "Apache-2.0" +readme = "README.md" + +[dependencies] +cretonne-codegen = { path = "../codegen", version = "0.5.0" } +cretonne-module = { path = "../module", version = "0.5.0" } +faerie = "0.1.0" +goblin = "0.0.14" +failure = "0.1.1" + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "Cretonne/cretonne" } diff --git a/lib/faerie/README.md b/lib/faerie/README.md new file mode 100644 index 0000000000..7817ccb21e --- /dev/null +++ b/lib/faerie/README.md @@ -0,0 +1,4 @@ +This crate contains a library that enables +[Cretonne](https://crates.io/crates/cretonne) +to emit native object (".o") files, using the +[Faerie](https://crates.io/crates/faerie) library. diff --git a/lib/faerie/src/backend.rs b/lib/faerie/src/backend.rs new file mode 100644 index 0000000000..e33fe5e420 --- /dev/null +++ b/lib/faerie/src/backend.rs @@ -0,0 +1,293 @@ +//! Defines `FaerieBackend`. + +use container; +use cretonne_codegen::binemit::{Addend, CodeOffset, Reloc, RelocSink, NullTrapSink}; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::result::CtonError; +use cretonne_codegen::{self, binemit, ir}; +use cretonne_module::{Backend, DataContext, Linkage, ModuleNamespace, Init, DataDescription}; +use faerie; +use failure::Error; +use std::fs::File; +use target; + +pub struct FaerieCompiledFunction {} + +pub struct FaerieCompiledData {} + +/// A `FaerieBackend` implements `Backend` and emits ".o" files using the `faerie` library. +pub struct FaerieBackend { + isa: Box, + artifact: faerie::Artifact, + format: container::Format, +} + +impl FaerieBackend { + /// Create a new `FaerieBackend` using the given Cretonne target. + pub fn new( + isa: Box, + name: String, + format: container::Format, + ) -> Result { + debug_assert!(isa.flags().is_pic(), "faerie requires PIC"); + let faerie_target = target::translate(&*isa)?; + Ok(Self { + isa, + artifact: faerie::Artifact::new(faerie_target, name), + format, + }) + } + + /// Return the name of the output file. This is the name passed into `new`. + pub fn name(&self) -> &str { + &self.artifact.name + } + + /// Call `emit` on the faerie `Artifact`, producing bytes in memory. + pub fn emit(&self) -> Result, Error> { + match self.format { + container::Format::ELF => self.artifact.emit::(), + container::Format::MachO => self.artifact.emit::(), + } + } + + /// Call `write` on the faerie `Artifact`, writing to a file. + pub fn write(&self, sink: File) -> Result<(), Error> { + match self.format { + container::Format::ELF => self.artifact.write::(sink), + container::Format::MachO => self.artifact.write::(sink), + } + } +} + +impl Backend for FaerieBackend { + type CompiledFunction = FaerieCompiledFunction; + type CompiledData = FaerieCompiledData; + + // There's no need to return invidual artifacts; we're writing them into + // the output file instead. + type FinalizedFunction = (); + type FinalizedData = (); + + fn isa(&self) -> &TargetIsa { + &*self.isa + } + + fn declare_function(&mut self, name: &str, linkage: Linkage) { + self.artifact + .declare(name, translate_function_linkage(linkage)) + .expect("inconsistent declarations"); + } + + fn declare_data(&mut self, name: &str, linkage: Linkage, writable: bool) { + self.artifact + .declare(name, translate_data_linkage(linkage, writable)) + .expect("inconsistent declarations"); + } + + fn define_function( + &mut self, + name: &str, + ctx: &cretonne_codegen::Context, + namespace: &ModuleNamespace, + code_size: u32, + ) -> Result { + let mut code: Vec = Vec::with_capacity(code_size as usize); + code.resize(code_size as usize, 0); + + // Non-lexical lifetimes would obviate the braces here. + { + let mut reloc_sink = FaerieRelocSink { + format: self.format, + artifact: &mut self.artifact, + name, + namespace, + }; + // Ignore traps for now. For now, frontends should just avoid generating code + // that traps. + let mut trap_sink = NullTrapSink {}; + + ctx.emit_to_memory( + code.as_mut_ptr(), + &mut reloc_sink, + &mut trap_sink, + &*self.isa, + ); + } + + self.artifact.define(name, code).expect( + "inconsistent declaration", + ); + Ok(FaerieCompiledFunction {}) + } + + fn define_data( + &mut self, + name: &str, + data_ctx: &DataContext, + namespace: &ModuleNamespace, + ) -> Result { + let &DataDescription { + writable: _writable, + ref init, + ref function_decls, + ref data_decls, + ref function_relocs, + ref data_relocs, + } = data_ctx.description(); + + let size = init.size(); + let mut bytes = Vec::with_capacity(size); + match *init { + Init::Uninitialized => { + panic!("data is not initialized yet"); + } + Init::Zeros { .. } => { + bytes.resize(size, 0); + } + Init::Bytes { ref contents } => { + bytes.extend_from_slice(contents); + } + } + + // TODO: Change the signature of this function to use something other + // than `CtonError`, as `CtonError` can't convey faerie's errors. + for &(offset, id) in function_relocs { + let to = &namespace.get_function_decl(&function_decls[id]).name; + self.artifact + .link(faerie::Link { + from: name, + to, + at: offset as usize, + }) + .map_err(|_e| CtonError::InvalidInput)?; + } + for &(offset, id, addend) in data_relocs { + debug_assert_eq!( + addend, + 0, + "faerie doesn't support addends in data section relocations yet" + ); + let to = &namespace.get_data_decl(&data_decls[id]).name; + self.artifact + .link(faerie::Link { + from: name, + to, + at: offset as usize, + }) + .map_err(|_e| CtonError::InvalidInput)?; + } + + self.artifact.define(name, bytes).expect( + "inconsistent declaration", + ); + Ok(FaerieCompiledData {}) + } + + fn write_data_funcaddr( + &mut self, + _data: &mut FaerieCompiledData, + _offset: usize, + _what: ir::FuncRef, + ) { + unimplemented!() + } + + fn write_data_dataaddr( + &mut self, + _data: &mut FaerieCompiledData, + _offset: usize, + _what: ir::GlobalVar, + _usize: binemit::Addend, + ) { + unimplemented!() + } + + fn finalize_function( + &mut self, + _func: &FaerieCompiledFunction, + _namespace: &ModuleNamespace, + ) { + // Nothing to do. + } + + fn finalize_data(&mut self, _data: &FaerieCompiledData, _namespace: &ModuleNamespace) { + // Nothing to do. + } +} + +fn translate_function_linkage(linkage: Linkage) -> faerie::Decl { + match linkage { + Linkage::Import => faerie::Decl::FunctionImport, + Linkage::Local => faerie::Decl::Function { global: false }, + Linkage::Preemptible | Linkage::Export => faerie::Decl::Function { global: true }, + } +} + +fn translate_data_linkage(linkage: Linkage, writable: bool) -> faerie::Decl { + match linkage { + Linkage::Import => faerie::Decl::DataImport, + Linkage::Local => { + faerie::Decl::Data { + global: false, + writeable: writable, + } + } + Linkage::Export => { + faerie::Decl::Data { + global: true, + writeable: writable, + } + } + Linkage::Preemptible => { + unimplemented!("faerie doesn't support preemptible globals yet"); + } + } +} + +struct FaerieRelocSink<'a> { + format: container::Format, + artifact: &'a mut faerie::Artifact, + name: &'a str, + namespace: &'a ModuleNamespace<'a, FaerieBackend>, +} + +impl<'a> RelocSink for FaerieRelocSink<'a> { + fn reloc_ebb(&mut self, _offset: CodeOffset, _reloc: Reloc, _ebb_offset: CodeOffset) { + unimplemented!(); + } + + fn reloc_external( + &mut self, + offset: CodeOffset, + reloc: Reloc, + name: &ir::ExternalName, + addend: Addend, + ) { + let ref_name = if self.namespace.is_function(name) { + &self.namespace.get_function_decl(name).name + } else { + &self.namespace.get_data_decl(name).name + }; + let addend_i32 = addend as i32; + debug_assert!(addend_i32 as i64 == addend); + let raw_reloc = container::raw_relocation(reloc, self.format); + self.artifact + .link_with( + faerie::Link { + from: self.name, + to: ref_name, + at: offset as usize, + }, + faerie::RelocOverride { + reloc: raw_reloc, + addend: addend_i32, + }, + ) + .expect("faerie relocation error"); + } + + fn reloc_jt(&mut self, _offset: CodeOffset, _reloc: Reloc, _jt: ir::JumpTable) { + unimplemented!(); + } +} diff --git a/lib/faerie/src/container.rs b/lib/faerie/src/container.rs new file mode 100644 index 0000000000..c78f05878c --- /dev/null +++ b/lib/faerie/src/container.rs @@ -0,0 +1,33 @@ +//! Utilities for working with Faerie container formats. + +use cretonne_codegen::binemit::Reloc; + +/// An object file format. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum Format { + /// The ELF object file format. + ELF, + /// The Mach-O object file format. + MachO, +} + +/// Translate from a Cretonne `Reloc` to a raw object-file-format-specific +/// relocation code. +pub fn raw_relocation(reloc: Reloc, format: Format) -> u32 { + match format { + Format::ELF => { + use goblin::elf; + match reloc { + Reloc::Abs4 => elf::reloc::R_X86_64_32, + Reloc::Abs8 => elf::reloc::R_X86_64_64, + Reloc::X86PCRel4 => elf::reloc::R_X86_64_PC32, + // TODO: Get Cretonne to tell us when we can use + // R_X86_64_GOTPCRELX/R_X86_64_REX_GOTPCRELX. + Reloc::X86GOTPCRel4 => elf::reloc::R_X86_64_GOTPCREL, + Reloc::X86PLTRel4 => elf::reloc::R_X86_64_PLT32, + _ => unimplemented!(), + } + } + Format::MachO => unimplemented!(), + } +} diff --git a/lib/faerie/src/lib.rs b/lib/faerie/src/lib.rs new file mode 100644 index 0000000000..dc1dd5a0c3 --- /dev/null +++ b/lib/faerie/src/lib.rs @@ -0,0 +1,19 @@ +//! Top-level lib.rs for `cretonne_faerie`. +//! +//! Users of this module should not have to depend on faerie directly. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] + +extern crate cretonne_codegen; +extern crate cretonne_module; +extern crate faerie; +#[macro_use] +extern crate failure; +extern crate goblin; + +mod backend; +mod container; +mod target; + +pub use backend::FaerieBackend; +pub use container::Format; diff --git a/lib/faerie/src/target.rs b/lib/faerie/src/target.rs new file mode 100644 index 0000000000..e1116dd08d --- /dev/null +++ b/lib/faerie/src/target.rs @@ -0,0 +1,18 @@ +use cretonne_codegen::isa; +use faerie::Target; +use failure::Error; + +/// Translate from a Cretonne `TargetIsa` to a Faerie `Target`. +pub fn translate(isa: &isa::TargetIsa) -> Result { + let name = isa.name(); + match name { + "x86" => Ok(if isa.flags().is_64bit() { + Target::X86_64 + } else { + Target::X86 + }), + "arm32" => Ok(Target::ARMv7), + "arm64" => Ok(Target::ARM64), + _ => Err(format_err!("unsupported isa: {}", name)), + } +} diff --git a/lib/filetests/Cargo.toml b/lib/filetests/Cargo.toml index 0e37c1ef8d..2ab50d0ebd 100644 --- a/lib/filetests/Cargo.toml +++ b/lib/filetests/Cargo.toml @@ -1,18 +1,15 @@ [package] name = "cretonne-filetests" authors = ["The Cretonne Project Developers"] -version = "0.4.1" +version = "0.5.0" description = "Test driver and implementations of the filetest commands" license = "Apache-2.0" documentation = "http://cretonne.readthedocs.io/en/latest/testing.html#file-tests" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" publish = false -[lib] -name = "cton_filetests" - [dependencies] -cretonne = { path = "../cretonne", version = "0.4.1" } -cretonne-reader = { path = "../reader", version = "0.4.1" } +cretonne-codegen = { path = "../codegen", version = "0.5.0" } +cretonne-reader = { path = "../reader", version = "0.5.0" } filecheck = "0.3.0" num_cpus = "1.8.0" diff --git a/lib/filetests/src/concurrent.rs b/lib/filetests/src/concurrent.rs index 7ca4b01d89..ac45624114 100644 --- a/lib/filetests/src/concurrent.rs +++ b/lib/filetests/src/concurrent.rs @@ -3,7 +3,7 @@ //! This module provides the `ConcurrentRunner` struct which uses a pool of threads to run tests //! concurrently. -use cretonne::timing; +use cretonne_codegen::timing; use num_cpus; use std::panic::catch_unwind; use std::path::{Path, PathBuf}; diff --git a/lib/filetests/src/lib.rs b/lib/filetests/src/lib.rs index 718502eb53..df7be54fa6 100644 --- a/lib/filetests/src/lib.rs +++ b/lib/filetests/src/lib.rs @@ -9,12 +9,12 @@ block_in_if_condition_stmt))] #[macro_use(dbg)] -extern crate cretonne; -extern crate cton_reader; +extern crate cretonne_codegen; +extern crate cretonne_reader; extern crate filecheck; extern crate num_cpus; -use cton_reader::TestCommand; +use cretonne_reader::TestCommand; use runner::TestRunner; use std::path::Path; use std::time; diff --git a/lib/filetests/src/runone.rs b/lib/filetests/src/runone.rs index 8cdec2d626..6d80afffad 100644 --- a/lib/filetests/src/runone.rs +++ b/lib/filetests/src/runone.rs @@ -1,13 +1,13 @@ //! Run the tests in a single test file. -use cretonne::ir::Function; -use cretonne::isa::TargetIsa; -use cretonne::print_errors::pretty_verifier_error; -use cretonne::settings::Flags; -use cretonne::timing; -use cretonne::verify_function; -use cton_reader::IsaSpec; -use cton_reader::parse_test; +use cretonne_codegen::ir::Function; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::print_errors::pretty_verifier_error; +use cretonne_codegen::settings::Flags; +use cretonne_codegen::timing; +use cretonne_codegen::verify_function; +use cretonne_reader::IsaSpec; +use cretonne_reader::parse_test; use std::borrow::Cow; use std::fs; use std::io::{self, Read}; diff --git a/lib/filetests/src/subtest.rs b/lib/filetests/src/subtest.rs index ba94f87e78..2ed560cb3f 100644 --- a/lib/filetests/src/subtest.rs +++ b/lib/filetests/src/subtest.rs @@ -1,9 +1,9 @@ //! `SubTest` trait. -use cretonne::ir::Function; -use cretonne::isa::TargetIsa; -use cretonne::settings::{Flags, FlagsOrIsa}; -use cton_reader::{Comment, Details}; +use cretonne_codegen::ir::Function; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::settings::{Flags, FlagsOrIsa}; +use cretonne_reader::{Comment, Details}; use filecheck::{Checker, CheckerBuilder, NO_VARIABLES}; use std::borrow::Cow; use std::result; diff --git a/lib/filetests/src/test_binemit.rs b/lib/filetests/src/test_binemit.rs index 775e014600..86058673e3 100644 --- a/lib/filetests/src/test_binemit.rs +++ b/lib/filetests/src/test_binemit.rs @@ -3,13 +3,13 @@ //! The `binemit` test command generates binary machine code for every instruction in the input //! functions and compares the results to the expected output. -use cretonne::binemit; -use cretonne::binemit::RegDiversions; -use cretonne::dbg::DisplayList; -use cretonne::ir; -use cretonne::ir::entities::AnyEntity; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen::binemit; +use cretonne_codegen::binemit::RegDiversions; +use cretonne_codegen::dbg::DisplayList; +use cretonne_codegen::ir; +use cretonne_codegen::ir::entities::AnyEntity; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use match_directive::match_directive; use std::borrow::Cow; use std::collections::HashMap; @@ -133,7 +133,7 @@ impl SubTest for TestBinEmit { // constraints. if let Some(enc) = { let mut legal_encodings = isa.legal_encodings( - &func.dfg, + &func, &func.dfg[inst], func.dfg.ctrl_typevar(inst), ).filter(|e| { @@ -251,7 +251,7 @@ impl SubTest for TestBinEmit { // Do any encodings exist? let encodings = isa.legal_encodings( - &func.dfg, + &func, &func.dfg[inst], func.dfg.ctrl_typevar(inst), ).map(|e| encinfo.display(e)) diff --git a/lib/filetests/src/test_cat.rs b/lib/filetests/src/test_cat.rs index f8f145834c..4fdedf115f 100644 --- a/lib/filetests/src/test_cat.rs +++ b/lib/filetests/src/test_cat.rs @@ -1,7 +1,7 @@ //! The `cat` subtest. -use cretonne::ir::Function; -use cton_reader::TestCommand; +use cretonne_codegen::ir::Function; +use cretonne_reader::TestCommand; use std::borrow::Cow; use subtest::{self, Context, Result as STResult, SubTest}; diff --git a/lib/filetests/src/test_compile.rs b/lib/filetests/src/test_compile.rs index a924eee799..c4b737bfc6 100644 --- a/lib/filetests/src/test_compile.rs +++ b/lib/filetests/src/test_compile.rs @@ -2,11 +2,10 @@ //! //! The `compile` test command runs each function through the full code generator pipeline -use cretonne; -use cretonne::binemit; -use cretonne::ir; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::{binemit, ir}; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -39,7 +38,7 @@ impl SubTest for TestCompile { let isa = context.isa.expect("compile needs an ISA"); // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); let code_size = comp_ctx.compile(isa).map_err(|e| { diff --git a/lib/filetests/src/test_dce.rs b/lib/filetests/src/test_dce.rs index d96214182b..14d535aca4 100644 --- a/lib/filetests/src/test_dce.rs +++ b/lib/filetests/src/test_dce.rs @@ -5,10 +5,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -35,7 +35,7 @@ impl SubTest for TestDCE { fn run(&self, func: Cow, context: &Context) -> Result<()> { // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); comp_ctx.flowgraph(); diff --git a/lib/filetests/src/test_domtree.rs b/lib/filetests/src/test_domtree.rs index da5a926f3d..9803a67d4e 100644 --- a/lib/filetests/src/test_domtree.rs +++ b/lib/filetests/src/test_domtree.rs @@ -12,11 +12,11 @@ //! We verify that the dominator tree annotations are complete and correct. //! -use cretonne::dominator_tree::{DominatorTree, DominatorTreePreorder}; -use cretonne::flowgraph::ControlFlowGraph; -use cretonne::ir::Function; -use cretonne::ir::entities::AnyEntity; -use cton_reader::TestCommand; +use cretonne_codegen::dominator_tree::{DominatorTree, DominatorTreePreorder}; +use cretonne_codegen::flowgraph::ControlFlowGraph; +use cretonne_codegen::ir::Function; +use cretonne_codegen::ir::entities::AnyEntity; +use cretonne_reader::TestCommand; use match_directive::match_directive; use std::borrow::{Borrow, Cow}; use std::collections::HashMap; diff --git a/lib/filetests/src/test_legalizer.rs b/lib/filetests/src/test_legalizer.rs index 0794081e51..cb24ba44a5 100644 --- a/lib/filetests/src/test_legalizer.rs +++ b/lib/filetests/src/test_legalizer.rs @@ -3,10 +3,10 @@ //! The `test legalizer` test command runs each function through `legalize_function()` and sends //! the result to filecheck. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -36,7 +36,7 @@ impl SubTest for TestLegalizer { } fn run(&self, func: Cow, context: &Context) -> Result<()> { - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); let isa = context.isa.expect("legalizer needs an ISA"); diff --git a/lib/filetests/src/test_licm.rs b/lib/filetests/src/test_licm.rs index c59dee1cba..3add99b1ab 100644 --- a/lib/filetests/src/test_licm.rs +++ b/lib/filetests/src/test_licm.rs @@ -5,10 +5,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -35,7 +35,7 @@ impl SubTest for TestLICM { fn run(&self, func: Cow, context: &Context) -> Result<()> { // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); comp_ctx.flowgraph(); diff --git a/lib/filetests/src/test_postopt.rs b/lib/filetests/src/test_postopt.rs index c89fb33ea5..14c0060e6d 100644 --- a/lib/filetests/src/test_postopt.rs +++ b/lib/filetests/src/test_postopt.rs @@ -2,10 +2,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -32,7 +32,7 @@ impl SubTest for TestPostopt { fn run(&self, func: Cow, context: &Context) -> Result<()> { // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); let isa = context.isa.expect("postopt needs an ISA"); diff --git a/lib/filetests/src/test_preopt.rs b/lib/filetests/src/test_preopt.rs index e2fc9819c9..f4c53ce267 100644 --- a/lib/filetests/src/test_preopt.rs +++ b/lib/filetests/src/test_preopt.rs @@ -2,10 +2,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -32,7 +32,7 @@ impl SubTest for TestPreopt { fn run(&self, func: Cow, context: &Context) -> Result<()> { // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); let isa = context.isa.expect("preopt needs an ISA"); diff --git a/lib/filetests/src/test_print_cfg.rs b/lib/filetests/src/test_print_cfg.rs index 7092126cd7..3f48b1d4e9 100644 --- a/lib/filetests/src/test_print_cfg.rs +++ b/lib/filetests/src/test_print_cfg.rs @@ -5,9 +5,9 @@ use std::borrow::Cow; -use cretonne::cfg_printer::CFGPrinter; -use cretonne::ir::Function; -use cton_reader::TestCommand; +use cretonne_codegen::cfg_printer::CFGPrinter; +use cretonne_codegen::ir::Function; +use cretonne_reader::TestCommand; use subtest::{self, Context, Result as STResult, SubTest}; /// Object implementing the `test print-cfg` sub-test. diff --git a/lib/filetests/src/test_regalloc.rs b/lib/filetests/src/test_regalloc.rs index b2ab98c3a4..5010c84ad4 100644 --- a/lib/filetests/src/test_regalloc.rs +++ b/lib/filetests/src/test_regalloc.rs @@ -5,10 +5,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -41,7 +41,7 @@ impl SubTest for TestRegalloc { let isa = context.isa.expect("register allocator needs an ISA"); // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); comp_ctx.compute_cfg(); diff --git a/lib/filetests/src/test_simple_gvn.rs b/lib/filetests/src/test_simple_gvn.rs index 62f5a2adae..467559eecb 100644 --- a/lib/filetests/src/test_simple_gvn.rs +++ b/lib/filetests/src/test_simple_gvn.rs @@ -5,10 +5,10 @@ //! //! The resulting function is sent to `filecheck`. -use cretonne; -use cretonne::ir::Function; -use cretonne::print_errors::pretty_error; -use cton_reader::TestCommand; +use cretonne_codegen; +use cretonne_codegen::ir::Function; +use cretonne_codegen::print_errors::pretty_error; +use cretonne_reader::TestCommand; use std::borrow::Cow; use std::fmt::Write; use subtest::{run_filecheck, Context, Result, SubTest}; @@ -35,7 +35,7 @@ impl SubTest for TestSimpleGVN { fn run(&self, func: Cow, context: &Context) -> Result<()> { // Create a compilation context, and drop in the function. - let mut comp_ctx = cretonne::Context::new(); + let mut comp_ctx = cretonne_codegen::Context::new(); comp_ctx.func = func.into_owned(); comp_ctx.flowgraph(); diff --git a/lib/filetests/src/test_verifier.rs b/lib/filetests/src/test_verifier.rs index a4ec799ee3..514e988936 100644 --- a/lib/filetests/src/test_verifier.rs +++ b/lib/filetests/src/test_verifier.rs @@ -9,9 +9,9 @@ //! This annotation means that the verifier is expected to given an error for the jump instruction //! containing the substring "jump to non-existent EBB". -use cretonne::ir::Function; -use cretonne::verify_function; -use cton_reader::TestCommand; +use cretonne_codegen::ir::Function; +use cretonne_codegen::verify_function; +use cretonne_reader::TestCommand; use match_directive::match_directive; use std::borrow::{Borrow, Cow}; use subtest::{Context, Result, SubTest}; diff --git a/lib/frontend/Cargo.toml b/lib/frontend/Cargo.toml index 57ee26d8c0..8dd2e65b1f 100644 --- a/lib/frontend/Cargo.toml +++ b/lib/frontend/Cargo.toml @@ -1,24 +1,21 @@ [package] authors = ["The Cretonne Project Developers"] name = "cretonne-frontend" -version = "0.4.1" +version = "0.5.0" description = "Cretonne IR builder helper" license = "Apache-2.0" documentation = "https://cretonne.readthedocs.io/" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" readme = "README.md" -[lib] -name = "cton_frontend" - [dependencies] -cretonne = { path = "../cretonne", version = "0.4.1", default-features = false } +cretonne-codegen = { path = "../codegen", version = "0.5.0", default-features = false } [features] default = ["std"] -std = ["cretonne/std"] -core = ["cretonne/core"] +std = ["cretonne-codegen/std"] +core = ["cretonne-codegen/core"] [badges] maintenance = { status = "experimental" } -travis-ci = { repository = "Cretonne/cretonne" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/frontend/src/frontend.rs b/lib/frontend/src/frontend.rs index 4396c4edac..12568582e2 100644 --- a/lib/frontend/src/frontend.rs +++ b/lib/frontend/src/frontend.rs @@ -1,13 +1,14 @@ //! A frontend for building Cretonne IR from other languages. -use cretonne::cursor::{Cursor, FuncCursor}; -use cretonne::entity::{EntityMap, EntityRef, EntitySet}; -use cretonne::ir; -use cretonne::ir::function::DisplayFunction; -use cretonne::ir::{DataFlowGraph, Ebb, ExtFuncData, FuncRef, Function, GlobalVar, GlobalVarData, - Heap, HeapData, Inst, InstBuilderBase, InstructionData, JumpTable, - JumpTableData, SigRef, Signature, StackSlot, StackSlotData, Type, Value}; -use cretonne::isa::TargetIsa; -use cretonne::packed_option::PackedOption; +use cretonne_codegen::cursor::{Cursor, FuncCursor}; +use cretonne_codegen::entity::{EntityMap, EntityRef, EntitySet}; +use cretonne_codegen::ir; +use cretonne_codegen::ir::function::DisplayFunction; +use cretonne_codegen::ir::{DataFlowGraph, Ebb, ExtFuncData, FuncRef, Function, GlobalVar, + GlobalVarData, Heap, HeapData, Inst, InstBuilderBase, InstructionData, + JumpTable, JumpTableData, SigRef, Signature, StackSlot, StackSlotData, + Type, Value}; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::packed_option::PackedOption; use ssa::{Block, SSABuilder, SideEffects}; /// Structure used for translating a series of functions into Cretonne IR. @@ -101,7 +102,7 @@ where } } -/// Implementation of the [`InstBuilder`](../cretonne/ir/builder/trait.InstBuilder.html) that has +/// Implementation of the [`InstBuilder`](../codegen/ir/builder/trait.InstBuilder.html) that has /// one convenience method per Cretonne IR instruction. pub struct FuncInstBuilder<'short, 'long: 'short, Variable: 'long> where @@ -374,7 +375,7 @@ where self.func.create_heap(data) } - /// Returns an object with the [`InstBuilder`](../cretonne/ir/builder/trait.InstBuilder.html) + /// Returns an object with the [`InstBuilder`](../codegen/ir/builder/trait.InstBuilder.html) /// trait that allows to conveniently append an instruction to the current `Ebb` being built. pub fn ins<'short>(&'short mut self) -> FuncInstBuilder<'short, 'a, Variable> { let ebb = self.position.ebb.unwrap(); @@ -593,11 +594,11 @@ where mod tests { use Variable; - use cretonne::entity::EntityRef; - use cretonne::ir::types::*; - use cretonne::ir::{AbiParam, CallConv, ExternalName, Function, InstBuilder, Signature}; - use cretonne::settings; - use cretonne::verifier::verify_function; + use cretonne_codegen::entity::EntityRef; + use cretonne_codegen::ir::types::*; + use cretonne_codegen::ir::{AbiParam, CallConv, ExternalName, Function, InstBuilder, Signature}; + use cretonne_codegen::settings; + use cretonne_codegen::verifier::verify_function; use frontend::{FunctionBuilder, FunctionBuilderContext}; fn sample_function(lazy_seal: bool) { diff --git a/lib/frontend/src/lib.rs b/lib/frontend/src/lib.rs index 6e04fd190a..5a3d4d9b66 100644 --- a/lib/frontend/src/lib.rs +++ b/lib/frontend/src/lib.rs @@ -32,15 +32,15 @@ //! Here is how you build the corresponding Cretonne IR function using `FunctionBuilderContext`: //! //! ```rust -//! extern crate cretonne; -//! extern crate cton_frontend; +//! extern crate cretonne_codegen; +//! extern crate cretonne_frontend; //! -//! use cretonne::entity::EntityRef; -//! use cretonne::ir::{ExternalName, CallConv, Function, Signature, AbiParam, InstBuilder}; -//! use cretonne::ir::types::*; -//! use cretonne::settings; -//! use cton_frontend::{FunctionBuilderContext, FunctionBuilder, Variable}; -//! use cretonne::verifier::verify_function; +//! use cretonne_codegen::entity::EntityRef; +//! use cretonne_codegen::ir::{ExternalName, CallConv, Function, Signature, AbiParam, InstBuilder}; +//! use cretonne_codegen::ir::types::*; +//! use cretonne_codegen::settings; +//! use cretonne_frontend::{FunctionBuilderContext, FunctionBuilder, Variable}; +//! use cretonne_codegen::verifier::verify_function; //! //! fn main() { //! let mut sig = Signature::new(CallConv::SystemV); @@ -129,11 +129,10 @@ #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![cfg_attr(feature = "cargo-clippy", allow(new_without_default, redundant_field_names))] - #![cfg_attr(not(feature = "std"), no_std)] #![cfg_attr(not(feature = "std"), feature(alloc))] -extern crate cretonne; +extern crate cretonne_codegen; #[cfg(not(feature = "std"))] extern crate alloc; diff --git a/lib/frontend/src/ssa.rs b/lib/frontend/src/ssa.rs index 6c1579228b..138dfe3933 100644 --- a/lib/frontend/src/ssa.rs +++ b/lib/frontend/src/ssa.rs @@ -5,14 +5,14 @@ //! In: Jhala R., De Bosschere K. (eds) Compiler Construction. CC 2013. //! Lecture Notes in Computer Science, vol 7791. Springer, Berlin, Heidelberg -use cretonne::cursor::{Cursor, FuncCursor}; -use cretonne::entity::{EntityMap, EntityRef, PrimaryMap}; -use cretonne::ir::immediates::{Ieee32, Ieee64}; -use cretonne::ir::instructions::BranchInfo; -use cretonne::ir::types::{F32, F64}; -use cretonne::ir::{Ebb, Function, Inst, InstBuilder, Type, Value}; -use cretonne::packed_option::PackedOption; -use cretonne::packed_option::ReservedValue; +use cretonne_codegen::cursor::{Cursor, FuncCursor}; +use cretonne_codegen::entity::{EntityMap, EntityRef, PrimaryMap}; +use cretonne_codegen::ir::immediates::{Ieee32, Ieee64}; +use cretonne_codegen::ir::instructions::BranchInfo; +use cretonne_codegen::ir::types::{F32, F64}; +use cretonne_codegen::ir::{Ebb, Function, Inst, InstBuilder, Type, Value}; +use cretonne_codegen::packed_option::PackedOption; +use cretonne_codegen::packed_option::ReservedValue; use std::mem; use std::u32; use std::vec::Vec; @@ -714,13 +714,13 @@ where #[cfg(test)] mod tests { use Variable; - use cretonne::cursor::{Cursor, FuncCursor}; - use cretonne::entity::EntityRef; - use cretonne::ir::instructions::BranchInfo; - use cretonne::ir::types::*; - use cretonne::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode}; - use cretonne::settings; - use cretonne::verify_function; + use cretonne_codegen::cursor::{Cursor, FuncCursor}; + use cretonne_codegen::entity::EntityRef; + use cretonne_codegen::ir::instructions::BranchInfo; + use cretonne_codegen::ir::types::*; + use cretonne_codegen::ir::{Function, Inst, InstBuilder, JumpTableData, Opcode}; + use cretonne_codegen::settings; + use cretonne_codegen::verify_function; use ssa::SSABuilder; #[test] diff --git a/lib/frontend/src/variable.rs b/lib/frontend/src/variable.rs index b4e3c75da2..368d4bfb18 100644 --- a/lib/frontend/src/variable.rs +++ b/lib/frontend/src/variable.rs @@ -5,7 +5,7 @@ //! their own index types to use them directly. Frontends which don't //! can use the `Variable` defined here. -use cretonne::entity::EntityRef; +use cretonne_codegen::entity::EntityRef; use std::u32; ///! An opaque reference to a variable. diff --git a/lib/module/Cargo.toml b/lib/module/Cargo.toml new file mode 100644 index 0000000000..f43fde30a7 --- /dev/null +++ b/lib/module/Cargo.toml @@ -0,0 +1,17 @@ +[package] +name = "cretonne-module" +version = "0.5.0" +authors = ["The Cretonne Project Developers"] +description = "Support for linking functions and data with Cretonne" +repository = "https://github.com/Cretonne/cretonne" +documentation = "https://cretonne.readthedocs.io/" +license = "Apache-2.0" +readme = "README.md" + +[dependencies] +cretonne-codegen = { path = "../codegen", version = "0.5.0" } +cretonne-entity = { path = "../entity", version = "0.5.0" } + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "Cretonne/cretonne" } diff --git a/lib/module/README.md b/lib/module/README.md new file mode 100644 index 0000000000..370bde4333 --- /dev/null +++ b/lib/module/README.md @@ -0,0 +1,3 @@ +This crate provides the `Module` trait, which provides an interface for +multiple functions and data to be emitted with +[Cretonne](https://crates.io/crates/cretonne) and then linked together. diff --git a/lib/module/src/backend.rs b/lib/module/src/backend.rs new file mode 100644 index 0000000000..0d6a6c6672 --- /dev/null +++ b/lib/module/src/backend.rs @@ -0,0 +1,97 @@ +//! Defines the `Backend` trait. + +use DataContext; +use Linkage; +use ModuleNamespace; +use cretonne_codegen::Context; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::result::CtonError; +use cretonne_codegen::{binemit, ir}; +use std::marker; + +/// A `Backend` implements the functionality needed to support a `Module`. +pub trait Backend +where + Self: marker::Sized, +{ + /// The results of compiling a function. + type CompiledFunction; + + /// The results of "compiling" a data object. + type CompiledData; + + /// The completed output artifact for a function, if this is meaningful for + /// the Backend. + type FinalizedFunction; + + /// The completed output artifact for a data object, if this is meaningful for + /// the Backend. + type FinalizedData; + + /// Return the `TargetIsa` to compile for. + fn isa(&self) -> &TargetIsa; + + /// Declare a function. + fn declare_function(&mut self, name: &str, linkage: Linkage); + + /// Declare a data object. + fn declare_data(&mut self, name: &str, linkage: Linkage, writable: bool); + + /// Define a function, producing the function body from the given `Context`. + /// + /// Functions must be declared before being defined. + fn define_function( + &mut self, + name: &str, + ctx: &Context, + namespace: &ModuleNamespace, + code_size: u32, + ) -> Result; + + /// Define a zero-initialized data object of the given size. + /// + /// Data objects must be declared before being defined. + /// + /// TODO: Is CtonError the right error code here? + fn define_data( + &mut self, + name: &str, + data_ctx: &DataContext, + namespace: &ModuleNamespace, + ) -> Result; + + /// Write the address of `what` into the data for `data` at `offset`. `data` must refer to a + /// defined data object. + fn write_data_funcaddr( + &mut self, + data: &mut Self::CompiledData, + offset: usize, + what: ir::FuncRef, + ); + + /// Write the address of `what` plus `addend` into the data for `data` at `offset`. `data` must + /// refer to a defined data object. + fn write_data_dataaddr( + &mut self, + data: &mut Self::CompiledData, + offset: usize, + what: ir::GlobalVar, + addend: binemit::Addend, + ); + + /// Perform all outstanding relocations on the given function. This requires all `Local` + /// and `Export` entities referenced to be defined. + fn finalize_function( + &mut self, + func: &Self::CompiledFunction, + namespace: &ModuleNamespace, + ) -> Self::FinalizedFunction; + + /// Perform all outstanding relocations on the given data object. This requires all + /// `Local` and `Export` entities referenced to be defined. + fn finalize_data( + &mut self, + data: &Self::CompiledData, + namespace: &ModuleNamespace, + ) -> Self::FinalizedData; +} diff --git a/lib/module/src/data_context.rs b/lib/module/src/data_context.rs new file mode 100644 index 0000000000..510b549e90 --- /dev/null +++ b/lib/module/src/data_context.rs @@ -0,0 +1,205 @@ +//! Defines `DataContext`. + +use cretonne_codegen::entity::PrimaryMap; +use cretonne_codegen::binemit::{CodeOffset, Addend}; +use cretonne_codegen::ir; + +/// This specifies how data is to be initialized. +#[derive(PartialEq, Eq, Debug)] +pub enum Init { + /// This indicates that no initialization has been specified yet. + Uninitialized, + /// Initialize the data with all zeros. + Zeros { + /// The size of the data. + size: usize, + }, + /// Initialize the data with the specified contents. + Bytes { + /// The contents, which also implies the size of the data. + contents: Box<[u8]>, + }, +} + +impl Init { + /// Return the size of the data to be initialized. + pub fn size(&self) -> usize { + match *self { + Init::Uninitialized => panic!("data size not initialized yet"), + Init::Zeros { size } => size, + Init::Bytes { ref contents } => contents.len(), + } + } +} + +/// A flag specifying whether data is readonly or may be written to. +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum Writability { + /// Data is readonly, meaning writes to it will trap. + Readonly, + /// Data is writable. + Writable, +} + +/// A description of a data object. +pub struct DataDescription { + /// Whether the data readonly or writable. + pub writable: Writability, + /// How the data should be initialized. + pub init: Init, + /// External function declarations. + pub function_decls: PrimaryMap, + /// External data object declarations. + pub data_decls: PrimaryMap, + /// Function addresses to write at specified offsets. + pub function_relocs: Vec<(CodeOffset, ir::FuncRef)>, + /// Data addresses to write at specified offsets. + pub data_relocs: Vec<(CodeOffset, ir::GlobalVar, Addend)>, +} + +/// This is to data objects what cretonne_codegen::Context is to functions. +pub struct DataContext { + description: DataDescription, +} + +impl DataContext { + /// Allocate a new context. + pub fn new() -> Self { + Self { + description: DataDescription { + writable: Writability::Readonly, + init: Init::Uninitialized, + function_decls: PrimaryMap::new(), + data_decls: PrimaryMap::new(), + function_relocs: Vec::new(), + data_relocs: Vec::new(), + }, + } + } + + /// Clear all data structures in this context. + pub fn clear(&mut self) { + self.description.writable = Writability::Readonly; + self.description.init = Init::Uninitialized; + self.description.function_decls.clear(); + self.description.data_decls.clear(); + self.description.function_relocs.clear(); + self.description.data_relocs.clear(); + } + + /// Define a zero-initialized object with the given size. + pub fn define_zeroinit(&mut self, size: usize, writable: Writability) { + debug_assert_eq!(self.description.init, Init::Uninitialized); + self.description.writable = writable; + self.description.init = Init::Zeros { size }; + } + + /// Define a zero-initialized object with the given size. + /// + /// TODO: Can we avoid a Box here? + pub fn define(&mut self, contents: Box<[u8]>, writable: Writability) { + debug_assert_eq!(self.description.init, Init::Uninitialized); + self.description.writable = writable; + self.description.init = Init::Bytes { contents }; + } + + /// Declare an external function import. + pub fn import_function(&mut self, name: ir::ExternalName) -> ir::FuncRef { + self.description.function_decls.push(name) + } + + /// Declares a global variable import. + /// + /// TODO: Rename to import_data? + pub fn import_global_var(&mut self, name: ir::ExternalName) -> ir::GlobalVar { + self.description.data_decls.push(name) + } + + /// Write the address of `func` into the data at offset `offset`. + pub fn write_function_addr(&mut self, offset: CodeOffset, func: ir::FuncRef) { + self.description.function_relocs.push((offset, func)) + } + + /// Write the address of `data` into the data at offset `offset`. + pub fn write_data_addr(&mut self, offset: CodeOffset, data: ir::GlobalVar, addend: Addend) { + self.description.data_relocs.push((offset, data, addend)) + } + + /// Reference the initializer data. + pub fn description(&self) -> &DataDescription { + debug_assert!( + self.description.init != Init::Uninitialized, + "data must be initialized first" + ); + &self.description + } +} + +#[cfg(test)] +mod tests { + use {DataContext, Writability, Init}; + use cretonne_codegen::ir; + + #[test] + fn basic_data_context() { + let mut data_ctx = DataContext::new(); + { + let description = data_ctx.description(); + assert_eq!(description.writable, Writability::Readonly); + assert_eq!(description.init, Init::Uninitialized); + assert!(description.function_decls.is_empty()); + assert!(description.data_decls.is_empty()); + assert!(description.function_relocs.is_empty()); + assert!(description.data_relocs.is_empty()); + } + + data_ctx.define_zeroinit(256, Writability::Writable); + + let _func_a = data_ctx.import_function(ir::ExternalName::user(0, 0)); + let func_b = data_ctx.import_function(ir::ExternalName::user(0, 1)); + let func_c = data_ctx.import_function(ir::ExternalName::user(1, 0)); + let _data_a = data_ctx.import_global_var(ir::ExternalName::user(2, 2)); + let data_b = data_ctx.import_global_var(ir::ExternalName::user(2, 3)); + + data_ctx.write_function_addr(8, func_b); + data_ctx.write_function_addr(16, func_c); + data_ctx.write_data_addr(32, data_b, 27); + + { + let description = data_ctx.description(); + assert_eq!(description.writable, Writability::Writable); + assert_eq!(description.init, Init::Zeros { size: 256 }); + assert_eq!(description.function_decls.len(), 3); + assert_eq!(description.data_decls.len(), 2); + assert_eq!(description.function_relocs.len(), 2); + assert_eq!(description.data_relocs.len(), 1); + } + + data_ctx.clear(); + { + let description = data_ctx.description(); + assert_eq!(description.writable, Writability::Readonly); + assert_eq!(description.init, Init::Uninitialized); + assert!(description.function_decls.is_empty()); + assert!(description.data_decls.is_empty()); + assert!(description.function_relocs.is_empty()); + assert!(description.data_relocs.is_empty()); + } + + let contents = vec![33, 34, 35, 36]; + let contents_clone = contents.clone(); + data_ctx.define(contents.into_boxed_slice(), Writability::Readonly); + { + let description = data_ctx.description(); + assert_eq!(description.writable, Writability::Readonly); + assert_eq!( + description.init, + Init::Bytes { contents: contents_clone.into_boxed_slice() } + ); + assert_eq!(description.function_decls.len(), 0); + assert_eq!(description.data_decls.len(), 0); + assert_eq!(description.function_relocs.len(), 0); + assert_eq!(description.data_relocs.len(), 0); + } + } +} diff --git a/lib/module/src/lib.rs b/lib/module/src/lib.rs new file mode 100644 index 0000000000..ebc44420cc --- /dev/null +++ b/lib/module/src/lib.rs @@ -0,0 +1,15 @@ +//! Top-level lib.rs for `cretonne_module`. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] + +extern crate cretonne_codegen; +#[macro_use] +extern crate cretonne_entity; + +mod backend; +mod data_context; +mod module; + +pub use backend::Backend; +pub use data_context::{DataContext, Writability, DataDescription, Init}; +pub use module::{DataId, FuncId, Linkage, Module, ModuleNamespace}; diff --git a/lib/module/src/module.rs b/lib/module/src/module.rs new file mode 100644 index 0000000000..69e9d7432f --- /dev/null +++ b/lib/module/src/module.rs @@ -0,0 +1,541 @@ +//! Defines `Module` and related types. + +// TODO: Should `ir::Function` really have a `name`? + +// TODO: Factor out `ir::Function`'s `ext_funcs` and `global_vars` into a struct +// shared with `DataContext`? + +use Backend; +use cretonne_codegen::entity::{EntityRef, PrimaryMap}; +use cretonne_codegen::result::{CtonError, CtonResult}; +use cretonne_codegen::{binemit, ir, Context}; +use data_context::DataContext; +use std::collections::HashMap; + +/// A function identifier for use in the `Module` interface. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct FuncId(u32); +entity_impl!(FuncId, "funcid"); + +/// A data object identifier for use in the `Module` interface. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +pub struct DataId(u32); +entity_impl!(DataId, "dataid"); + +/// Linkage refers to where an entity is defined and who can see it. +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum Linkage { + /// Defined outside of a module. + Import, + /// Defined inside the module, but not visible outside it. + Local, + /// Defined inside the module, visible outside it, and may be preempted. + Preemptible, + /// Defined inside the module, and visible outside it. + Export, +} + +impl Linkage { + fn merge(a: Linkage, b: Linkage) -> Linkage { + match a { + Linkage::Export => Linkage::Export, + Linkage::Preemptible => { + match b { + Linkage::Export => Linkage::Export, + _ => Linkage::Preemptible, + } + } + Linkage::Local => { + match b { + Linkage::Export => Linkage::Export, + Linkage::Preemptible => Linkage::Preemptible, + _ => Linkage::Local, + } + } + Linkage::Import => b, + } + } + + /// Test whether this linkage can have a definition. + pub fn is_definable(&self) -> bool { + match *self { + Linkage::Import => false, + Linkage::Local | Linkage::Preemptible | Linkage::Export => true, + } + } + + /// Test whether this linkage will have a definition that cannot be preempted. + pub fn is_final(&self) -> bool { + match *self { + Linkage::Import | Linkage::Preemptible => false, + Linkage::Local | Linkage::Export => true, + } + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] +enum FuncOrDataId { + Func(FuncId), + Data(DataId), +} + +pub struct FunctionDeclaration { + pub name: String, + pub linkage: Linkage, + pub signature: ir::Signature, +} + +struct ModuleFunction +where + B: Backend, +{ + decl: FunctionDeclaration, + compiled: Option, + finalized: bool, +} + +impl ModuleFunction +where + B: Backend, +{ + fn merge(&mut self, linkage: Linkage) { + self.decl.linkage = Linkage::merge(self.decl.linkage, linkage); + } +} + +pub struct DataDeclaration { + pub name: String, + pub linkage: Linkage, + pub writable: bool, +} + +struct ModuleData +where + B: Backend, +{ + decl: DataDeclaration, + compiled: Option, + finalized: bool, +} + +impl ModuleData +where + B: Backend, +{ + fn merge(&mut self, linkage: Linkage, writable: bool) { + self.decl.linkage = Linkage::merge(self.decl.linkage, linkage); + self.decl.writable = self.decl.writable || writable; + } +} + +struct ModuleContents +where + B: Backend, +{ + functions: PrimaryMap>, + data_objects: PrimaryMap>, +} + +impl ModuleContents +where + B: Backend, +{ + fn get_function_info(&self, name: &ir::ExternalName) -> &ModuleFunction { + if let ir::ExternalName::User { namespace, index } = *name { + debug_assert_eq!(namespace, 0); + let func = FuncId::new(index as usize); + &self.functions[func] + } else { + panic!("unexpected ExternalName kind") + } + } + + /// Get the `DataDeclaration` for the function named by `name`. + fn get_data_info(&self, name: &ir::ExternalName) -> &ModuleData { + if let ir::ExternalName::User { namespace, index } = *name { + debug_assert_eq!(namespace, 1); + let data = DataId::new(index as usize); + &self.data_objects[data] + } else { + panic!("unexpected ExternalName kind") + } + } +} + +/// This provides a view to the state of a module which allows `ir::ExternalName`s to be translated +/// into `FunctionDeclaration`s and `DataDeclaration`s. +pub struct ModuleNamespace<'a, B: 'a> +where + B: Backend, +{ + contents: &'a ModuleContents, +} + +impl<'a, B> ModuleNamespace<'a, B> +where + B: Backend, +{ + /// Get the `FunctionDeclaration` for the function named by `name`. + pub fn get_function_decl(&self, name: &ir::ExternalName) -> &FunctionDeclaration { + &self.contents.get_function_info(name).decl + } + + /// Get the `DataDeclaration` for the function named by `name`. + pub fn get_data_decl(&self, name: &ir::ExternalName) -> &DataDeclaration { + &self.contents.get_data_info(name).decl + } + + /// Get the definition for the function named by `name`, along with its name + /// and signature. + pub fn get_function_definition( + &self, + name: &ir::ExternalName, + ) -> (Option<&B::CompiledFunction>, &str, &ir::Signature) { + let info = self.contents.get_function_info(name); + debug_assert_eq!(info.decl.linkage.is_definable(), info.compiled.is_some()); + ( + info.compiled.as_ref(), + &info.decl.name, + &info.decl.signature, + ) + } + + /// Get the definition for the data object named by `name`, along with its name + /// and writable flag + pub fn get_data_definition( + &self, + name: &ir::ExternalName, + ) -> (Option<&B::CompiledData>, &str, bool) { + let info = self.contents.get_data_info(name); + debug_assert_eq!(info.decl.linkage.is_definable(), info.compiled.is_some()); + (info.compiled.as_ref(), &info.decl.name, info.decl.writable) + } + + /// Return whether `name` names a function, rather than a data object. + pub fn is_function(&self, name: &ir::ExternalName) -> bool { + if let ir::ExternalName::User { namespace, .. } = *name { + namespace == 0 + } else { + panic!("unexpected ExternalName kind") + } + } +} + +/// A `Module` is a utility for collecting functions and data objects, and linking them together. +pub struct Module +where + B: Backend, +{ + names: HashMap, + contents: ModuleContents, + backend: B, +} + +impl Module +where + B: Backend, +{ + /// Create a new `Module`. + pub fn new(backend: B) -> Self { + Self { + names: HashMap::new(), + contents: ModuleContents { + functions: PrimaryMap::new(), + data_objects: PrimaryMap::new(), + }, + backend, + } + } + + /// Return then pointer type for the current target. + pub fn pointer_type(&self) -> ir::types::Type { + if self.backend.isa().flags().is_64bit() { + ir::types::I64 + } else { + ir::types::I32 + } + } + + /// Declare a function in this module. + pub fn declare_function( + &mut self, + name: &str, + linkage: Linkage, + signature: &ir::Signature, + ) -> Result { + // TODO: Can we avoid allocating names so often? + use std::collections::hash_map::Entry::*; + match self.names.entry(name.to_owned()) { + Occupied(entry) => { + match *entry.get() { + FuncOrDataId::Func(id) => { + let existing = &mut self.contents.functions[id]; + existing.merge(linkage); + self.backend.declare_function(name, existing.decl.linkage); + Ok(id) + } + FuncOrDataId::Data(..) => unimplemented!(), + } + } + Vacant(entry) => { + let id = self.contents.functions.push(ModuleFunction { + decl: FunctionDeclaration { + name: name.to_owned(), + linkage, + signature: signature.clone(), + }, + compiled: None, + finalized: false, + }); + entry.insert(FuncOrDataId::Func(id)); + self.backend.declare_function(name, linkage); + Ok(id) + } + } + } + + /// Declare a data object in this module. + pub fn declare_data( + &mut self, + name: &str, + linkage: Linkage, + writable: bool, + ) -> Result { + // TODO: Can we avoid allocating names so often? + use std::collections::hash_map::Entry::*; + match self.names.entry(name.to_owned()) { + Occupied(entry) => { + match *entry.get() { + FuncOrDataId::Data(id) => { + let existing = &mut self.contents.data_objects[id]; + existing.merge(linkage, writable); + self.backend.declare_data( + name, + existing.decl.linkage, + existing.decl.writable, + ); + Ok(id) + } + + FuncOrDataId::Func(..) => unimplemented!(), + } + } + Vacant(entry) => { + let id = self.contents.data_objects.push(ModuleData { + decl: DataDeclaration { + name: name.to_owned(), + linkage, + writable, + }, + compiled: None, + finalized: false, + }); + entry.insert(FuncOrDataId::Data(id)); + self.backend.declare_data(name, linkage, writable); + Ok(id) + } + } + } + + /// Use this when you're building the IR of a function to reference a function. + /// + /// TODO: Coalesce redundant decls and signatures. + /// TODO: Look into ways to reduce the risk of using a FuncRef in the wrong function. + pub fn declare_func_in_func(&self, func: FuncId, in_func: &mut ir::Function) -> ir::FuncRef { + let decl = &self.contents.functions[func].decl; + let signature = in_func.import_signature(decl.signature.clone()); + let colocated = decl.linkage.is_final(); + in_func.import_function(ir::ExtFuncData { + name: ir::ExternalName::user(0, func.index() as u32), + signature, + colocated, + }) + } + + /// Use this when you're building the IR of a function to reference a data object. + /// + /// TODO: Same as above. + pub fn declare_data_in_func(&self, data: DataId, func: &mut ir::Function) -> ir::GlobalVar { + let decl = &self.contents.data_objects[data].decl; + let colocated = decl.linkage.is_final(); + func.create_global_var(ir::GlobalVarData::Sym { + name: ir::ExternalName::user(1, data.index() as u32), + colocated, + }) + } + + /// TODO: Same as above. + pub fn declare_func_in_data(&self, func: FuncId, ctx: &mut DataContext) -> ir::FuncRef { + ctx.import_function(ir::ExternalName::user(0, func.index() as u32)) + } + + /// TODO: Same as above. + pub fn declare_data_in_data(&self, data: DataId, ctx: &mut DataContext) -> ir::GlobalVar { + ctx.import_global_var(ir::ExternalName::user(1, data.index() as u32)) + } + + /// Define a function, producing the function body from the given `Context`. + pub fn define_function(&mut self, func: FuncId, ctx: &mut Context) -> CtonResult { + let compiled = { + let code_size = ctx.compile(self.backend.isa())?; + + let info = &self.contents.functions[func]; + debug_assert!( + info.compiled.is_none(), + "functions can be defined only once" + ); + debug_assert!( + info.decl.linkage.is_definable(), + "imported functions cannot be defined" + ); + Some(self.backend.define_function( + &info.decl.name, + ctx, + &ModuleNamespace:: { + contents: &self.contents, + }, + code_size, + )?) + }; + self.contents.functions[func].compiled = compiled; + Ok(()) + } + + /// Define a function, producing the data contents from the given `DataContext`. + pub fn define_data(&mut self, data: DataId, data_ctx: &DataContext) -> CtonResult { + let compiled = { + let info = &self.contents.data_objects[data]; + debug_assert!( + info.compiled.is_none(), + "functions can be defined only once" + ); + debug_assert!( + info.decl.linkage.is_definable(), + "imported functions cannot be defined" + ); + Some(self.backend.define_data( + &info.decl.name, + data_ctx, + &ModuleNamespace:: { + contents: &self.contents, + }, + )?) + }; + self.contents.data_objects[data].compiled = compiled; + Ok(()) + } + + /// Write the address of `what` into the data for `data` at `offset`. `data` must refer to a + /// defined data object. + pub fn write_data_funcaddr(&mut self, data: DataId, offset: usize, what: ir::FuncRef) { + let info = &mut self.contents.data_objects[data]; + debug_assert!( + info.decl.linkage.is_definable(), + "imported data cannot contain references" + ); + self.backend.write_data_funcaddr( + &mut info.compiled.as_mut().expect( + "`data` must refer to a defined data object", + ), + offset, + what, + ); + } + + /// Write the address of `what` plus `addend` into the data for `data` at `offset`. `data` must + /// refer to a defined data object. + pub fn write_data_dataaddr( + &mut self, + data: DataId, + offset: usize, + what: ir::GlobalVar, + addend: binemit::Addend, + ) { + let info = &mut self.contents.data_objects[data]; + debug_assert!( + info.decl.linkage.is_definable(), + "imported data cannot contain references" + ); + self.backend.write_data_dataaddr( + &mut info.compiled.as_mut().expect( + "`data` must refer to a defined data object", + ), + offset, + what, + addend, + ); + } + + /// Perform all outstanding relocations on the given function. This requires all `Local` + /// and `Export` entities referenced to be defined. + pub fn finalize_function(&mut self, func: FuncId) -> B::FinalizedFunction { + let output = { + let info = &self.contents.functions[func]; + debug_assert!( + info.decl.linkage.is_definable(), + "imported data cannot be finalized" + ); + self.backend.finalize_function( + info.compiled.as_ref().expect( + "function must be compiled before it can be finalized", + ), + &ModuleNamespace:: { contents: &self.contents }, + ) + }; + self.contents.functions[func].finalized = true; + output + } + + /// Perform all outstanding relocations on the given data object. This requires all + /// `Local` and `Export` entities referenced to be defined. + pub fn finalize_data(&mut self, data: DataId) -> B::FinalizedData { + let output = { + let info = &self.contents.data_objects[data]; + debug_assert!( + info.decl.linkage.is_definable(), + "imported data cannot be finalized" + ); + self.backend.finalize_data( + info.compiled.as_ref().expect( + "data object must be compiled before it can be finalized", + ), + &ModuleNamespace:: { contents: &self.contents }, + ) + }; + self.contents.data_objects[data].finalized = true; + output + } + + /// Finalize all functions and data objects. Note that this doesn't return the + /// final artifacts returned from `finalize_function` or `finalize_data`. + pub fn finalize_all(&mut self) { + // TODO: Could we use something like `into_iter()` here? + for info in self.contents.functions.values() { + if info.decl.linkage.is_definable() && !info.finalized { + self.backend.finalize_function( + info.compiled.as_ref().expect( + "function must be compiled before it can be finalized", + ), + &ModuleNamespace:: { contents: &self.contents }, + ); + } + } + for info in self.contents.data_objects.values() { + if info.decl.linkage.is_definable() && !info.finalized { + self.backend.finalize_data( + info.compiled.as_ref().expect( + "data object must be compiled before it can be finalized", + ), + &ModuleNamespace:: { contents: &self.contents }, + ); + } + } + } + + /// Consume the module and return its contained `Backend`. Some `Backend` + /// implementations have additional features not available through the + /// `Module` interface. + pub fn consume(self) -> B { + self.backend + } +} diff --git a/lib/native/Cargo.toml b/lib/native/Cargo.toml index 34e910de8f..d01a72ddde 100644 --- a/lib/native/Cargo.toml +++ b/lib/native/Cargo.toml @@ -1,26 +1,23 @@ [package] name = "cretonne-native" -version = "0.4.1" +version = "0.5.0" authors = ["The Cretonne Project Developers"] description = "Support for targeting the host with Cretonne" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" license = "Apache-2.0" readme = "README.md" -[lib] -name = "cton_native" - [dependencies] -cretonne = { path = "../cretonne", version = "0.4.1", default-features = false } +cretonne-codegen = { path = "../codegen", version = "0.5.0", default-features = false } [target.'cfg(any(target_arch = "x86", target_arch = "x86_64"))'.dependencies] raw-cpuid = "3.0.0" [features] default = ["std"] -std = ["cretonne/std"] -core = ["cretonne/core"] +std = ["cretonne-codegen/std"] +core = ["cretonne-codegen/core"] [badges] maintenance = { status = "experimental" } -travis-ci = { repository = "Cretonne/cretonne" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/native/src/lib.rs b/lib/native/src/lib.rs index d09a0b04f2..601a9bfc28 100644 --- a/lib/native/src/lib.rs +++ b/lib/native/src/lib.rs @@ -2,16 +2,14 @@ //! Cretonne to generate code to run on the same machine. #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] - #![cfg_attr(not(feature = "std"), no_std)] -extern crate cretonne; - +extern crate cretonne_codegen; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] extern crate raw_cpuid; -use cretonne::isa; -use cretonne::settings::{self, Configurable}; +use cretonne_codegen::isa; +use cretonne_codegen::settings::{self, Configurable}; #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] use raw_cpuid::CpuId; @@ -29,7 +27,7 @@ pub fn builders() -> Result<(settings::Builder, isa::Builder), &'static str> { } let name = if cfg!(any(target_arch = "x86", target_arch = "x86_64")) { - "intel" + "x86" } else if cfg!(target_arch = "arm") { "arm32" } else if cfg!(target_arch = "aarch64") { diff --git a/lib/reader/Cargo.toml b/lib/reader/Cargo.toml index d8259a2027..0b984515d9 100644 --- a/lib/reader/Cargo.toml +++ b/lib/reader/Cargo.toml @@ -1,19 +1,16 @@ [package] authors = ["The Cretonne Project Developers"] name = "cretonne-reader" -version = "0.4.1" +version = "0.5.0" description = "Cretonne textual IR reader" license = "Apache-2.0" documentation = "https://cretonne.readthedocs.io/" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" readme = "README.md" -[lib] -name = "cton_reader" - [dependencies] -cretonne = { path = "../cretonne", version = "0.4.1" } +cretonne-codegen = { path = "../codegen", version = "0.5.0" } [badges] maintenance = { status = "experimental" } -travis-ci = { repository = "Cretonne/cretonne" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/reader/src/isaspec.rs b/lib/reader/src/isaspec.rs index e87b2b6771..85b08df368 100644 --- a/lib/reader/src/isaspec.rs +++ b/lib/reader/src/isaspec.rs @@ -6,8 +6,8 @@ //! If a test case file contains `isa` commands, the tests will only be run against the specified //! ISAs. If the file contains no `isa` commands, the tests will be run against all supported ISAs. -use cretonne::isa::TargetIsa; -use cretonne::settings::{Configurable, Error as SetError, Flags}; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::settings::{Configurable, Error as SetError, Flags}; use error::{Location, Result}; use testcommand::TestOption; diff --git a/lib/reader/src/lexer.rs b/lib/reader/src/lexer.rs index a2fde86b5a..bad7a6369d 100644 --- a/lib/reader/src/lexer.rs +++ b/lib/reader/src/lexer.rs @@ -1,7 +1,7 @@ //! Lexical analysis for .cton files. -use cretonne::ir::types; -use cretonne::ir::{Ebb, Value}; +use cretonne_codegen::ir::types; +use cretonne_codegen::ir::{Ebb, Value}; use error::Location; #[allow(unused_imports)] use std::ascii::AsciiExt; @@ -457,8 +457,8 @@ impl<'a> Lexer<'a> { mod tests { use super::trailing_digits; use super::*; - use cretonne::ir::types; - use cretonne::ir::{Ebb, Value}; + use cretonne_codegen::ir::types; + use cretonne_codegen::ir::{Ebb, Value}; use error::Location; #[test] diff --git a/lib/reader/src/lib.rs b/lib/reader/src/lib.rs index e012876c1c..5a51d4199d 100644 --- a/lib/reader/src/lib.rs +++ b/lib/reader/src/lib.rs @@ -1,11 +1,11 @@ //! Cretonne file reader library. //! -//! The `cton_reader` library supports reading .cton files. This functionality is needed for testing -//! Cretonne, but is not essential for a JIT compiler. +//! The `cretonne_reader` library supports reading .cton files. This functionality is needed for +//! testing Cretonne, but is not essential for a JIT compiler. #![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] -extern crate cretonne; +extern crate cretonne_codegen; pub use error::{Error, Location, Result}; pub use isaspec::{parse_options, IsaSpec}; diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index f23f644a0e..e96e415afc 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -1,18 +1,19 @@ //! Parser for .cton files. -use cretonne::entity::EntityRef; -use cretonne::ir; -use cretonne::ir::entities::AnyEntity; -use cretonne::ir::immediates::{Ieee32, Ieee64, Imm64, Offset32, Uimm32}; -use cretonne::ir::instructions::{InstructionData, InstructionFormat, VariableArgs}; -use cretonne::ir::types::VOID; -use cretonne::ir::{AbiParam, ArgumentExtension, ArgumentLoc, CallConv, Ebb, ExtFuncData, - ExternalName, FuncRef, Function, GlobalVar, GlobalVarData, Heap, HeapBase, - HeapData, HeapStyle, JumpTable, JumpTableData, MemFlags, Opcode, SigRef, - Signature, StackSlot, StackSlotData, StackSlotKind, Type, Value, ValueLoc}; -use cretonne::isa::{self, Encoding, RegUnit, TargetIsa}; -use cretonne::packed_option::ReservedValue; -use cretonne::{settings, timing}; +use cretonne_codegen::entity::EntityRef; +use cretonne_codegen::ir; +use cretonne_codegen::ir::entities::AnyEntity; +use cretonne_codegen::ir::immediates::{Ieee32, Ieee64, Imm64, Offset32, Uimm32}; +use cretonne_codegen::ir::instructions::{InstructionData, InstructionFormat, VariableArgs}; +use cretonne_codegen::ir::types::VOID; +use cretonne_codegen::ir::{AbiParam, ArgumentExtension, ArgumentLoc, CallConv, Ebb, ExtFuncData, + ExternalName, FuncRef, Function, GlobalVar, GlobalVarData, Heap, + HeapBase, HeapData, HeapStyle, JumpTable, JumpTableData, MemFlags, + Opcode, SigRef, Signature, StackSlot, StackSlotData, StackSlotKind, + Type, Value, ValueLoc}; +use cretonne_codegen::isa::{self, Encoding, RegUnit, TargetIsa}; +use cretonne_codegen::packed_option::ReservedValue; +use cretonne_codegen::{settings, timing}; use error::{Error, Location, Result}; use isaspec; use lexer::{self, Lexer, Token}; @@ -144,6 +145,7 @@ impl<'a> Context<'a> { while self.function.global_vars.next_key().index() <= gv.index() { self.function.create_global_var(GlobalVarData::Sym { name: ExternalName::testcase(""), + colocated: false, }); } self.function.global_vars[gv] = data; @@ -208,6 +210,7 @@ impl<'a> Context<'a> { self.function.import_function(ExtFuncData { name: ExternalName::testcase(""), signature: SigRef::reserved_value(), + colocated: false, }); } self.function.dfg.ext_funcs[fn_] = data; @@ -760,7 +763,7 @@ impl<'a> Parser<'a> { // Parse a whole function definition. // - // function ::= * function-spec "{" preamble function-body "}" + // function ::= * "function" name signature "{" preamble function-body "}" // fn parse_function( &mut self, @@ -772,10 +775,19 @@ impl<'a> Parser<'a> { debug_assert!(self.comments.is_empty()); self.start_gathering_comments(); - let (location, name, sig) = self.parse_function_spec(unique_isa)?; + self.match_identifier("function", "expected 'function'")?; + + let location = self.loc; + + // function ::= "function" * name signature "{" preamble function-body "}" + let name = self.parse_external_name()?; + + // function ::= "function" name * signature "{" preamble function-body "}" + let sig = self.parse_signature(unique_isa)?; + let mut ctx = Context::new(Function::with_name_signature(name, sig), unique_isa); - // function ::= function-spec * "{" preamble function-body "}" + // function ::= "function" name signature * "{" preamble function-body "}" self.match_token( Token::LBrace, "expected '{' before function body", @@ -784,11 +796,11 @@ impl<'a> Parser<'a> { self.token(); self.claim_gathered_comments(AnyEntity::Function); - // function ::= function-spec "{" * preamble function-body "}" + // function ::= "function" name signature "{" * preamble function-body "}" self.parse_preamble(&mut ctx)?; - // function ::= function-spec "{" preamble * function-body "}" + // function ::= "function" name signature "{" preamble * function-body "}" self.parse_function_body(&mut ctx)?; - // function ::= function-spec "{" preamble function-body * "}" + // function ::= "function" name signature "{" preamble function-body * "}" self.match_token( Token::RBrace, "expected '}' after function body", @@ -808,29 +820,9 @@ impl<'a> Parser<'a> { Ok((ctx.function, details)) } - // Parse a function spec. - // - // function-spec ::= * "function" name signature - // - fn parse_function_spec( - &mut self, - unique_isa: Option<&TargetIsa>, - ) -> Result<(Location, ExternalName, Signature)> { - self.match_identifier("function", "expected 'function'")?; - let location = self.loc; - - // function-spec ::= "function" * name signature - let name = self.parse_external_name()?; - - // function-spec ::= "function" name * signature - let sig = self.parse_signature(unique_isa)?; - - Ok((location, name, sig)) - } - // Parse an external name. // - // For example, in a function spec, the parser would be in this state: + // For example, in a function decl, the parser would be in this state: // // function ::= "function" * name signature { ... } // @@ -1095,7 +1087,7 @@ impl<'a> Parser<'a> { // global-var-decl ::= * GlobalVar(gv) "=" global-var-desc // global-var-desc ::= "vmctx" offset32 // | "deref" "(" GlobalVar(base) ")" offset32 - // | "globalsym" name + // | globalsym ["colocated"] name // fn parse_global_var_decl(&mut self) -> Result<(GlobalVar, GlobalVarData)> { let gv = self.match_gv("expected global variable number: gv«n»")?; @@ -1108,7 +1100,7 @@ impl<'a> Parser<'a> { let data = match self.match_any_identifier("expected global variable kind")? { "vmctx" => { let offset = self.optional_offset32()?; - GlobalVarData::VmCtx { offset } + GlobalVarData::VMContext { offset } } "deref" => { self.match_token( @@ -1124,8 +1116,9 @@ impl<'a> Parser<'a> { GlobalVarData::Deref { base, offset } } "globalsym" => { + let colocated = self.optional(Token::Identifier("colocated")); let name = self.parse_external_name()?; - GlobalVarData::Sym { name } + GlobalVarData::Sym { name, colocated } } other => return err!(self.loc, "Unknown global variable kind '{}'", other), }; @@ -1237,8 +1230,8 @@ impl<'a> Parser<'a> { // // Two variants: // - // function-decl ::= FuncRef(fnref) "=" function-spec - // FuncRef(fnref) "=" SigRef(sig) name + // function-decl ::= FuncRef(fnref) "=" ["colocated"]" name function-decl-sig + // function-decl-sig ::= SigRef(sig) | signature // // The first variant allocates a new signature reference. The second references an existing // signature which must be declared first. @@ -1250,9 +1243,19 @@ impl<'a> Parser<'a> { "expected '=' in function decl", )?; + let loc = self.loc; + + // function-decl ::= FuncRef(fnref) "=" * ["colocated"] name function-decl-sig + let colocated = self.optional(Token::Identifier("colocated")); + + // function-decl ::= FuncRef(fnref) "=" ["colocated"] * name function-decl-sig + let name = self.parse_external_name()?; + + // function-decl ::= FuncRef(fnref) "=" ["colocated"] name * function-decl-sig let data = match self.token() { - Some(Token::Identifier("function")) => { - let (loc, name, sig) = self.parse_function_spec(ctx.unique_isa)?; + Some(Token::LPar) => { + // function-decl ::= FuncRef(fnref) "=" ["colocated"] name * signature + let sig = self.parse_signature(ctx.unique_isa)?; let sigref = ctx.function.import_signature(sig); ctx.map.def_entity(sigref.into(), &loc).expect( "duplicate SigRef entities created", @@ -1260,6 +1263,7 @@ impl<'a> Parser<'a> { ExtFuncData { name, signature: sigref, + colocated, } } Some(Token::SigRef(sig_src)) => { @@ -1271,10 +1275,10 @@ impl<'a> Parser<'a> { }; ctx.check_sig(sig, &self.loc)?; self.consume(); - let name = self.parse_external_name()?; ExtFuncData { name, signature: sig, + colocated, } } _ => return err!(self.loc, "expected 'function' or sig«n» in function decl"), @@ -2175,7 +2179,7 @@ impl<'a> Parser<'a> { args: args.into_value_list(&[], &mut ctx.function.dfg.value_lists), } } - InstructionFormat::IndirectCall => { + InstructionFormat::CallIndirect => { let sig_ref = self.match_sig("expected signature reference")?; ctx.check_sig(sig_ref, &self.loc)?; self.match_token( @@ -2192,7 +2196,7 @@ impl<'a> Parser<'a> { Token::RPar, "expected ')' after arguments", )?; - InstructionData::IndirectCall { + InstructionData::CallIndirect { opcode, sig_ref, args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists), @@ -2395,10 +2399,10 @@ impl<'a> Parser<'a> { #[cfg(test)] mod tests { use super::*; - use cretonne::ir::StackSlotKind; - use cretonne::ir::entities::AnyEntity; - use cretonne::ir::types; - use cretonne::ir::{ArgumentExtension, ArgumentPurpose, CallConv}; + use cretonne_codegen::ir::StackSlotKind; + use cretonne_codegen::ir::entities::AnyEntity; + use cretonne_codegen::ir::types; + use cretonne_codegen::ir::{ArgumentExtension, ArgumentPurpose, CallConv}; use error::Error; use isaspec::IsaSpec; use testfile::{Comment, Details}; diff --git a/lib/reader/src/sourcemap.rs b/lib/reader/src/sourcemap.rs index b30b172768..a4bc1954c1 100644 --- a/lib/reader/src/sourcemap.rs +++ b/lib/reader/src/sourcemap.rs @@ -6,8 +6,8 @@ //! The `SourceMap` struct defined in this module makes this mapping available //! to parser clients. -use cretonne::ir::entities::AnyEntity; -use cretonne::ir::{Ebb, FuncRef, GlobalVar, Heap, JumpTable, SigRef, StackSlot, Value}; +use cretonne_codegen::ir::entities::AnyEntity; +use cretonne_codegen::ir::{Ebb, FuncRef, GlobalVar, Heap, JumpTable, SigRef, StackSlot, Value}; use error::{Location, Result}; use lexer::split_entity_name; use std::collections::HashMap; diff --git a/lib/reader/src/testfile.rs b/lib/reader/src/testfile.rs index 7218f8cb72..2fae3c2d3d 100644 --- a/lib/reader/src/testfile.rs +++ b/lib/reader/src/testfile.rs @@ -4,8 +4,8 @@ //! file-based test case. //! -use cretonne::ir::Function; -use cretonne::ir::entities::AnyEntity; +use cretonne_codegen::ir::Function; +use cretonne_codegen::ir::entities::AnyEntity; use error::Location; use isaspec::IsaSpec; use sourcemap::SourceMap; diff --git a/lib/simplejit/Cargo.toml b/lib/simplejit/Cargo.toml new file mode 100644 index 0000000000..699212afc0 --- /dev/null +++ b/lib/simplejit/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "cretonne-simplejit" +version = "0.5.0" +authors = ["The Cretonne Project Developers"] +description = "A simple JIT library backed by Cretonne" +repository = "https://github.com/Cretonne/cretonne" +documentation = "https://cretonne.readthedocs.io/" +license = "Apache-2.0" +readme = "README.md" + +[dependencies] +cretonne-codegen = { path = "../codegen", version = "0.5.0" } +cretonne-module = { path = "../module", version = "0.5.0" } +cretonne-native = { path = "../native", version = "0.5.0" } +region = "0.2.0" +libc = "0.2.40" +errno = "0.2.3" + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "Cretonne/cretonne" } diff --git a/lib/simplejit/README.md b/lib/simplejit/README.md new file mode 100644 index 0000000000..8b0aea6d28 --- /dev/null +++ b/lib/simplejit/README.md @@ -0,0 +1,4 @@ +This crate provides a simple JIT library that uses +[Cretonne](https://crates.io/crates/cretonne). + +This crate is extremely experimental. diff --git a/lib/simplejit/src/backend.rs b/lib/simplejit/src/backend.rs new file mode 100644 index 0000000000..497ac1bb15 --- /dev/null +++ b/lib/simplejit/src/backend.rs @@ -0,0 +1,360 @@ +//! Defines `SimpleJITBackend`. + +use cretonne_codegen::binemit::{Addend, CodeOffset, Reloc, RelocSink, NullTrapSink}; +use cretonne_codegen::isa::TargetIsa; +use cretonne_codegen::result::CtonError; +use cretonne_codegen::{self, ir, settings}; +use cretonne_module::{Backend, DataContext, Linkage, ModuleNamespace, Writability, + DataDescription, Init}; +use cretonne_native; +use std::ffi::CString; +use std::ptr; +use libc; +use memory::Memory; + +/// A record of a relocation to perform. +struct RelocRecord { + offset: CodeOffset, + reloc: Reloc, + name: ir::ExternalName, + addend: Addend, +} + +pub struct SimpleJITCompiledFunction { + code: *mut u8, + size: usize, + relocs: Vec, +} + +pub struct SimpleJITCompiledData { + storage: *mut u8, + size: usize, + relocs: Vec, +} + +/// A `SimpleJITBackend` implements `Backend` and emits code and data into memory where it can be +/// directly called and accessed. +pub struct SimpleJITBackend { + isa: Box, + code_memory: Memory, + readonly_memory: Memory, + writable_memory: Memory, +} + +impl SimpleJITBackend { + /// Create a new `SimpleJITBackend`. + pub fn new() -> Self { + let (flag_builder, isa_builder) = cretonne_native::builders().unwrap_or_else(|_| { + panic!("host machine is not a supported target"); + }); + let isa = isa_builder.finish(settings::Flags::new(&flag_builder)); + Self::with_isa(isa) + } + + /// Create a new `SimpleJITBackend` with an arbitrary target. This is mainly + /// useful for testing. + /// + /// SimpleJIT requires a `TargetIsa` configured for non-PIC. + /// + /// To create a `SimpleJITBackend` for native use, use the `new` constructor + /// instead. + pub fn with_isa(isa: Box) -> Self { + debug_assert!(!isa.flags().is_pic(), "SimpleJIT requires non-PIC code"); + Self { + isa, + code_memory: Memory::new(), + readonly_memory: Memory::new(), + writable_memory: Memory::new(), + } + } +} + +impl<'simple_jit_backend> Backend for SimpleJITBackend { + type CompiledFunction = SimpleJITCompiledFunction; + type CompiledData = SimpleJITCompiledData; + + type FinalizedFunction = *const u8; + type FinalizedData = (*mut u8, usize); + + fn isa(&self) -> &TargetIsa { + &*self.isa + } + + fn declare_function(&mut self, _name: &str, _linkage: Linkage) { + // Nothing to do. + } + + fn declare_data(&mut self, _name: &str, _linkage: Linkage, _writable: bool) { + // Nothing to do. + } + + fn define_function( + &mut self, + _name: &str, + ctx: &cretonne_codegen::Context, + _namespace: &ModuleNamespace, + code_size: u32, + ) -> Result { + let size = code_size as usize; + let ptr = self.code_memory.allocate(size).expect( + "TODO: handle OOM etc.", + ); + let mut reloc_sink = SimpleJITRelocSink::new(); + // Ignore traps for now. For now, frontends should just avoid generating code + // that traps. + let mut trap_sink = NullTrapSink {}; + ctx.emit_to_memory(ptr, &mut reloc_sink, &mut trap_sink, &*self.isa); + + Ok(Self::CompiledFunction { + code: ptr, + size, + relocs: reloc_sink.relocs, + }) + } + + fn define_data( + &mut self, + _name: &str, + data: &DataContext, + _namespace: &ModuleNamespace, + ) -> Result { + let &DataDescription { + writable, + ref init, + ref function_decls, + ref data_decls, + ref function_relocs, + ref data_relocs, + } = data.description(); + + let size = init.size(); + let storage = match writable { + Writability::Readonly => { + self.writable_memory.allocate(size).expect( + "TODO: handle OOM etc.", + ) + } + Writability::Writable => { + self.writable_memory.allocate(size).expect( + "TODO: handle OOM etc.", + ) + } + }; + + match *init { + Init::Uninitialized => { + panic!("data is not initialized yet"); + } + Init::Zeros { .. } => { + unsafe { ptr::write_bytes(storage, 0, size) }; + } + Init::Bytes { ref contents } => { + let src = contents.as_ptr(); + unsafe { ptr::copy_nonoverlapping(src, storage, size) }; + } + } + + let reloc = if self.isa.flags().is_64bit() { + Reloc::Abs8 + } else { + Reloc::Abs4 + }; + let mut relocs = Vec::new(); + for &(offset, id) in function_relocs { + relocs.push(RelocRecord { + reloc, + offset, + name: function_decls[id].clone(), + addend: 0, + }); + } + for &(offset, id, addend) in data_relocs { + relocs.push(RelocRecord { + reloc, + offset, + name: data_decls[id].clone(), + addend, + }); + } + + Ok(Self::CompiledData { + storage, + size, + relocs, + }) + } + + fn write_data_funcaddr( + &mut self, + _data: &mut Self::CompiledData, + _offset: usize, + _what: ir::FuncRef, + ) { + unimplemented!(); + } + + fn write_data_dataaddr( + &mut self, + _data: &mut Self::CompiledData, + _offset: usize, + _what: ir::GlobalVar, + _usize: Addend, + ) { + unimplemented!(); + } + + fn finalize_function( + &mut self, + func: &Self::CompiledFunction, + namespace: &ModuleNamespace, + ) -> Self::FinalizedFunction { + use std::ptr::write_unaligned; + + for &RelocRecord { + reloc, + offset, + ref name, + addend, + } in &func.relocs + { + let ptr = func.code; + debug_assert!((offset as usize) < func.size); + let at = unsafe { ptr.offset(offset as isize) }; + let base = if namespace.is_function(name) { + let (def, name_str, _signature) = namespace.get_function_definition(&name); + match def { + Some(compiled) => compiled.code, + None => lookup_with_dlsym(name_str), + } + } else { + let (def, name_str, _writable) = namespace.get_data_definition(&name); + match def { + Some(compiled) => compiled.storage, + None => lookup_with_dlsym(name_str), + } + }; + // TODO: Handle overflow. + let what = unsafe { base.offset(addend as isize) }; + match reloc { + Reloc::Abs4 => { + // TODO: Handle overflow. + unsafe { write_unaligned(at as *mut u32, what as u32) }; + } + Reloc::Abs8 => { + unsafe { write_unaligned(at as *mut u64, what as u64) }; + } + Reloc::X86PCRel4 => { + // TODO: Handle overflow. + let pcrel = ((what as isize) - (at as isize)) as i32; + unsafe { write_unaligned(at as *mut i32, pcrel) }; + } + Reloc::X86GOTPCRel4 | + Reloc::X86PLTRel4 => panic!("unexpected PIC relocation"), + _ => unimplemented!(), + } + } + + // Now that we're done patching, make the memory executable. + self.code_memory.set_executable(); + func.code + } + + fn finalize_data( + &mut self, + data: &Self::CompiledData, + namespace: &ModuleNamespace, + ) -> Self::FinalizedData { + use std::ptr::write_unaligned; + + for record in &data.relocs { + match *record { + RelocRecord { + reloc, + offset, + ref name, + addend, + } => { + let ptr = data.storage; + debug_assert!((offset as usize) < data.size); + let at = unsafe { ptr.offset(offset as isize) }; + let base = if namespace.is_function(name) { + let (def, name_str, _signature) = namespace.get_function_definition(&name); + match def { + Some(compiled) => compiled.code, + None => lookup_with_dlsym(name_str), + } + } else { + let (def, name_str, _writable) = namespace.get_data_definition(&name); + match def { + Some(compiled) => compiled.storage, + None => lookup_with_dlsym(name_str), + } + }; + // TODO: Handle overflow. + let what = unsafe { base.offset(addend as isize) }; + match reloc { + Reloc::Abs4 => { + // TODO: Handle overflow. + unsafe { write_unaligned(at as *mut u32, what as u32) }; + } + Reloc::Abs8 => { + unsafe { write_unaligned(at as *mut u64, what as u64) }; + } + Reloc::X86PCRel4 | + Reloc::X86GOTPCRel4 | + Reloc::X86PLTRel4 => panic!("unexpected text relocation in data"), + _ => unimplemented!(), + } + } + } + } + + self.readonly_memory.set_readonly(); + (data.storage, data.size) + } +} + +fn lookup_with_dlsym(name: &str) -> *const u8 { + let c_str = CString::new(name).unwrap(); + let c_str_ptr = c_str.as_ptr(); + let sym = unsafe { libc::dlsym(libc::RTLD_DEFAULT, c_str_ptr) }; + if sym.is_null() { + panic!("can't resolve symbol {}", name); + } + sym as *const u8 +} + +struct SimpleJITRelocSink { + pub relocs: Vec, +} + +impl SimpleJITRelocSink { + pub fn new() -> Self { + Self { relocs: Vec::new() } + } +} + +impl RelocSink for SimpleJITRelocSink { + fn reloc_ebb(&mut self, _offset: CodeOffset, _reloc: Reloc, _ebb_offset: CodeOffset) { + unimplemented!(); + } + + fn reloc_external( + &mut self, + offset: CodeOffset, + reloc: Reloc, + name: &ir::ExternalName, + addend: Addend, + ) { + self.relocs.push(RelocRecord { + offset, + reloc, + name: name.clone(), + addend, + }); + } + + fn reloc_jt(&mut self, _offset: CodeOffset, _reloc: Reloc, _jt: ir::JumpTable) { + unimplemented!(); + } +} diff --git a/lib/simplejit/src/lib.rs b/lib/simplejit/src/lib.rs new file mode 100644 index 0000000000..0157466cac --- /dev/null +++ b/lib/simplejit/src/lib.rs @@ -0,0 +1,15 @@ +//! Top-level lib.rs for `cretonne_simplejit`. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] + +extern crate cretonne_codegen; +extern crate cretonne_module; +extern crate cretonne_native; +extern crate errno; +extern crate region; +extern crate libc; + +mod backend; +mod memory; + +pub use backend::SimpleJITBackend; diff --git a/lib/simplejit/src/memory.rs b/lib/simplejit/src/memory.rs new file mode 100644 index 0000000000..235a3976d7 --- /dev/null +++ b/lib/simplejit/src/memory.rs @@ -0,0 +1,108 @@ +use std::mem; +use std::ptr; +use errno; +use libc; +use region; + +struct PtrLen { + ptr: *mut u8, + len: usize, +} + +impl PtrLen { + fn new() -> Self { + Self { + ptr: ptr::null_mut(), + len: 0, + } + } + + fn with_size(size: usize) -> Result { + let page_size = region::page::size(); + let alloc_size = (size + (page_size - 1)) & (page_size - 1); + unsafe { + let mut ptr: *mut libc::c_void = mem::uninitialized(); + let err = libc::posix_memalign(&mut ptr, page_size, alloc_size); + if err == 0 { + Ok(Self { + ptr: mem::transmute(ptr), + len: alloc_size, + }) + } else { + Err(errno::Errno(err).to_string()) + } + } + } +} + +pub struct Memory { + allocations: Vec, + executable: usize, + current: PtrLen, + position: usize, +} + +impl Memory { + pub fn new() -> Self { + Self { + allocations: Vec::new(), + executable: 0, + current: PtrLen::new(), + position: 0, + } + } + + fn finish_current(&mut self) { + self.allocations.push(mem::replace( + &mut self.current, + PtrLen::new(), + )); + self.position = 0; + } + + /// TODO: Use a proper error type. + pub fn allocate(&mut self, size: usize) -> Result<*mut u8, String> { + if size <= self.current.len - self.position { + // TODO: Ensure overflow is not possible. + let ptr = unsafe { self.current.ptr.offset(self.position as isize) }; + self.position += size; + return Ok(ptr); + } + + self.finish_current(); + + // TODO: Allocate more at a time. + self.current = PtrLen::with_size(size)?; + self.position = size; + Ok(self.current.ptr) + } + + pub fn set_executable(&mut self) { + self.finish_current(); + + for &PtrLen { ptr, len } in &self.allocations[self.executable..] { + if len != 0 { + unsafe { + region::protect(ptr, len, region::Protection::Execute) + .expect("unable to make memory executable"); + } + } + } + } + + pub fn set_readonly(&mut self) { + self.finish_current(); + + for &PtrLen { ptr, len } in &self.allocations[self.executable..] { + if len != 0 { + unsafe { + region::protect(ptr, len, region::Protection::Read).expect( + "unable to make memory readonly", + ); + } + } + } + } +} + +// TODO: Implement Drop to unprotect and deallocate the memory? diff --git a/lib/umbrella/Cargo.toml b/lib/umbrella/Cargo.toml new file mode 100644 index 0000000000..fc89536394 --- /dev/null +++ b/lib/umbrella/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Cretonne Project Developers"] +name = "cretonne" +version = "0.5.0" +description = "Umbrella for commonly-used cretonne crates" +license = "Apache-2.0" +documentation = "https://cretonne.readthedocs.io/" +repository = "https://github.com/cretonne/cretonne" +readme = "README.md" +keywords = ["compile", "compiler", "jit"] + +[dependencies] +cretonne-codegen = { path = "../codegen", version = "0.5.0" } +cretonne-frontend = { path = "../frontend", version = "0.5.0" } + +[badges] +maintenance = { status = "experimental" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/umbrella/README.md b/lib/umbrella/README.md new file mode 100644 index 0000000000..f9c2ee3fbf --- /dev/null +++ b/lib/umbrella/README.md @@ -0,0 +1,3 @@ +This is an umbrella crate which contains no code of its own, but pulls in +other cretonne library crates to provide a convenient one-line dependency +for common use cases. diff --git a/lib/umbrella/src/lib.rs b/lib/umbrella/src/lib.rs new file mode 100644 index 0000000000..a70a97e86f --- /dev/null +++ b/lib/umbrella/src/lib.rs @@ -0,0 +1,19 @@ +//! Cretonne umbrella crate, providing a convenient one-line dependency. + +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../../clippy.toml")))] + +pub extern crate cretonne_codegen; +pub extern crate cretonne_frontend; + +/// A prelude providing convenient access to commonly-used cretonne features. Use +/// as `use cretonne::prelude::*`. +pub mod prelude { + pub use cretonne_codegen; + pub use cretonne_codegen::entity::EntityRef; + pub use cretonne_codegen::ir::{AbiParam, InstBuilder, Value, Ebb, Signature, CallConv}; + pub use cretonne_codegen::ir::types; + pub use cretonne_codegen::ir::condcodes::IntCC; + + pub use cretonne_frontend::{FunctionBuilderContext, FunctionBuilder, Variable}; +} diff --git a/lib/wasm/Cargo.toml b/lib/wasm/Cargo.toml index 4af0ab68ef..dd053698f0 100644 --- a/lib/wasm/Cargo.toml +++ b/lib/wasm/Cargo.toml @@ -1,20 +1,17 @@ [package] name = "cretonne-wasm" -version = "0.4.1" +version = "0.5.0" authors = ["The Cretonne Project Developers"] description = "Translator from WebAssembly to Cretonne IR" -repository = "https://github.com/Cretonne/cretonne" +repository = "https://github.com/cretonne/cretonne" license = "Apache-2.0" readme = "README.md" keywords = ["webassembly", "wasm"] -[lib] -name = "cton_wasm" - [dependencies] wasmparser = "0.15.1" -cretonne = { path = "../cretonne", version = "0.4.1", default_features = false } -cretonne-frontend = { path = "../frontend", version = "0.4.1", default_features = false } +cretonne-codegen = { path = "../codegen", version = "0.5.0", default_features = false } +cretonne-frontend = { path = "../frontend", version = "0.5.0", default_features = false } [dependencies.hashmap_core] version = "0.1.1" @@ -25,9 +22,9 @@ tempdir = "0.3.5" [features] default = ["std"] -std = ["cretonne/std", "cretonne-frontend/std"] -core = ["hashmap_core", "cretonne/core", "cretonne-frontend/core"] +std = ["cretonne-codegen/std", "cretonne-frontend/std"] +core = ["hashmap_core", "cretonne-codegen/core", "cretonne-frontend/core"] [badges] maintenance = { status = "experimental" } -travis-ci = { repository = "Cretonne/cretonne" } +travis-ci = { repository = "cretonne/cretonne" } diff --git a/lib/wasm/src/code_translator.rs b/lib/wasm/src/code_translator.rs index 9dbace8556..2b48cd50c0 100644 --- a/lib/wasm/src/code_translator.rs +++ b/lib/wasm/src/code_translator.rs @@ -22,11 +22,11 @@ //! //! That is why `translate_function_body` takes an object having the `WasmRuntime` trait as //! argument. -use cretonne::ir::condcodes::{FloatCC, IntCC}; -use cretonne::ir::types::*; -use cretonne::ir::{self, InstBuilder, JumpTableData, MemFlags}; -use cretonne::packed_option::ReservedValue; -use cton_frontend::{FunctionBuilder, Variable}; +use cretonne_codegen::ir::condcodes::{FloatCC, IntCC}; +use cretonne_codegen::ir::types::*; +use cretonne_codegen::ir::{self, InstBuilder, JumpTableData, MemFlags}; +use cretonne_codegen::packed_option::ReservedValue; +use cretonne_frontend::{FunctionBuilder, Variable}; use environ::{FuncEnvironment, GlobalValue}; use state::{ControlStackFrame, TranslationState}; use std::collections::{hash_map, HashMap}; diff --git a/lib/wasm/src/environ/dummy.rs b/lib/wasm/src/environ/dummy.rs index 49386fe2bb..3676ea23da 100644 --- a/lib/wasm/src/environ/dummy.rs +++ b/lib/wasm/src/environ/dummy.rs @@ -1,9 +1,9 @@ //! "Dummy" environment for testing wasm translation. -use cretonne::cursor::FuncCursor; -use cretonne::ir::types::*; -use cretonne::ir::{self, InstBuilder}; -use cretonne::settings; +use cretonne_codegen::cursor::FuncCursor; +use cretonne_codegen::ir::types::*; +use cretonne_codegen::ir::{self, InstBuilder}; +use cretonne_codegen::settings; use environ::{FuncEnvironment, GlobalValue, ModuleEnvironment}; use func_translator::FuncTranslator; use std::string::String; @@ -150,7 +150,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ fn make_global(&mut self, func: &mut ir::Function, index: GlobalIndex) -> GlobalValue { // Just create a dummy `vmctx` global. let offset = ((index * 8) as i32 + 8).into(); - let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset }); + let gv = func.create_global_var(ir::GlobalVarData::VMContext { offset }); GlobalValue::Memory { gv, ty: self.mod_info.globals[index].entity.ty, @@ -159,7 +159,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ fn make_heap(&mut self, func: &mut ir::Function, _index: MemoryIndex) -> ir::Heap { // Create a static heap whose base address is stored at `vmctx+0`. - let gv = func.create_global_var(ir::GlobalVarData::VmCtx { offset: 0.into() }); + let gv = func.create_global_var(ir::GlobalVarData::VMContext { offset: 0.into() }); func.create_heap(ir::HeapData { base: ir::HeapBase::GlobalVar(gv), @@ -181,7 +181,11 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ // And maybe attempt some signature de-duplication. let signature = func.import_signature(self.vmctx_sig(sigidx)); let name = get_func_name(index); - func.import_function(ir::ExtFuncData { name, signature }) + func.import_function(ir::ExtFuncData { + name, + signature, + colocated: false, + }) } fn translate_call_indirect( @@ -221,7 +225,7 @@ impl<'dummy_environment> FuncEnvironment for DummyFuncEnvironment<'dummy_environ args.push(vmctx, &mut pos.func.dfg.value_lists); pos.ins() - .IndirectCall(ir::Opcode::CallIndirect, ir::types::VOID, sig_ref, args) + .CallIndirect(ir::Opcode::CallIndirect, ir::types::VOID, sig_ref, args) .0 } diff --git a/lib/wasm/src/environ/spec.rs b/lib/wasm/src/environ/spec.rs index 8c313f0ef3..51aba3fd7e 100644 --- a/lib/wasm/src/environ/spec.rs +++ b/lib/wasm/src/environ/spec.rs @@ -1,8 +1,8 @@ //! All the runtime support necessary for the wasm to cretonne translation is formalized by the //! traits `FunctionEnvironment` and `ModuleEnvironment`. -use cretonne::cursor::FuncCursor; -use cretonne::ir::{self, InstBuilder}; -use cretonne::settings::Flags; +use cretonne_codegen::cursor::FuncCursor; +use cretonne_codegen::ir::{self, InstBuilder}; +use cretonne_codegen::settings::Flags; use std::string::String; use std::vec::Vec; use translation_utils::{FunctionIndex, Global, GlobalIndex, Memory, MemoryIndex, SignatureIndex, diff --git a/lib/wasm/src/func_translator.rs b/lib/wasm/src/func_translator.rs index c89fa21266..4801cccf11 100644 --- a/lib/wasm/src/func_translator.rs +++ b/lib/wasm/src/func_translator.rs @@ -5,11 +5,11 @@ //! WebAssembly module and the runtime environment. use code_translator::translate_operator; -use cretonne::entity::EntityRef; -use cretonne::ir::{self, Ebb, InstBuilder}; -use cretonne::result::{CtonError, CtonResult}; -use cretonne::timing; -use cton_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; +use cretonne_codegen::entity::EntityRef; +use cretonne_codegen::ir::{self, Ebb, InstBuilder}; +use cretonne_codegen::result::{CtonError, CtonResult}; +use cretonne_codegen::timing; +use cretonne_frontend::{FunctionBuilder, FunctionBuilderContext, Variable}; use environ::FuncEnvironment; use state::TranslationState; use wasmparser::{self, BinaryReader}; @@ -233,8 +233,8 @@ fn cur_srcloc(reader: &BinaryReader) -> ir::SourceLoc { #[cfg(test)] mod tests { use super::FuncTranslator; - use cretonne::ir::types::I32; - use cretonne::{ir, Context}; + use cretonne_codegen::ir::types::I32; + use cretonne_codegen::{ir, Context}; use environ::{DummyEnvironment, FuncEnvironment}; #[test] diff --git a/lib/wasm/src/lib.rs b/lib/wasm/src/lib.rs index d89072b5e4..f63eb26e14 100644 --- a/lib/wasm/src/lib.rs +++ b/lib/wasm/src/lib.rs @@ -25,8 +25,8 @@ extern crate alloc; extern crate hashmap_core; #[macro_use(dbg)] -extern crate cretonne; -extern crate cton_frontend; +extern crate cretonne_codegen; +extern crate cretonne_frontend; extern crate wasmparser; mod code_translator; diff --git a/lib/wasm/src/module_translator.rs b/lib/wasm/src/module_translator.rs index e41712a6d6..f1092651d6 100644 --- a/lib/wasm/src/module_translator.rs +++ b/lib/wasm/src/module_translator.rs @@ -1,6 +1,6 @@ //! Translation skeleton that traverses the whole WebAssembly module and call helper functions //! to deal with each part of it. -use cretonne::timing; +use cretonne_codegen::timing; use environ::ModuleEnvironment; use sections_translator::{parse_data_section, parse_elements_section, parse_export_section, parse_function_section, parse_function_signatures, parse_global_section, @@ -11,7 +11,7 @@ use wasmparser::{BinaryReaderError, Parser, ParserInput, ParserState, SectionCod use std::string::String; /// Translate a sequence of bytes forming a valid Wasm binary into a list of valid Cretonne IR -/// [`Function`](../cretonne/ir/function/struct.Function.html). +/// [`Function`](../codegen/ir/function/struct.Function.html). /// Returns the functions and also the mappings for imported functions and signature between the /// indexes in the wasm module and the indexes inside each functions. pub fn translate_module<'data>( diff --git a/lib/wasm/src/sections_translator.rs b/lib/wasm/src/sections_translator.rs index ce5ed05995..b744c505e4 100644 --- a/lib/wasm/src/sections_translator.rs +++ b/lib/wasm/src/sections_translator.rs @@ -7,8 +7,7 @@ //! The special case of the initialize expressions for table elements offsets or global variables //! is handled, according to the semantics of WebAssembly, to only specific expressions that are //! interpreted on the fly. -use cretonne; -use cretonne::ir::{AbiParam, CallConv, Signature}; +use cretonne_codegen::ir::{self, AbiParam, CallConv, Signature}; use environ::ModuleEnvironment; use std::str::from_utf8; use std::string::String; @@ -38,13 +37,13 @@ pub fn parse_function_signatures( }) => { let mut sig = Signature::new(CallConv::SystemV); sig.params.extend(params.iter().map(|ty| { - let cret_arg: cretonne::ir::Type = type_to_type(ty).expect( + let cret_arg: ir::Type = type_to_type(ty).expect( "only numeric types are supported in function signatures", ); AbiParam::new(cret_arg) })); sig.returns.extend(returns.iter().map(|ty| { - let cret_arg: cretonne::ir::Type = type_to_type(ty).expect( + let cret_arg: ir::Type = type_to_type(ty).expect( "only numeric types are supported in function signatures", ); AbiParam::new(cret_arg) diff --git a/lib/wasm/src/state.rs b/lib/wasm/src/state.rs index f95619d52b..c322906c95 100644 --- a/lib/wasm/src/state.rs +++ b/lib/wasm/src/state.rs @@ -3,7 +3,7 @@ //! The `TranslationState` struct defined in this module is used to keep track of the WebAssembly //! value and control stacks during the translation of a single function. -use cretonne::ir::{self, Ebb, Inst, Value}; +use cretonne_codegen::ir::{self, Ebb, Inst, Value}; use environ::{FuncEnvironment, GlobalValue}; use std::collections::HashMap; use std::vec::Vec; diff --git a/lib/wasm/src/translation_utils.rs b/lib/wasm/src/translation_utils.rs index bac50be7a6..0089c5a75d 100644 --- a/lib/wasm/src/translation_utils.rs +++ b/lib/wasm/src/translation_utils.rs @@ -1,5 +1,5 @@ //! Helper functions and structures for the translation. -use cretonne; +use cretonne_codegen::ir; use std::u32; use wasmparser; @@ -18,7 +18,7 @@ pub type SignatureIndex = usize; #[derive(Debug, Clone, Copy)] pub struct Global { /// The type of the value stored in the global. - pub ty: cretonne::ir::Type, + pub ty: ir::Type, /// A flag indicating whether the value may change at runtime. pub mutability: bool, /// The source of the initial value. @@ -56,7 +56,7 @@ pub struct Table { /// WebAssembly table element. Can be a function or a scalar type. #[derive(Debug, Clone, Copy)] pub enum TableElementType { - Val(cretonne::ir::Type), + Val(ir::Type), Func(), } @@ -72,24 +72,24 @@ pub struct Memory { } /// Helper function translating wasmparser types to Cretonne types when possible. -pub fn type_to_type(ty: &wasmparser::Type) -> Result { +pub fn type_to_type(ty: &wasmparser::Type) -> Result { match *ty { - wasmparser::Type::I32 => Ok(cretonne::ir::types::I32), - wasmparser::Type::I64 => Ok(cretonne::ir::types::I64), - wasmparser::Type::F32 => Ok(cretonne::ir::types::F32), - wasmparser::Type::F64 => Ok(cretonne::ir::types::F64), + wasmparser::Type::I32 => Ok(ir::types::I32), + wasmparser::Type::I64 => Ok(ir::types::I64), + wasmparser::Type::F32 => Ok(ir::types::F32), + wasmparser::Type::F64 => Ok(ir::types::F64), _ => Err(()), } } /// Turns a `wasmparser` `f32` into a `Cretonne` one. -pub fn f32_translation(x: wasmparser::Ieee32) -> cretonne::ir::immediates::Ieee32 { - cretonne::ir::immediates::Ieee32::with_bits(x.bits()) +pub fn f32_translation(x: wasmparser::Ieee32) -> ir::immediates::Ieee32 { + ir::immediates::Ieee32::with_bits(x.bits()) } /// Turns a `wasmparser` `f64` into a `Cretonne` one. -pub fn f64_translation(x: wasmparser::Ieee64) -> cretonne::ir::immediates::Ieee64 { - cretonne::ir::immediates::Ieee64::with_bits(x.bits()) +pub fn f64_translation(x: wasmparser::Ieee64) -> ir::immediates::Ieee64 { + ir::immediates::Ieee64::with_bits(x.bits()) } /// Translate a `wasmparser` type into its `Cretonne` equivalent, when possible diff --git a/lib/wasm/tests/wasm_testsuite.rs b/lib/wasm/tests/wasm_testsuite.rs index 273818f470..15feea4b55 100644 --- a/lib/wasm/tests/wasm_testsuite.rs +++ b/lib/wasm/tests/wasm_testsuite.rs @@ -1,11 +1,11 @@ -extern crate cretonne; -extern crate cton_wasm; +extern crate cretonne_codegen; +extern crate cretonne_wasm; extern crate tempdir; -use cretonne::print_errors::pretty_verifier_error; -use cretonne::settings::{self, Configurable, Flags}; -use cretonne::verifier; -use cton_wasm::{translate_module, DummyEnvironment}; +use cretonne_codegen::print_errors::pretty_verifier_error; +use cretonne_codegen::settings::{self, Configurable, Flags}; +use cretonne_codegen::verifier; +use cretonne_wasm::{translate_module, DummyEnvironment}; use std::error::Error; use std::fs; use std::fs::File;