moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
moved crates in lib/ to src/, renamed crates, modified some files' text (#660)
This commit is contained in:
1
cranelift/codegen/meta-python/base/__init__.py
Normal file
1
cranelift/codegen/meta-python/base/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
"""Definitions for the base Cranelift language."""
|
||||
38
cranelift/codegen/meta-python/base/entities.py
Normal file
38
cranelift/codegen/meta-python/base/entities.py
Normal file
@@ -0,0 +1,38 @@
|
||||
"""
|
||||
The `cranelift.entities` module predefines all the Cranelift entity reference
|
||||
operand types. There are corresponding definitions in the `cranelift.entities`
|
||||
Rust module.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.operands import EntityRefKind
|
||||
|
||||
|
||||
#: A reference to an extended basic block in the same function.
|
||||
#: This is primarliy used in control flow instructions.
|
||||
ebb = EntityRefKind(
|
||||
'ebb', 'An extended basic block in the same function.',
|
||||
default_member='destination')
|
||||
|
||||
#: A reference to a stack slot declared in the function preamble.
|
||||
stack_slot = EntityRefKind('stack_slot', 'A stack slot.')
|
||||
|
||||
#: A reference to a global value.
|
||||
global_value = EntityRefKind('global_value', 'A global value.')
|
||||
|
||||
#: A reference to a function sugnature declared in the function preamble.
|
||||
#: 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.
|
||||
#: This is used to provide the callee and signature in a call instruction.
|
||||
func_ref = EntityRefKind('func_ref', 'An external function.')
|
||||
|
||||
#: A reference to a jump table declared in the function preamble.
|
||||
jump_table = EntityRefKind(
|
||||
'jump_table', 'A jump table.', default_member='table')
|
||||
|
||||
#: A reference to a heap declared in the function preamble.
|
||||
heap = EntityRefKind('heap', 'A heap.')
|
||||
|
||||
#: A reference to a table declared in the function preamble.
|
||||
table = EntityRefKind('table', 'A table.')
|
||||
89
cranelift/codegen/meta-python/base/formats.py
Normal file
89
cranelift/codegen/meta-python/base/formats.py
Normal file
@@ -0,0 +1,89 @@
|
||||
"""
|
||||
The cranelift.formats defines all instruction formats.
|
||||
|
||||
Every instruction format has a corresponding `InstructionData` variant in the
|
||||
Rust representation of Cranelift IR, so all instruction formats must be defined
|
||||
in this module.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.formats import InstructionFormat
|
||||
from cdsl.operands import VALUE, VARIABLE_ARGS
|
||||
from .immediates import imm64, uimm8, uimm32, ieee32, ieee64, offset32
|
||||
from .immediates import boolean, intcc, floatcc, memflags, regunit, trapcode
|
||||
from . import entities
|
||||
from .entities import ebb, sig_ref, func_ref, stack_slot, heap, table
|
||||
|
||||
Unary = InstructionFormat(VALUE)
|
||||
UnaryImm = InstructionFormat(imm64)
|
||||
UnaryIeee32 = InstructionFormat(ieee32)
|
||||
UnaryIeee64 = InstructionFormat(ieee64)
|
||||
UnaryBool = InstructionFormat(boolean)
|
||||
UnaryGlobalValue = InstructionFormat(entities.global_value)
|
||||
|
||||
Binary = InstructionFormat(VALUE, VALUE)
|
||||
BinaryImm = InstructionFormat(VALUE, imm64)
|
||||
|
||||
# The select instructions are controlled by the second VALUE operand.
|
||||
# The first VALUE operand is the controlling flag which has a derived type.
|
||||
# The fma instruction has the same constraint on all inputs.
|
||||
Ternary = InstructionFormat(VALUE, VALUE, VALUE, typevar_operand=1)
|
||||
|
||||
# Catch-all for instructions with many outputs and inputs and no immediate
|
||||
# operands.
|
||||
MultiAry = InstructionFormat(VARIABLE_ARGS)
|
||||
|
||||
NullAry = InstructionFormat()
|
||||
|
||||
InsertLane = InstructionFormat(VALUE, ('lane', uimm8), VALUE)
|
||||
ExtractLane = InstructionFormat(VALUE, ('lane', uimm8))
|
||||
|
||||
IntCompare = InstructionFormat(intcc, VALUE, VALUE)
|
||||
IntCompareImm = InstructionFormat(intcc, VALUE, imm64)
|
||||
IntCond = InstructionFormat(intcc, VALUE)
|
||||
FloatCompare = InstructionFormat(floatcc, VALUE, VALUE)
|
||||
FloatCond = InstructionFormat(floatcc, VALUE)
|
||||
|
||||
IntSelect = InstructionFormat(intcc, VALUE, VALUE, VALUE)
|
||||
|
||||
Jump = InstructionFormat(ebb, VARIABLE_ARGS)
|
||||
Branch = InstructionFormat(VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchInt = InstructionFormat(intcc, VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchFloat = InstructionFormat(floatcc, VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchIcmp = InstructionFormat(intcc, VALUE, VALUE, ebb, VARIABLE_ARGS)
|
||||
BranchTable = InstructionFormat(VALUE, ebb, entities.jump_table)
|
||||
BranchTableEntry = InstructionFormat(VALUE, VALUE, uimm8, entities.jump_table)
|
||||
BranchTableBase = InstructionFormat(entities.jump_table)
|
||||
IndirectJump = InstructionFormat(VALUE, entities.jump_table)
|
||||
|
||||
Call = InstructionFormat(func_ref, VARIABLE_ARGS)
|
||||
CallIndirect = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
|
||||
FuncAddr = InstructionFormat(func_ref)
|
||||
|
||||
Load = InstructionFormat(memflags, VALUE, offset32)
|
||||
LoadComplex = InstructionFormat(memflags, VARIABLE_ARGS, offset32)
|
||||
Store = InstructionFormat(memflags, VALUE, VALUE, offset32)
|
||||
StoreComplex = InstructionFormat(memflags, VALUE, VARIABLE_ARGS, offset32)
|
||||
|
||||
StackLoad = InstructionFormat(stack_slot, offset32)
|
||||
StackStore = InstructionFormat(VALUE, stack_slot, offset32)
|
||||
|
||||
# Accessing a WebAssembly heap.
|
||||
HeapAddr = InstructionFormat(heap, VALUE, uimm32)
|
||||
|
||||
# Accessing a WebAssembly table.
|
||||
TableAddr = InstructionFormat(table, VALUE, offset32)
|
||||
|
||||
RegMove = InstructionFormat(VALUE, ('src', regunit), ('dst', regunit))
|
||||
CopySpecial = InstructionFormat(('src', regunit), ('dst', regunit))
|
||||
RegSpill = InstructionFormat(
|
||||
VALUE, ('src', regunit), ('dst', entities.stack_slot))
|
||||
RegFill = InstructionFormat(
|
||||
VALUE, ('src', entities.stack_slot), ('dst', regunit))
|
||||
|
||||
Trap = InstructionFormat(trapcode)
|
||||
CondTrap = InstructionFormat(VALUE, trapcode)
|
||||
IntCondTrap = InstructionFormat(intcc, VALUE, trapcode)
|
||||
FloatCondTrap = InstructionFormat(floatcc, VALUE, trapcode)
|
||||
|
||||
# Finally extract the names of global values in this module.
|
||||
InstructionFormat.extract_names(globals())
|
||||
123
cranelift/codegen/meta-python/base/immediates.py
Normal file
123
cranelift/codegen/meta-python/base/immediates.py
Normal file
@@ -0,0 +1,123 @@
|
||||
"""
|
||||
The `cranelift.immediates` module predefines all the Cranelift immediate
|
||||
operand types.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.operands import ImmediateKind
|
||||
|
||||
#: A 64-bit immediate integer operand.
|
||||
#:
|
||||
#: This type of immediate integer can interact with SSA values with any
|
||||
#: :py:class:`cranelift.IntType` type.
|
||||
imm64 = ImmediateKind('imm64', 'A 64-bit immediate integer.')
|
||||
|
||||
#: An unsigned 8-bit immediate integer operand.
|
||||
#:
|
||||
#: This small operand is used to indicate lane indexes in SIMD vectors and
|
||||
#: immediate bit counts on shift instructions.
|
||||
uimm8 = ImmediateKind('uimm8', 'An 8-bit immediate unsigned integer.')
|
||||
|
||||
#: An unsigned 32-bit immediate integer operand.
|
||||
uimm32 = ImmediateKind('uimm32', 'A 32-bit immediate unsigned integer.')
|
||||
|
||||
#: A 32-bit immediate signed offset.
|
||||
#:
|
||||
#: This is used to represent an immediate address offset in load/store
|
||||
#: instructions.
|
||||
offset32 = ImmediateKind(
|
||||
'offset32',
|
||||
'A 32-bit immediate signed offset.',
|
||||
default_member='offset')
|
||||
|
||||
#: A 32-bit immediate floating point operand.
|
||||
#:
|
||||
#: IEEE 754-2008 binary32 interchange format.
|
||||
ieee32 = ImmediateKind('ieee32', 'A 32-bit immediate floating point number.')
|
||||
|
||||
#: A 64-bit immediate floating point operand.
|
||||
#:
|
||||
#: IEEE 754-2008 binary64 interchange format.
|
||||
ieee64 = ImmediateKind('ieee64', 'A 64-bit immediate floating point number.')
|
||||
|
||||
#: An immediate boolean operand.
|
||||
#:
|
||||
#: This type of immediate boolean can interact with SSA values with any
|
||||
#: :py:class:`cranelift.BoolType` type.
|
||||
boolean = ImmediateKind('bool', 'An immediate boolean.',
|
||||
rust_type='bool')
|
||||
|
||||
#: A condition code for comparing integer values.
|
||||
#:
|
||||
#: This enumerated operand kind is used for the :clif:inst:`icmp` instruction
|
||||
#: and corresponds to the `condcodes::IntCC` Rust type.
|
||||
intcc = ImmediateKind(
|
||||
'intcc',
|
||||
'An integer comparison condition code.',
|
||||
default_member='cond',
|
||||
rust_type='ir::condcodes::IntCC',
|
||||
values={
|
||||
'eq': 'Equal',
|
||||
'ne': 'NotEqual',
|
||||
'sge': 'SignedGreaterThanOrEqual',
|
||||
'sgt': 'SignedGreaterThan',
|
||||
'sle': 'SignedLessThanOrEqual',
|
||||
'slt': 'SignedLessThan',
|
||||
'uge': 'UnsignedGreaterThanOrEqual',
|
||||
'ugt': 'UnsignedGreaterThan',
|
||||
'ule': 'UnsignedLessThanOrEqual',
|
||||
'ult': 'UnsignedLessThan',
|
||||
})
|
||||
|
||||
#: A condition code for comparing floating point values.
|
||||
#:
|
||||
#: This enumerated operand kind is used for the :clif:inst:`fcmp` instruction
|
||||
#: and corresponds to the `condcodes::FloatCC` Rust type.
|
||||
floatcc = ImmediateKind(
|
||||
'floatcc',
|
||||
'A floating point comparison condition code.',
|
||||
default_member='cond',
|
||||
rust_type='ir::condcodes::FloatCC',
|
||||
values={
|
||||
'ord': 'Ordered',
|
||||
'uno': 'Unordered',
|
||||
'eq': 'Equal',
|
||||
'ne': 'NotEqual',
|
||||
'one': 'OrderedNotEqual',
|
||||
'ueq': 'UnorderedOrEqual',
|
||||
'lt': 'LessThan',
|
||||
'le': 'LessThanOrEqual',
|
||||
'gt': 'GreaterThan',
|
||||
'ge': 'GreaterThanOrEqual',
|
||||
'ult': 'UnorderedOrLessThan',
|
||||
'ule': 'UnorderedOrLessThanOrEqual',
|
||||
'ugt': 'UnorderedOrGreaterThan',
|
||||
'uge': 'UnorderedOrGreaterThanOrEqual',
|
||||
})
|
||||
|
||||
#: Flags for memory operations like :clif:inst:`load` and :clif:inst:`store`.
|
||||
memflags = ImmediateKind(
|
||||
'memflags',
|
||||
'Memory operation flags',
|
||||
default_member='flags', rust_type='ir::MemFlags')
|
||||
|
||||
#: A register unit in the current target ISA.
|
||||
regunit = ImmediateKind(
|
||||
'regunit',
|
||||
'A register unit in the target ISA',
|
||||
rust_type='isa::RegUnit')
|
||||
|
||||
#: A trap code indicating the reason for trapping.
|
||||
#:
|
||||
#: The Rust enum type also has a `User(u16)` variant for user-provided trap
|
||||
#: codes.
|
||||
trapcode = ImmediateKind(
|
||||
'trapcode',
|
||||
'A trap reason code.',
|
||||
default_member='code',
|
||||
rust_type='ir::TrapCode',
|
||||
values={
|
||||
"stk_ovf": 'StackOverflow',
|
||||
"heap_oob": 'HeapOutOfBounds',
|
||||
"int_ovf": 'IntegerOverflow',
|
||||
"int_divz": 'IntegerDivisionByZero',
|
||||
})
|
||||
2038
cranelift/codegen/meta-python/base/instructions.py
Normal file
2038
cranelift/codegen/meta-python/base/instructions.py
Normal file
File diff suppressed because it is too large
Load Diff
708
cranelift/codegen/meta-python/base/legalize.py
Normal file
708
cranelift/codegen/meta-python/base/legalize.py
Normal file
@@ -0,0 +1,708 @@
|
||||
"""
|
||||
Patterns for legalizing the `base` instruction set.
|
||||
|
||||
The base Cranelift instruction set is 'fat', and many instructions don't have
|
||||
legal representations in a given target ISA. This module defines legalization
|
||||
patterns that describe how base instructions can be transformed to other base
|
||||
instructions that are legal.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from .immediates import intcc, imm64, ieee32, ieee64
|
||||
from . import instructions as insts
|
||||
from . import types
|
||||
from .instructions import uextend, sextend, ireduce
|
||||
from .instructions import iadd, iadd_cout, iadd_cin, iadd_carry, iadd_imm
|
||||
from .instructions import isub, isub_bin, isub_bout, isub_borrow, irsub_imm
|
||||
from .instructions import imul, imul_imm
|
||||
from .instructions import sdiv, sdiv_imm, udiv, udiv_imm
|
||||
from .instructions import srem, srem_imm, urem, urem_imm
|
||||
from .instructions import band, bor, bxor, isplit, iconcat
|
||||
from .instructions import bnot, band_not, bor_not, bxor_not
|
||||
from .instructions import band_imm, bor_imm, bxor_imm
|
||||
from .instructions import icmp, icmp_imm, ifcmp, ifcmp_imm
|
||||
from .instructions import iconst, bint, select
|
||||
from .instructions import ishl, ishl_imm, sshr, sshr_imm, ushr, ushr_imm
|
||||
from .instructions import rotl, rotl_imm, rotr, rotr_imm
|
||||
from .instructions import f32const, f64const
|
||||
from .instructions import store, load
|
||||
from .instructions import br_table
|
||||
from .instructions import bitrev
|
||||
from cdsl.ast import Var
|
||||
from cdsl.xform import Rtl, XFormGroup
|
||||
|
||||
try:
|
||||
from typing import TYPE_CHECKING # noqa
|
||||
if TYPE_CHECKING:
|
||||
from cdsl.instructions import Instruction # noqa
|
||||
except ImportError:
|
||||
TYPE_CHECKING = False
|
||||
|
||||
|
||||
narrow = XFormGroup('narrow', """
|
||||
Legalize instructions by narrowing.
|
||||
|
||||
The transformations in the 'narrow' group work by expressing
|
||||
instructions in terms of smaller types. Operations on vector types are
|
||||
expressed in terms of vector types with fewer lanes, and integer
|
||||
operations are expressed in terms of smaller integer types.
|
||||
""")
|
||||
|
||||
widen = XFormGroup('widen', """
|
||||
Legalize instructions by widening.
|
||||
|
||||
The transformations in the 'widen' group work by expressing
|
||||
instructions in terms of larger types.
|
||||
""")
|
||||
|
||||
expand = XFormGroup('expand', """
|
||||
Legalize instructions by expansion.
|
||||
|
||||
Rewrite instructions in terms of other instructions, generally
|
||||
operating on the same types as the original instructions.
|
||||
""")
|
||||
|
||||
expand_flags = XFormGroup('expand_flags', """
|
||||
Instruction expansions for architectures with flags.
|
||||
|
||||
Expand some instructions using CPU flags, then fall back to the normal
|
||||
expansions. Not all architectures support CPU flags, so these patterns
|
||||
are kept separate.
|
||||
""", chain=expand)
|
||||
|
||||
|
||||
# Custom expansions for memory objects.
|
||||
expand.custom_legalize(insts.global_value, 'expand_global_value')
|
||||
expand.custom_legalize(insts.heap_addr, 'expand_heap_addr')
|
||||
expand.custom_legalize(insts.table_addr, 'expand_table_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')
|
||||
expand.custom_legalize(insts.trapnz, 'expand_cond_trap')
|
||||
expand.custom_legalize(insts.br_table, 'expand_br_table')
|
||||
expand.custom_legalize(insts.select, 'expand_select')
|
||||
|
||||
# Custom expansions for floating point constants.
|
||||
# These expansions require bit-casting or creating constant pool entries.
|
||||
expand.custom_legalize(insts.f32const, 'expand_fconst')
|
||||
expand.custom_legalize(insts.f64const, 'expand_fconst')
|
||||
|
||||
# Custom expansions for stack memory accesses.
|
||||
expand.custom_legalize(insts.stack_load, 'expand_stack_load')
|
||||
expand.custom_legalize(insts.stack_store, 'expand_stack_store')
|
||||
|
||||
x = Var('x')
|
||||
y = Var('y')
|
||||
z = Var('z')
|
||||
a = Var('a')
|
||||
a1 = Var('a1')
|
||||
a2 = Var('a2')
|
||||
a3 = Var('a3')
|
||||
a4 = Var('a4')
|
||||
b = Var('b')
|
||||
b1 = Var('b1')
|
||||
b2 = Var('b2')
|
||||
b3 = Var('b3')
|
||||
b4 = Var('b4')
|
||||
b_in = Var('b_in')
|
||||
b_int = Var('b_int')
|
||||
c = Var('c')
|
||||
c1 = Var('c1')
|
||||
c2 = Var('c2')
|
||||
c3 = Var('c3')
|
||||
c4 = Var('c4')
|
||||
c_in = Var('c_in')
|
||||
c_int = Var('c_int')
|
||||
d = Var('d')
|
||||
d1 = Var('d1')
|
||||
d2 = Var('d2')
|
||||
d3 = Var('d3')
|
||||
d4 = Var('d4')
|
||||
e = Var('e')
|
||||
e1 = Var('e1')
|
||||
e2 = Var('e2')
|
||||
e3 = Var('e3')
|
||||
e4 = Var('e4')
|
||||
f = Var('f')
|
||||
f1 = Var('f1')
|
||||
f2 = Var('f2')
|
||||
xl = Var('xl')
|
||||
xh = Var('xh')
|
||||
yl = Var('yl')
|
||||
yh = Var('yh')
|
||||
al = Var('al')
|
||||
ah = Var('ah')
|
||||
cc = Var('cc')
|
||||
ptr = Var('ptr')
|
||||
flags = Var('flags')
|
||||
offset = Var('off')
|
||||
ss = Var('ss')
|
||||
|
||||
narrow.legalize(
|
||||
a << iadd(x, y),
|
||||
Rtl(
|
||||
(xl, xh) << isplit(x),
|
||||
(yl, yh) << isplit(y),
|
||||
(al, c) << iadd_cout(xl, yl),
|
||||
ah << iadd_cin(xh, yh, c),
|
||||
a << iconcat(al, ah)
|
||||
))
|
||||
|
||||
narrow.legalize(
|
||||
a << isub(x, y),
|
||||
Rtl(
|
||||
(xl, xh) << isplit(x),
|
||||
(yl, yh) << isplit(y),
|
||||
(al, b) << isub_bout(xl, yl),
|
||||
ah << isub_bin(xh, yh, b),
|
||||
a << iconcat(al, ah)
|
||||
))
|
||||
|
||||
for bitop in [band, bor, bxor]:
|
||||
narrow.legalize(
|
||||
a << bitop(x, y),
|
||||
Rtl(
|
||||
(xl, xh) << isplit(x),
|
||||
(yl, yh) << isplit(y),
|
||||
al << bitop(xl, yl),
|
||||
ah << bitop(xh, yh),
|
||||
a << iconcat(al, ah)
|
||||
))
|
||||
|
||||
narrow.legalize(
|
||||
a << select(c, x, y),
|
||||
Rtl(
|
||||
(xl, xh) << isplit(x),
|
||||
(yl, yh) << isplit(y),
|
||||
al << select(c, xl, yl),
|
||||
ah << select(c, xh, yh),
|
||||
a << iconcat(al, ah)
|
||||
))
|
||||
|
||||
|
||||
def widen_one_arg(signed, op):
|
||||
# type: (bool, Instruction) -> None
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
if signed:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
z << op.i32(x),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
else:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
z << op.i32(x),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
|
||||
def widen_two_arg(signed, op):
|
||||
# type: (bool, Instruction) -> None
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
if signed:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
y << sextend.i32(c),
|
||||
z << op.i32(x, y),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
else:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
y << uextend.i32(c),
|
||||
z << op.i32(x, y),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
|
||||
def widen_imm(signed, op):
|
||||
# type: (bool, Instruction) -> None
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
if signed:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
z << op.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
else:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
z << op.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
|
||||
# int ops
|
||||
for binop in [iadd, isub, imul, udiv, urem]:
|
||||
widen_two_arg(False, binop)
|
||||
|
||||
for binop in [sdiv, srem]:
|
||||
widen_two_arg(True, binop)
|
||||
|
||||
for binop in [iadd_imm, imul_imm, udiv_imm, urem_imm]:
|
||||
widen_imm(False, binop)
|
||||
|
||||
for binop in [sdiv_imm, srem_imm]:
|
||||
widen_imm(True, binop)
|
||||
|
||||
widen_imm(False, irsub_imm)
|
||||
|
||||
# bit ops
|
||||
widen_one_arg(False, bnot)
|
||||
|
||||
for binop in [band, bor, bxor, band_not, bor_not, bxor_not]:
|
||||
widen_two_arg(False, binop)
|
||||
|
||||
for binop in [band_imm, bor_imm, bxor_imm]:
|
||||
widen_imm(False, binop)
|
||||
|
||||
widen_one_arg(False, insts.popcnt)
|
||||
|
||||
for (int_ty, num) in [(types.i8, 24), (types.i16, 16)]:
|
||||
widen.legalize(
|
||||
a << insts.clz.bind(int_ty)(b),
|
||||
Rtl(
|
||||
c << uextend.i32(b),
|
||||
d << insts.clz.i32(c),
|
||||
e << iadd_imm(d, imm64(-num)),
|
||||
a << ireduce.bind(int_ty)(e)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << insts.cls.bind(int_ty)(b),
|
||||
Rtl(
|
||||
c << sextend.i32(b),
|
||||
d << insts.cls.i32(c),
|
||||
e << iadd_imm(d, imm64(-num)),
|
||||
a << ireduce.bind(int_ty)(e)
|
||||
))
|
||||
|
||||
for (int_ty, num) in [(types.i8, 1 << 8), (types.i16, 1 << 16)]:
|
||||
widen.legalize(
|
||||
a << insts.ctz.bind(int_ty)(b),
|
||||
Rtl(
|
||||
c << uextend.i32(b),
|
||||
# When `b` is zero, returns the size of x in bits.
|
||||
d << bor_imm(c, imm64(num)),
|
||||
e << insts.ctz.i32(d),
|
||||
a << ireduce.bind(int_ty)(e)
|
||||
))
|
||||
|
||||
# iconst
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
widen.legalize(
|
||||
a << iconst.bind(int_ty)(b),
|
||||
Rtl(
|
||||
c << iconst.i32(b),
|
||||
a << ireduce.bind(int_ty)(c)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << uextend.i16.i8(b),
|
||||
Rtl(
|
||||
c << uextend.i32(b),
|
||||
a << ireduce(c)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << sextend.i16.i8(b),
|
||||
Rtl(
|
||||
c << sextend.i32(b),
|
||||
a << ireduce(c)
|
||||
))
|
||||
|
||||
|
||||
widen.legalize(
|
||||
store.i8(flags, a, ptr, offset),
|
||||
Rtl(
|
||||
b << uextend.i32(a),
|
||||
insts.istore8(flags, b, ptr, offset)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
store.i16(flags, a, ptr, offset),
|
||||
Rtl(
|
||||
b << uextend.i32(a),
|
||||
insts.istore16(flags, b, ptr, offset)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << load.i8(flags, ptr, offset),
|
||||
Rtl(
|
||||
b << insts.uload8.i32(flags, ptr, offset),
|
||||
a << ireduce(b)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << load.i16(flags, ptr, offset),
|
||||
Rtl(
|
||||
b << insts.uload16.i32(flags, ptr, offset),
|
||||
a << ireduce(b)
|
||||
))
|
||||
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
widen.legalize(
|
||||
br_table.bind(int_ty)(x, y, z),
|
||||
Rtl(
|
||||
b << uextend.i32(x),
|
||||
br_table(b, y, z),
|
||||
)
|
||||
)
|
||||
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
widen.legalize(
|
||||
a << insts.bint.bind(int_ty)(b),
|
||||
Rtl(
|
||||
x << insts.bint.i32(b),
|
||||
a << ireduce.bind(int_ty)(x)
|
||||
)
|
||||
)
|
||||
|
||||
for int_ty in [types.i8, types.i16]:
|
||||
for op in [ushr_imm, ishl_imm]:
|
||||
widen.legalize(
|
||||
a << op.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
z << op.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << ishl.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
z << ishl.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << ushr.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
z << ushr.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << sshr.bind(int_ty)(b, c),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
z << sshr.i32(x, c),
|
||||
a << ireduce.bind(int_ty)(z)
|
||||
))
|
||||
|
||||
for w_cc in [
|
||||
intcc.eq, intcc.ne, intcc.ugt, intcc.ult, intcc.uge, intcc.ule
|
||||
]:
|
||||
widen.legalize(
|
||||
a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
a << insts.icmp_imm(w_cc, x, c)
|
||||
))
|
||||
widen.legalize(
|
||||
a << insts.icmp.bind(int_ty)(w_cc, b, c),
|
||||
Rtl(
|
||||
x << uextend.i32(b),
|
||||
y << uextend.i32(c),
|
||||
a << insts.icmp.i32(w_cc, x, y)
|
||||
))
|
||||
for w_cc in [intcc.sgt, intcc.slt, intcc.sge, intcc.sle]:
|
||||
widen.legalize(
|
||||
a << insts.icmp_imm.bind(int_ty)(w_cc, b, c),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
a << insts.icmp_imm(w_cc, x, c)
|
||||
))
|
||||
widen.legalize(
|
||||
a << insts.icmp.bind(int_ty)(w_cc, b, c),
|
||||
Rtl(
|
||||
x << sextend.i32(b),
|
||||
y << sextend.i32(c),
|
||||
a << insts.icmp(w_cc, x, y)
|
||||
)
|
||||
)
|
||||
|
||||
# Expand integer operations with carry for RISC architectures that don't have
|
||||
# the flags.
|
||||
expand.legalize(
|
||||
(a, c) << iadd_cout(x, y),
|
||||
Rtl(
|
||||
a << iadd(x, y),
|
||||
c << icmp(intcc.ult, a, x)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
(a, b) << isub_bout(x, y),
|
||||
Rtl(
|
||||
a << isub(x, y),
|
||||
b << icmp(intcc.ugt, a, x)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << iadd_cin(x, y, c),
|
||||
Rtl(
|
||||
a1 << iadd(x, y),
|
||||
c_int << bint(c),
|
||||
a << iadd(a1, c_int)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << isub_bin(x, y, b),
|
||||
Rtl(
|
||||
a1 << isub(x, y),
|
||||
b_int << bint(b),
|
||||
a << isub(a1, b_int)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
(a, c) << iadd_carry(x, y, c_in),
|
||||
Rtl(
|
||||
(a1, c1) << iadd_cout(x, y),
|
||||
c_int << bint(c_in),
|
||||
(a, c2) << iadd_cout(a1, c_int),
|
||||
c << bor(c1, c2)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
(a, b) << isub_borrow(x, y, b_in),
|
||||
Rtl(
|
||||
(a1, b1) << isub_bout(x, y),
|
||||
b_int << bint(b_in),
|
||||
(a, b2) << isub_bout(a1, b_int),
|
||||
b << bor(b1, b2)
|
||||
))
|
||||
|
||||
# Expansions for immediate operands that are out of range.
|
||||
for inst_imm, inst in [
|
||||
(iadd_imm, iadd),
|
||||
(imul_imm, imul),
|
||||
(sdiv_imm, sdiv),
|
||||
(udiv_imm, udiv),
|
||||
(srem_imm, srem),
|
||||
(urem_imm, urem),
|
||||
(band_imm, band),
|
||||
(bor_imm, bor),
|
||||
(bxor_imm, bxor),
|
||||
(ifcmp_imm, ifcmp)]:
|
||||
expand.legalize(
|
||||
a << inst_imm(x, y),
|
||||
Rtl(
|
||||
a1 << iconst(y),
|
||||
a << inst(x, a1)
|
||||
))
|
||||
expand.legalize(
|
||||
a << irsub_imm(y, x),
|
||||
Rtl(
|
||||
a1 << iconst(x),
|
||||
a << isub(a1, y)
|
||||
))
|
||||
|
||||
# Rotates and shifts.
|
||||
for inst_imm, inst in [
|
||||
(rotl_imm, rotl),
|
||||
(rotr_imm, rotr),
|
||||
(ishl_imm, ishl),
|
||||
(sshr_imm, sshr),
|
||||
(ushr_imm, ushr)]:
|
||||
expand.legalize(
|
||||
a << inst_imm(x, y),
|
||||
Rtl(
|
||||
a1 << iconst.i32(y),
|
||||
a << inst(x, a1)
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << icmp_imm(cc, x, y),
|
||||
Rtl(
|
||||
a1 << iconst(y),
|
||||
a << icmp(cc, x, a1)
|
||||
))
|
||||
|
||||
# Expansions for *_not variants of bitwise ops.
|
||||
for inst_not, inst in [
|
||||
(band_not, band),
|
||||
(bor_not, bor),
|
||||
(bxor_not, bxor)]:
|
||||
expand.legalize(
|
||||
a << inst_not(x, y),
|
||||
Rtl(
|
||||
a1 << bnot(y),
|
||||
a << inst(x, a1)
|
||||
))
|
||||
|
||||
# Expand bnot using xor.
|
||||
expand.legalize(
|
||||
a << bnot(x),
|
||||
Rtl(
|
||||
y << iconst(imm64(-1)),
|
||||
a << bxor(x, y)
|
||||
))
|
||||
|
||||
# Expand bitrev
|
||||
# Adapted from Stack Overflow.
|
||||
# https://stackoverflow.com/questions/746171/most-efficient-algorithm-for-bit-reversal-from-msb-lsb-to-lsb-msb-in-c
|
||||
widen.legalize(
|
||||
a << bitrev.i8(x),
|
||||
Rtl(
|
||||
a1 << band_imm(x, imm64(0xaa)),
|
||||
a2 << ushr_imm(a1, imm64(1)),
|
||||
a3 << band_imm(x, imm64(0x55)),
|
||||
a4 << ishl_imm(a3, imm64(1)),
|
||||
b << bor(a2, a4),
|
||||
b1 << band_imm(b, imm64(0xcc)),
|
||||
b2 << ushr_imm(b1, imm64(2)),
|
||||
b3 << band_imm(b, imm64(0x33)),
|
||||
b4 << ushr_imm(b3, imm64(2)),
|
||||
c << bor(b2, b4),
|
||||
c1 << band_imm(c, imm64(0xf0)),
|
||||
c2 << ushr_imm(c1, imm64(4)),
|
||||
c3 << band_imm(c, imm64(0x0f)),
|
||||
c4 << ishl_imm(c3, imm64(4)),
|
||||
a << bor(c2, c4),
|
||||
))
|
||||
|
||||
widen.legalize(
|
||||
a << bitrev.i16(x),
|
||||
Rtl(
|
||||
a1 << band_imm(x, imm64(0xaaaa)),
|
||||
a2 << ushr_imm(a1, imm64(1)),
|
||||
a3 << band_imm(x, imm64(0x5555)),
|
||||
a4 << ishl_imm(a3, imm64(1)),
|
||||
b << bor(a2, a4),
|
||||
b1 << band_imm(b, imm64(0xcccc)),
|
||||
b2 << ushr_imm(b1, imm64(2)),
|
||||
b3 << band_imm(b, imm64(0x3333)),
|
||||
b4 << ushr_imm(b3, imm64(2)),
|
||||
c << bor(b2, b4),
|
||||
c1 << band_imm(c, imm64(0xf0f0)),
|
||||
c2 << ushr_imm(c1, imm64(4)),
|
||||
c3 << band_imm(c, imm64(0x0f0f)),
|
||||
c4 << ishl_imm(c3, imm64(4)),
|
||||
d << bor(c2, c4),
|
||||
d1 << band_imm(d, imm64(0xff00)),
|
||||
d2 << ushr_imm(d1, imm64(8)),
|
||||
d3 << band_imm(d, imm64(0x00ff)),
|
||||
d4 << ishl_imm(d3, imm64(8)),
|
||||
a << bor(d2, d4),
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << bitrev.i32(x),
|
||||
Rtl(
|
||||
a1 << band_imm(x, imm64(0xaaaaaaaa)),
|
||||
a2 << ushr_imm(a1, imm64(1)),
|
||||
a3 << band_imm(x, imm64(0x55555555)),
|
||||
a4 << ishl_imm(a3, imm64(1)),
|
||||
b << bor(a2, a4),
|
||||
b1 << band_imm(b, imm64(0xcccccccc)),
|
||||
b2 << ushr_imm(b1, imm64(2)),
|
||||
b3 << band_imm(b, imm64(0x33333333)),
|
||||
b4 << ushr_imm(b3, imm64(2)),
|
||||
c << bor(b2, b4),
|
||||
c1 << band_imm(c, imm64(0xf0f0f0f0)),
|
||||
c2 << ushr_imm(c1, imm64(4)),
|
||||
c3 << band_imm(c, imm64(0x0f0f0f0f)),
|
||||
c4 << ishl_imm(c3, imm64(4)),
|
||||
d << bor(c2, c4),
|
||||
d1 << band_imm(d, imm64(0xff00ff00)),
|
||||
d2 << ushr_imm(d1, imm64(8)),
|
||||
d3 << band_imm(d, imm64(0x00ff00ff)),
|
||||
d4 << ishl_imm(d3, imm64(8)),
|
||||
e << bor(d2, d4),
|
||||
e1 << ushr_imm(e, imm64(16)),
|
||||
e2 << ishl_imm(e, imm64(16)),
|
||||
a << bor(e1, e2),
|
||||
))
|
||||
|
||||
expand.legalize(
|
||||
a << bitrev.i64(x),
|
||||
Rtl(
|
||||
a1 << band_imm(x, imm64(0xaaaaaaaaaaaaaaaa)),
|
||||
a2 << ushr_imm(a1, imm64(1)),
|
||||
a3 << band_imm(x, imm64(0x5555555555555555)),
|
||||
a4 << ishl_imm(a3, imm64(1)),
|
||||
b << bor(a2, a4),
|
||||
b1 << band_imm(b, imm64(0xcccccccccccccccc)),
|
||||
b2 << ushr_imm(b1, imm64(2)),
|
||||
b3 << band_imm(b, imm64(0x3333333333333333)),
|
||||
b4 << ushr_imm(b3, imm64(2)),
|
||||
c << bor(b2, b4),
|
||||
c1 << band_imm(c, imm64(0xf0f0f0f0f0f0f0f0)),
|
||||
c2 << ushr_imm(c1, imm64(4)),
|
||||
c3 << band_imm(c, imm64(0x0f0f0f0f0f0f0f0f)),
|
||||
c4 << ishl_imm(c3, imm64(4)),
|
||||
d << bor(c2, c4),
|
||||
d1 << band_imm(d, imm64(0xff00ff00ff00ff00)),
|
||||
d2 << ushr_imm(d1, imm64(8)),
|
||||
d3 << band_imm(d, imm64(0x00ff00ff00ff00ff)),
|
||||
d4 << ishl_imm(d3, imm64(8)),
|
||||
e << bor(d2, d4),
|
||||
e1 << band_imm(e, imm64(0xffff0000ffff0000)),
|
||||
e2 << ushr_imm(e1, imm64(16)),
|
||||
e3 << band_imm(e, imm64(0x0000ffff0000ffff)),
|
||||
e4 << ishl_imm(e3, imm64(16)),
|
||||
f << bor(e2, e4),
|
||||
f1 << ushr_imm(f, imm64(32)),
|
||||
f2 << ishl_imm(f, imm64(32)),
|
||||
a << bor(f1, f2),
|
||||
))
|
||||
|
||||
# Floating-point sign manipulations.
|
||||
for ty, minus_zero in [
|
||||
(types.f32, f32const(ieee32.bits(0x80000000))),
|
||||
(types.f64, f64const(ieee64.bits(0x8000000000000000)))]:
|
||||
expand.legalize(
|
||||
a << insts.fabs.bind(ty)(x),
|
||||
Rtl(
|
||||
b << minus_zero,
|
||||
a << band_not(x, b),
|
||||
))
|
||||
expand.legalize(
|
||||
a << insts.fneg.bind(ty)(x),
|
||||
Rtl(
|
||||
b << minus_zero,
|
||||
a << bxor(x, b),
|
||||
))
|
||||
expand.legalize(
|
||||
a << insts.fcopysign.bind(ty)(x, y),
|
||||
Rtl(
|
||||
b << minus_zero,
|
||||
a1 << band_not(x, b),
|
||||
a2 << band(y, b),
|
||||
a << bor(a1, a2)
|
||||
))
|
||||
|
||||
expand.custom_legalize(insts.br_icmp, 'expand_br_icmp')
|
||||
|
||||
# Expansions using CPU flags.
|
||||
|
||||
expand_flags.legalize(
|
||||
insts.trapnz(x, c),
|
||||
Rtl(
|
||||
a << insts.ifcmp_imm(x, imm64(0)),
|
||||
insts.trapif(intcc.ne, a, c)
|
||||
))
|
||||
expand_flags.legalize(
|
||||
insts.trapz(x, c),
|
||||
Rtl(
|
||||
a << insts.ifcmp_imm(x, imm64(0)),
|
||||
insts.trapif(intcc.eq, a, c)
|
||||
))
|
||||
42
cranelift/codegen/meta-python/base/predicates.py
Normal file
42
cranelift/codegen/meta-python/base/predicates.py
Normal file
@@ -0,0 +1,42 @@
|
||||
"""
|
||||
Cranelift predicates that consider `Function` fields.
|
||||
"""
|
||||
from cdsl.predicates import FieldPredicate
|
||||
from .formats import UnaryGlobalValue, InstructionFormat
|
||||
|
||||
try:
|
||||
from typing import TYPE_CHECKING
|
||||
if TYPE_CHECKING:
|
||||
from cdsl.formats import InstructionFormat, 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__(
|
||||
UnaryGlobalValue.global_value, 'is_colocated_data', ('func',))
|
||||
|
||||
|
||||
class LengthEquals(FieldPredicate):
|
||||
def __init__(self, iform, num):
|
||||
# type: (InstructionFormat, int) -> None
|
||||
super(LengthEquals, self).__init__(
|
||||
iform.args(), 'has_length_of', (num, 'func'))
|
||||
218
cranelift/codegen/meta-python/base/semantics.py
Normal file
218
cranelift/codegen/meta-python/base/semantics.py
Normal file
@@ -0,0 +1,218 @@
|
||||
from __future__ import absolute_import
|
||||
from semantics.primitives import prim_to_bv, prim_from_bv, bvsplit, bvconcat,\
|
||||
bvadd, bvzeroext, bvsignext
|
||||
from semantics.primitives import bveq, bvne, bvsge, bvsgt, bvsle, bvslt,\
|
||||
bvuge, bvugt, bvule, bvult
|
||||
from semantics.macros import bool2bv
|
||||
from .instructions import vsplit, vconcat, iadd, iadd_cout, icmp, bextend, \
|
||||
isplit, iconcat, iadd_cin, iadd_carry
|
||||
from .immediates import intcc
|
||||
from cdsl.xform import Rtl, XForm
|
||||
from cdsl.ast import Var
|
||||
from cdsl.typevar import TypeSet
|
||||
from cdsl.ti import InTypeset
|
||||
|
||||
try:
|
||||
from typing import TYPE_CHECKING # noqa
|
||||
if TYPE_CHECKING:
|
||||
from cdsl.ast import Enumerator # noqa
|
||||
from cdsl.instructions import Instruction # noqa
|
||||
except ImportError:
|
||||
TYPE_CHECKING = False
|
||||
|
||||
x = Var('x')
|
||||
y = Var('y')
|
||||
a = Var('a')
|
||||
b = Var('b')
|
||||
c_out = Var('c_out')
|
||||
c_in = Var('c_in')
|
||||
CC = Var('CC')
|
||||
bc_out = Var('bc_out')
|
||||
bvc_out = Var('bvc_out')
|
||||
bvc_in = Var('bvc_in')
|
||||
xhi = Var('xhi')
|
||||
yhi = Var('yhi')
|
||||
ahi = Var('ahi')
|
||||
bhi = Var('bhi')
|
||||
xlo = Var('xlo')
|
||||
ylo = Var('ylo')
|
||||
alo = Var('alo')
|
||||
blo = Var('blo')
|
||||
lo = Var('lo')
|
||||
hi = Var('hi')
|
||||
bvx = Var('bvx')
|
||||
bvy = Var('bvy')
|
||||
bva = Var('bva')
|
||||
bvt = Var('bvt')
|
||||
bvs = Var('bvs')
|
||||
bva_wide = Var('bva_wide')
|
||||
bvlo = Var('bvlo')
|
||||
bvhi = Var('bvhi')
|
||||
|
||||
ScalarTS = TypeSet(lanes=(1, 1), ints=True, floats=True, bools=True)
|
||||
|
||||
vsplit.set_semantics(
|
||||
(lo, hi) << vsplit(x),
|
||||
Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
(bvlo, bvhi) << bvsplit(bvx),
|
||||
lo << prim_from_bv(bvlo),
|
||||
hi << prim_from_bv(bvhi)
|
||||
))
|
||||
|
||||
vconcat.set_semantics(
|
||||
x << vconcat(lo, hi),
|
||||
Rtl(
|
||||
bvlo << prim_to_bv(lo),
|
||||
bvhi << prim_to_bv(hi),
|
||||
bvx << bvconcat(bvlo, bvhi),
|
||||
x << prim_from_bv(bvx)
|
||||
))
|
||||
|
||||
iadd.set_semantics(
|
||||
a << iadd(x, y),
|
||||
(Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << prim_to_bv(y),
|
||||
bva << bvadd(bvx, bvy),
|
||||
a << prim_from_bv(bva)
|
||||
), [InTypeset(x.get_typevar(), ScalarTS)]),
|
||||
Rtl(
|
||||
(xlo, xhi) << vsplit(x),
|
||||
(ylo, yhi) << vsplit(y),
|
||||
alo << iadd(xlo, ylo),
|
||||
ahi << iadd(xhi, yhi),
|
||||
a << vconcat(alo, ahi)
|
||||
))
|
||||
|
||||
#
|
||||
# Integer arithmetic with carry and/or borrow.
|
||||
#
|
||||
iadd_cin.set_semantics(
|
||||
a << iadd_cin(x, y, c_in),
|
||||
Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << prim_to_bv(y),
|
||||
bvc_in << prim_to_bv(c_in),
|
||||
bvs << bvzeroext(bvc_in),
|
||||
bvt << bvadd(bvx, bvy),
|
||||
bva << bvadd(bvt, bvs),
|
||||
a << prim_from_bv(bva)
|
||||
))
|
||||
|
||||
iadd_cout.set_semantics(
|
||||
(a, c_out) << iadd_cout(x, y),
|
||||
Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << prim_to_bv(y),
|
||||
bva << bvadd(bvx, bvy),
|
||||
bc_out << bvult(bva, bvx),
|
||||
bvc_out << bool2bv(bc_out),
|
||||
a << prim_from_bv(bva),
|
||||
c_out << prim_from_bv(bvc_out)
|
||||
))
|
||||
|
||||
iadd_carry.set_semantics(
|
||||
(a, c_out) << iadd_carry(x, y, c_in),
|
||||
Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << prim_to_bv(y),
|
||||
bvc_in << prim_to_bv(c_in),
|
||||
bvs << bvzeroext(bvc_in),
|
||||
bvt << bvadd(bvx, bvy),
|
||||
bva << bvadd(bvt, bvs),
|
||||
bc_out << bvult(bva, bvx),
|
||||
bvc_out << bool2bv(bc_out),
|
||||
a << prim_from_bv(bva),
|
||||
c_out << prim_from_bv(bvc_out)
|
||||
))
|
||||
|
||||
bextend.set_semantics(
|
||||
a << bextend(x),
|
||||
(Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << bvsignext(bvx),
|
||||
a << prim_from_bv(bvy)
|
||||
), [InTypeset(x.get_typevar(), ScalarTS)]),
|
||||
Rtl(
|
||||
(xlo, xhi) << vsplit(x),
|
||||
alo << bextend(xlo),
|
||||
ahi << bextend(xhi),
|
||||
a << vconcat(alo, ahi)
|
||||
))
|
||||
|
||||
|
||||
def create_comp_xform(cc, bvcmp_func):
|
||||
# type: (Enumerator, Instruction) -> XForm
|
||||
ba = Var('ba')
|
||||
return XForm(
|
||||
Rtl(
|
||||
a << icmp(cc, x, y)
|
||||
),
|
||||
Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
bvy << prim_to_bv(y),
|
||||
ba << bvcmp_func(bvx, bvy),
|
||||
bva << bool2bv(ba),
|
||||
bva_wide << bvzeroext(bva),
|
||||
a << prim_from_bv(bva_wide),
|
||||
),
|
||||
constraints=InTypeset(x.get_typevar(), ScalarTS))
|
||||
|
||||
|
||||
icmp.set_semantics(
|
||||
a << icmp(CC, x, y),
|
||||
Rtl(
|
||||
(xlo, xhi) << vsplit(x),
|
||||
(ylo, yhi) << vsplit(y),
|
||||
alo << icmp(CC, xlo, ylo),
|
||||
ahi << icmp(CC, xhi, yhi),
|
||||
b << vconcat(alo, ahi),
|
||||
a << bextend(b)
|
||||
),
|
||||
create_comp_xform(intcc.eq, bveq),
|
||||
create_comp_xform(intcc.ne, bvne),
|
||||
create_comp_xform(intcc.sge, bvsge),
|
||||
create_comp_xform(intcc.sgt, bvsgt),
|
||||
create_comp_xform(intcc.sle, bvsle),
|
||||
create_comp_xform(intcc.slt, bvslt),
|
||||
create_comp_xform(intcc.uge, bvuge),
|
||||
create_comp_xform(intcc.ugt, bvugt),
|
||||
create_comp_xform(intcc.ule, bvule),
|
||||
create_comp_xform(intcc.ult, bvult))
|
||||
|
||||
#
|
||||
# Legalization helper instructions.
|
||||
#
|
||||
|
||||
isplit.set_semantics(
|
||||
(xlo, xhi) << isplit(x),
|
||||
(Rtl(
|
||||
bvx << prim_to_bv(x),
|
||||
(bvlo, bvhi) << bvsplit(bvx),
|
||||
xlo << prim_from_bv(bvlo),
|
||||
xhi << prim_from_bv(bvhi)
|
||||
), [InTypeset(x.get_typevar(), ScalarTS)]),
|
||||
Rtl(
|
||||
(a, b) << vsplit(x),
|
||||
(alo, ahi) << isplit(a),
|
||||
(blo, bhi) << isplit(b),
|
||||
xlo << vconcat(alo, blo),
|
||||
xhi << vconcat(bhi, bhi)
|
||||
))
|
||||
|
||||
iconcat.set_semantics(
|
||||
x << iconcat(xlo, xhi),
|
||||
(Rtl(
|
||||
bvlo << prim_to_bv(xlo),
|
||||
bvhi << prim_to_bv(xhi),
|
||||
bvx << bvconcat(bvlo, bvhi),
|
||||
x << prim_from_bv(bvx)
|
||||
), [InTypeset(x.get_typevar(), ScalarTS)]),
|
||||
Rtl(
|
||||
(alo, ahi) << vsplit(xlo),
|
||||
(blo, bhi) << vsplit(xhi),
|
||||
a << iconcat(alo, blo),
|
||||
b << iconcat(ahi, bhi),
|
||||
x << vconcat(a, b),
|
||||
))
|
||||
144
cranelift/codegen/meta-python/base/settings.py
Normal file
144
cranelift/codegen/meta-python/base/settings.py
Normal file
@@ -0,0 +1,144 @@
|
||||
"""
|
||||
Cranelift shared settings.
|
||||
|
||||
This module defines settings relevant for all code generators.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.settings import SettingGroup, BoolSetting, EnumSetting, NumSetting
|
||||
|
||||
group = SettingGroup('shared')
|
||||
|
||||
opt_level = EnumSetting(
|
||||
"""
|
||||
Optimization level:
|
||||
|
||||
- default: Very profitable optimizations enabled, none slow.
|
||||
- best: Enable all optimizations
|
||||
- fastest: Optimize for compile time by disabling most optimizations.
|
||||
""",
|
||||
'default', 'best', 'fastest')
|
||||
|
||||
enable_verifier = BoolSetting(
|
||||
"""
|
||||
Run the Cranelift IR verifier at strategic times during compilation.
|
||||
|
||||
This makes compilation slower but catches many bugs. The verifier is
|
||||
disabled by default, except when reading Cranelift IR from a text file.
|
||||
""",
|
||||
default=True)
|
||||
|
||||
# Note that Cranelift 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 values.
|
||||
is_pic = BoolSetting("Enable Position-Independent Code generation")
|
||||
|
||||
colocated_libcalls = BoolSetting(
|
||||
"""
|
||||
Use colocated libcalls.
|
||||
|
||||
Generate code that assumes that libcalls can be declared "colocated",
|
||||
meaning they will be defined along with the current function, such that
|
||||
they can use more efficient addressing.
|
||||
""")
|
||||
|
||||
avoid_div_traps = BoolSetting(
|
||||
"""
|
||||
Generate explicit checks around native division instructions to avoid
|
||||
their trapping.
|
||||
|
||||
This is primarily used by SpiderMonkey which doesn't install a signal
|
||||
handler for SIGFPE, but expects a SIGILL trap for division by zero.
|
||||
|
||||
On ISAs like ARM where the native division instructions don't trap,
|
||||
this setting has no effect - explicit checks are always inserted.
|
||||
""")
|
||||
|
||||
enable_float = BoolSetting(
|
||||
"""
|
||||
Enable the use of floating-point instructions
|
||||
|
||||
Disabling use of floating-point instructions is not yet implemented.
|
||||
""",
|
||||
default=True)
|
||||
|
||||
enable_nan_canonicalization = BoolSetting(
|
||||
"""
|
||||
Enable NaN canonicalization
|
||||
|
||||
This replaces NaNs with a single canonical value, for users requiring
|
||||
entirely deterministic WebAssembly computation. This is not required
|
||||
by the WebAssembly spec, so it is not enabled by default.
|
||||
""",
|
||||
default=False)
|
||||
|
||||
enable_simd = BoolSetting(
|
||||
"""Enable the use of SIMD instructions.""",
|
||||
default=True)
|
||||
|
||||
enable_atomics = BoolSetting(
|
||||
"""Enable the use of atomic instructions""",
|
||||
default=True)
|
||||
|
||||
#
|
||||
# Settings specific to the `baldrdash` calling convention.
|
||||
#
|
||||
baldrdash_prologue_words = NumSetting(
|
||||
"""
|
||||
Number of pointer-sized words pushed by the baldrdash prologue.
|
||||
|
||||
Functions with the `baldrdash` calling convention don't generate their
|
||||
own prologue and epilogue. They depend on externally generated code
|
||||
that pushes a fixed number of words in the prologue and restores them
|
||||
in the epilogue.
|
||||
|
||||
This setting configures the number of pointer-sized words pushed on the
|
||||
stack when the Cranelift-generated code is entered. This includes the
|
||||
pushed return address on x86.
|
||||
""")
|
||||
|
||||
#
|
||||
# BaldrMonkey requires that not-yet-relocated function addresses be encoded
|
||||
# as all-ones bitpatterns.
|
||||
#
|
||||
allones_funcaddrs = BoolSetting(
|
||||
"""
|
||||
Emit not-yet-relocated function addresses as all-ones bit patterns.
|
||||
""")
|
||||
|
||||
#
|
||||
# Stack probing options.
|
||||
#
|
||||
probestack_enabled = BoolSetting(
|
||||
"""
|
||||
Enable the use of stack probes, for calling conventions which support
|
||||
this functionality.
|
||||
""",
|
||||
default=True)
|
||||
|
||||
probestack_func_adjusts_sp = BoolSetting(
|
||||
"""
|
||||
Set this to true of the stack probe function modifies the stack pointer
|
||||
itself.
|
||||
""")
|
||||
|
||||
probestack_size_log2 = NumSetting(
|
||||
"""
|
||||
The log2 of the size of the stack guard region.
|
||||
|
||||
Stack frames larger than this size will have stack overflow checked
|
||||
by calling the probestack function.
|
||||
|
||||
The default is 12, which translates to a size of 4096.
|
||||
""",
|
||||
default=12)
|
||||
|
||||
#
|
||||
# Jump table options.
|
||||
#
|
||||
jump_tables_enabled = BoolSetting(
|
||||
"""
|
||||
Enable the use of jump tables in generated machine code.
|
||||
""",
|
||||
default=True)
|
||||
|
||||
group.close(globals())
|
||||
49
cranelift/codegen/meta-python/base/types.py
Normal file
49
cranelift/codegen/meta-python/base/types.py
Normal file
@@ -0,0 +1,49 @@
|
||||
"""
|
||||
The base.types module predefines all the Cranelift scalar types.
|
||||
"""
|
||||
from __future__ import absolute_import
|
||||
from cdsl.types import IntType, FloatType, BoolType, FlagsType
|
||||
|
||||
#: Abstract boolean (can't be stored in memory, use bint to convert to 0 or 1).
|
||||
b1 = BoolType(1) #: 1-bit bool.
|
||||
|
||||
#: Booleans used as SIMD elements (can be stored in memory, true is all-ones).
|
||||
b8 = BoolType(8) #: 8-bit bool.
|
||||
b16 = BoolType(16) #: 16-bit bool.
|
||||
b32 = BoolType(32) #: 32-bit bool.
|
||||
b64 = BoolType(64) #: 64-bit bool.
|
||||
|
||||
# Integers.
|
||||
i8 = IntType(8) #: 8-bit int.
|
||||
i16 = IntType(16) #: 16-bit int.
|
||||
i32 = IntType(32) #: 32-bit int.
|
||||
i64 = IntType(64) #: 64-bit int.
|
||||
|
||||
#: IEEE single precision.
|
||||
f32 = FloatType(
|
||||
32, """
|
||||
A 32-bit floating point type represented in the IEEE 754-2008
|
||||
*binary32* interchange format. This corresponds to the :c:type:`float`
|
||||
type in most C implementations.
|
||||
""")
|
||||
|
||||
#: IEEE double precision.
|
||||
f64 = FloatType(
|
||||
64, """
|
||||
A 64-bit floating point type represented in the IEEE 754-2008
|
||||
*binary64* interchange format. This corresponds to the :c:type:`double`
|
||||
type in most C implementations.
|
||||
""")
|
||||
#: CPU flags from an integer comparison.
|
||||
iflags = FlagsType(
|
||||
'iflags', """
|
||||
CPU flags representing the result of an integer comparison. These flags
|
||||
can be tested with an :type:`intcc` condition code.
|
||||
""")
|
||||
|
||||
#: CPU flags from a floating point comparison.
|
||||
fflags = FlagsType(
|
||||
'fflags', """
|
||||
CPU flags representing the result of a floating point comparison. These
|
||||
flags can be tested with a :type:`floatcc` condition code.
|
||||
""")
|
||||
Reference in New Issue
Block a user