Illegalize rbp/r13 for zero-offset loads on Intel x64 (#225)
* Switch RegClass to a bitmap implementation. * Add special RegClass to remove r13 from 'ld' recipe. * Use MASK_LEN constant instead of magic number. * Enforce that RegClass slicing is only valid on contiguous classes. * Use Optional[int] for RegClass optional bitmask parameter. * Add comment explaining use of Intel ISA's GPR_NORIP register class.
This commit is contained in:
committed by
Jakob Stoklund Olesen
parent
1e2b7de141
commit
eb85aa833c
@@ -26,12 +26,12 @@ from . import is_power_of_two, next_power_of_two
|
||||
|
||||
|
||||
try:
|
||||
from typing import Sequence, Tuple, List, Dict, Any, TYPE_CHECKING # noqa
|
||||
from typing import Sequence, Tuple, List, Dict, Any, Optional, TYPE_CHECKING # noqa
|
||||
if TYPE_CHECKING:
|
||||
from .isa import TargetISA # noqa
|
||||
# A tuple uniquely identifying a register class inside a register bank.
|
||||
# (count, width, start)
|
||||
RCTup = Tuple[int, int, int]
|
||||
# (width, bitmask)
|
||||
RCTup = Tuple[int, int]
|
||||
except ImportError:
|
||||
pass
|
||||
|
||||
@@ -195,24 +195,29 @@ class RegClass(object):
|
||||
:param start: The first unit to allocate, relative to `bank.first.unit`.
|
||||
"""
|
||||
|
||||
def __init__(self, bank, count=None, width=1, start=0):
|
||||
# type: (RegBank, int, int, int) -> None
|
||||
def __init__(self, bank, count=0, width=1, start=0, bitmask=None):
|
||||
# type: (RegBank, int, int, int, Optional[int]) -> None
|
||||
self.name = None # type: str
|
||||
self.index = None # type: int
|
||||
self.bank = bank
|
||||
self.start = start
|
||||
self.width = width
|
||||
self.bitmask = 0
|
||||
|
||||
# This is computed later in `finish_regclasses()`.
|
||||
self.subclasses = list() # type: List[RegClass]
|
||||
self.toprc = None # type: RegClass
|
||||
|
||||
assert width > 0
|
||||
assert start >= 0 and start < bank.units
|
||||
|
||||
if count is None:
|
||||
count = bank.units // width
|
||||
self.count = count
|
||||
if bitmask:
|
||||
self.bitmask = bitmask
|
||||
else:
|
||||
assert start >= 0 and start < bank.units
|
||||
if count == 0:
|
||||
count = bank.units // width
|
||||
for a in range(count):
|
||||
u = start + a * self.width
|
||||
self.bitmask |= 1 << u
|
||||
|
||||
bank.classes.append(self)
|
||||
|
||||
@@ -238,7 +243,7 @@ class RegClass(object):
|
||||
The tuple can be used as a dictionary key to ensure that there are no
|
||||
duplicate register classes.
|
||||
"""
|
||||
return (self.count, self.width, self.start)
|
||||
return (self.width, self.bitmask)
|
||||
|
||||
def intersect(self, other):
|
||||
# type: (RegClass) -> RCTup
|
||||
@@ -249,17 +254,11 @@ class RegClass(object):
|
||||
"""
|
||||
if self.width != other.width:
|
||||
return None
|
||||
s_end = self.start + self.count * self.width
|
||||
o_end = other.start + other.count * other.width
|
||||
if self.start >= o_end or other.start >= s_end:
|
||||
intersection = self.bitmask & other.bitmask
|
||||
if intersection == 0:
|
||||
return None
|
||||
|
||||
# We have an overlap.
|
||||
start = max(self.start, other.start)
|
||||
end = min(s_end, o_end)
|
||||
count = (end - start) // self.width
|
||||
assert count > 0
|
||||
return (count, self.width, start)
|
||||
return (self.width, intersection)
|
||||
|
||||
def __getitem__(self, sliced):
|
||||
# type: (slice) -> RegClass
|
||||
@@ -271,14 +270,57 @@ class RegClass(object):
|
||||
assert isinstance(sliced, slice), "RegClass slicing can't be 1 reg"
|
||||
# We could add strided sub-classes if needed.
|
||||
assert sliced.step is None, 'Subclass striding not supported'
|
||||
# Can't slice a non-contiguous class
|
||||
assert self.is_contiguous(), 'Cannot slice non-contiguous RegClass'
|
||||
|
||||
w = self.width
|
||||
s = self.start + sliced.start * w
|
||||
s = self.start() + sliced.start * w
|
||||
c = sliced.stop - sliced.start
|
||||
assert c > 1, "Can't have single-register classes"
|
||||
|
||||
return RegClass(self.bank, count=c, width=w, start=s)
|
||||
|
||||
def without(self, *registers):
|
||||
# type: (*Register) -> RegClass
|
||||
"""
|
||||
Create a sub-class of a register class excluding a specific set of
|
||||
registers.
|
||||
|
||||
For example: GPR.without(GPR.r9)
|
||||
"""
|
||||
bm = self.bitmask
|
||||
w = self.width
|
||||
fmask = (1 << self.width) - 1
|
||||
for reg in registers:
|
||||
bm &= ~(fmask << (reg.unit * w))
|
||||
|
||||
return RegClass(self.bank, bitmask=bm)
|
||||
|
||||
def is_contiguous(self):
|
||||
# type: () -> bool
|
||||
"""
|
||||
Returns boolean indicating whether a register class is a contiguous set
|
||||
of register units.
|
||||
"""
|
||||
x = self.bitmask | (self.bitmask-1)
|
||||
return self.bitmask != 0 and ((x+1) & x) == 0
|
||||
|
||||
def start(self):
|
||||
# type: () -> int
|
||||
"""
|
||||
Returns the first valid register unit in this class.
|
||||
"""
|
||||
start = 0
|
||||
bm = self.bitmask
|
||||
fmask = (1 << self.width) - 1
|
||||
while True:
|
||||
if bm & fmask > 0:
|
||||
break
|
||||
start += 1
|
||||
bm >>= self.width
|
||||
|
||||
return start
|
||||
|
||||
def __getattr__(self, attr):
|
||||
# type: (str) -> Register
|
||||
"""
|
||||
@@ -299,19 +341,13 @@ class RegClass(object):
|
||||
|
||||
Return as a list of 32-bit integers.
|
||||
"""
|
||||
mask = [0] * MASK_LEN
|
||||
out_mask = []
|
||||
mask32 = (1 << 32) - 1
|
||||
bitmask = self.bitmask << self.bank.first_unit
|
||||
for i in range(MASK_LEN):
|
||||
out_mask.append((bitmask >> (i * 32)) & mask32)
|
||||
|
||||
start = self.bank.first_unit + self.start
|
||||
for a in range(self.count):
|
||||
u = start + a * self.width
|
||||
b = u % 32
|
||||
# We need fancier masking code if a register can straddle mask
|
||||
# words. This will only happen with widths that are not powers of
|
||||
# two.
|
||||
assert b + self.width <= 32, 'Register straddles words'
|
||||
mask[u // 32] |= 1 << b
|
||||
|
||||
return mask
|
||||
return out_mask
|
||||
|
||||
def subclass_mask(self):
|
||||
# type: () -> int
|
||||
|
||||
@@ -59,7 +59,7 @@ def gen_regclass(rc, fmt):
|
||||
fmt.format('width: {},', rc.width)
|
||||
fmt.format('bank: {},', rc.bank.index)
|
||||
fmt.format('toprc: {},', rc.toprc.index)
|
||||
fmt.format('first: {},', rc.bank.first_unit + rc.start)
|
||||
fmt.format('first: {},', rc.bank.first_unit + rc.start())
|
||||
fmt.format('subclasses: 0x{:x},', rc.subclass_mask())
|
||||
mask = ', '.join('0x{:08x}'.format(x) for x in rc.mask())
|
||||
fmt.format('mask: [{}],', mask)
|
||||
|
||||
@@ -11,7 +11,8 @@ from base.formats import IntCompare, FloatCompare, IntCond, FloatCond
|
||||
from base.formats import Jump, Branch, BranchInt, BranchFloat
|
||||
from base.formats import Ternary, FuncAddr, UnaryGlobalVar
|
||||
from base.formats import RegMove, RegSpill, RegFill, CopySpecial
|
||||
from .registers import GPR, ABCD, FPR, GPR8, FPR8, FLAG, StackGPR32, StackFPR32
|
||||
from .registers import GPR, ABCD, FPR, GPR_NORIP, GPR8, FPR8, GPR8_NORIP
|
||||
from .registers import FLAG, StackGPR32, StackFPR32
|
||||
from .defs import supported_floatccs
|
||||
from .settings import use_sse41
|
||||
|
||||
@@ -103,6 +104,7 @@ def replace_put_op(emit, prefix):
|
||||
# Register class mapping for no-REX instructions.
|
||||
NOREX_MAP = {
|
||||
GPR: GPR8,
|
||||
GPR_NORIP: GPR8_NORIP,
|
||||
FPR: FPR8
|
||||
}
|
||||
|
||||
@@ -766,7 +768,7 @@ frsp32 = TailRecipe(
|
||||
|
||||
# XX /r load with no offset.
|
||||
ld = TailRecipe(
|
||||
'ld', Load, size=1, ins=(GPR), outs=(GPR),
|
||||
'ld', Load, size=1, ins=(GPR_NORIP), outs=(GPR),
|
||||
instp=IsEqual(Load.offset, 0),
|
||||
clobbers_flags=False,
|
||||
emit='''
|
||||
|
||||
@@ -47,6 +47,9 @@ FlagRegs = RegBank(
|
||||
|
||||
GPR = RegClass(IntRegs)
|
||||
GPR8 = GPR[0:8]
|
||||
# In certain instructions, RBP and R13 are interpreted as RIP-relative.
|
||||
GPR_NORIP = GPR.without(GPR.rbp, GPR.r13)
|
||||
GPR8_NORIP = GPR8.without(GPR.rbp)
|
||||
ABCD = GPR[0:4]
|
||||
FPR = RegClass(FloatRegs)
|
||||
FPR8 = FPR[0:8]
|
||||
|
||||
Reference in New Issue
Block a user