Merge branch 'master' into no_std
This commit is contained in:
@@ -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" }
|
||||
@@ -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",
|
||||
}
|
||||
@@ -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.
|
||||
@@ -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)
|
||||
@@ -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')
|
||||
35
lib/codegen/meta/base/predicates.py
Normal file
35
lib/codegen/meta/base/predicates.py
Normal file
@@ -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',))
|
||||
@@ -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.
|
||||
""")
|
||||
|
||||
#
|
||||
@@ -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
|
||||
@@ -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())
|
||||
@@ -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.
|
||||
|
||||
@@ -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(
|
||||
@@ -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')
|
||||
@@ -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.
|
||||
@@ -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]
|
||||
@@ -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,
|
||||
21
lib/codegen/meta/isa/x86/__init__.py
Normal file
21
lib/codegen/meta/isa/x86/__init__.py
Normal file
@@ -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()
|
||||
@@ -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)
|
||||
@@ -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))
|
||||
@@ -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
|
||||
@@ -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)),
|
||||
@@ -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);
|
||||
@@ -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
|
||||
@@ -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(
|
||||
@@ -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) {}
|
||||
}
|
||||
@@ -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"),
|
||||
}
|
||||
}
|
||||
@@ -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) {
|
||||
@@ -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<K: Copy + Eq, T: Table<K> + ?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() {
|
||||
@@ -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,
|
||||
) {
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user