Skip to content

Commit 93357f6

Browse files
committed
Enhance generator for register instructions
1 parent 9cdd2fa commit 93357f6

File tree

4 files changed

+73
-24
lines changed

4 files changed

+73
-24
lines changed

Python/bytecodes.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,12 @@ dummy_func(
176176
ERROR_IF(res == NULL, error);
177177
}
178178

179+
register inst(UNARY_POSITIVE_R, (value -- res)) {
180+
res = PyNumber_Positive(value);
181+
DECREF_INPUTS();
182+
ERROR_IF(res == NULL, error);
183+
}
184+
179185
inst(UNARY_NEGATIVE, (value -- res)) {
180186
res = PyNumber_Negative(value);
181187
DECREF_INPUTS();

Python/generated_cases.c.h

Lines changed: 9 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Tools/cases_generator/generate_cases.py

Lines changed: 50 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ class Instruction:
109109

110110
# Parts of the underlying instruction definition
111111
inst: parser.InstDef
112+
register: bool
112113
kind: typing.Literal["inst", "op"]
113114
name: str
114115
block: parser.Block
@@ -121,13 +122,16 @@ class Instruction:
121122
cache_effects: list[parser.CacheEffect]
122123
input_effects: list[StackEffect]
123124
output_effects: list[StackEffect]
125+
input_registers: list[str] # Parallel to input_effects
126+
output_registers: list[str] # Etc.
124127

125128
# Set later
126129
family: parser.Family | None = None
127130
predicted: bool = False
128131

129132
def __init__(self, inst: parser.InstDef):
130133
self.inst = inst
134+
self.register = inst.register
131135
self.kind = inst.kind
132136
self.name = inst.name
133137
self.block = inst.block
@@ -142,6 +146,14 @@ def __init__(self, inst: parser.InstDef):
142146
]
143147
self.output_effects = inst.outputs # For consistency/completeness
144148

149+
def analyze_registers(self, a: "Analyzer") -> None:
150+
regs = iter(("REG(oparg)", "REG(oparg2)", "REG(oparg3)"))
151+
try:
152+
self.input_registers = [next(regs) for _ in self.input_effects]
153+
self.output_registers = [next(regs) for _ in self.output_effects]
154+
except StopIteration: # Running out of registers
155+
a.error(f"Instruction {self.name} has too many register effects")
156+
145157
def write(self, out: Formatter) -> None:
146158
"""Write one instruction, sans prologue and epilogue."""
147159
# Write a static assertion that a family's cache size is correct
@@ -153,10 +165,16 @@ def write(self, out: Formatter) -> None:
153165
f'{self.cache_offset}, "incorrect cache size");'
154166
)
155167

156-
# Write input stack effect variable declarations and initializations
157-
for i, ieffect in enumerate(reversed(self.input_effects), 1):
158-
src = StackEffect(f"PEEK({i})", "")
159-
out.declare(ieffect, src)
168+
if not self.register:
169+
# Write input stack effect variable declarations and initializations
170+
for i, ieffect in enumerate(reversed(self.input_effects), 1):
171+
src = StackEffect(f"PEEK({i})", "")
172+
out.declare(ieffect, src)
173+
else:
174+
# Write input register variable declarations and initializations
175+
for ieffect, reg in zip(self.input_effects, self.input_registers):
176+
src = StackEffect(reg, "")
177+
out.declare(ieffect, src)
160178

161179
# Write output stack effect variable declarations
162180
input_names = {ieffect.name for ieffect in self.input_effects}
@@ -170,18 +188,24 @@ def write(self, out: Formatter) -> None:
170188
if self.always_exits:
171189
return
172190

173-
# Write net stack growth/shrinkage
174-
diff = len(self.output_effects) - len(self.input_effects)
175-
out.stack_adjust(diff)
176-
177-
# Write output stack effect assignments
178-
unmoved_names: set[str] = set()
179-
for ieffect, oeffect in zip(self.input_effects, self.output_effects):
180-
if ieffect.name == oeffect.name:
181-
unmoved_names.add(ieffect.name)
182-
for i, oeffect in enumerate(reversed(self.output_effects), 1):
183-
if oeffect.name not in unmoved_names:
184-
dst = StackEffect(f"PEEK({i})", "")
191+
if not self.register:
192+
# Write net stack growth/shrinkage
193+
diff = len(self.output_effects) - len(self.input_effects)
194+
out.stack_adjust(diff)
195+
196+
# Write output stack effect assignments
197+
unmoved_names: set[str] = set()
198+
for ieffect, oeffect in zip(self.input_effects, self.output_effects):
199+
if ieffect.name == oeffect.name:
200+
unmoved_names.add(ieffect.name)
201+
for i, oeffect in enumerate(reversed(self.output_effects), 1):
202+
if oeffect.name not in unmoved_names:
203+
dst = StackEffect(f"PEEK({i})", "")
204+
out.assign(dst, oeffect)
205+
else:
206+
# Write output register assignments
207+
for oeffect, reg in zip(self.output_effects, self.output_registers):
208+
dst = StackEffect(reg, "")
185209
out.assign(dst, oeffect)
186210

187211
# Write cache effect
@@ -233,9 +257,10 @@ def write_body(self, out: Formatter, dedent: int, cache_adjust: int = 0) -> None
233257
else:
234258
out.write_raw(f"{extra}{space}if ({cond}) goto {label};\n")
235259
elif m := re.match(r"(\s*)DECREF_INPUTS\(\);\s*$", line):
236-
space = m.group(1)
237-
for ieff in self.input_effects:
238-
out.write_raw(f"{extra}{space}Py_DECREF({ieff.name});\n")
260+
if not self.register:
261+
space = m.group(1)
262+
for ieff in self.input_effects:
263+
out.write_raw(f"{extra}{space}Py_DECREF({ieff.name});\n")
239264
else:
240265
out.write_raw(extra + line)
241266

@@ -387,6 +412,7 @@ def analyze(self) -> None:
387412
self.find_predictions()
388413
self.map_families()
389414
self.check_families()
415+
self.analyze_register_instrs()
390416
self.analyze_supers_and_macros()
391417

392418
def find_predictions(self) -> None:
@@ -453,6 +479,11 @@ def check_families(self) -> None:
453479
family,
454480
)
455481

482+
def analyze_register_instrs(self) -> None:
483+
for instr in self.instrs.values():
484+
if instr.register:
485+
instr.analyze_registers(self)
486+
456487
def analyze_supers_and_macros(self) -> None:
457488
"""Analyze each super- and macro instruction."""
458489
self.super_instrs = {}

Tools/cases_generator/parser.py

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@ class OpName(Node):
8484

8585
@dataclass
8686
class InstHeader(Node):
87+
register: bool
8788
kind: Literal["inst", "op"]
8889
name: str
8990
inputs: list[InputEffect]
@@ -92,6 +93,7 @@ class InstHeader(Node):
9293

9394
@dataclass
9495
class InstDef(Node):
96+
register: bool
9597
kind: Literal["inst", "op"]
9698
name: str
9799
inputs: list[InputEffect]
@@ -134,27 +136,28 @@ def definition(self) -> InstDef | Super | Macro | Family | None:
134136
def inst_def(self) -> InstDef | None:
135137
if hdr := self.inst_header():
136138
if block := self.block():
137-
return InstDef(hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block)
139+
return InstDef(hdr.register, hdr.kind, hdr.name, hdr.inputs, hdr.outputs, block)
138140
raise self.make_syntax_error("Expected block")
139141
return None
140142

141143
@contextual
142144
def inst_header(self) -> InstHeader | None:
143145
# inst(NAME)
144-
# | inst(NAME, (inputs -- outputs))
145-
# | op(NAME, (inputs -- outputs))
146+
# | [register] inst(NAME, (inputs -- outputs))
147+
# | [register] op(NAME, (inputs -- outputs))
146148
# TODO: Make INST a keyword in the lexer.
149+
register = bool(self.expect(lx.REGISTER))
147150
if (tkn := self.expect(lx.IDENTIFIER)) and (kind := tkn.text) in ("inst", "op"):
148151
if self.expect(lx.LPAREN) and (tkn := self.expect(lx.IDENTIFIER)):
149152
name = tkn.text
150153
if self.expect(lx.COMMA):
151154
inp, outp = self.io_effect()
152155
if self.expect(lx.RPAREN):
153156
if (tkn := self.peek()) and tkn.kind == lx.LBRACE:
154-
return InstHeader(kind, name, inp, outp)
157+
return InstHeader(register, kind, name, inp, outp)
155158
elif self.expect(lx.RPAREN) and kind == "inst":
156159
# No legacy stack effect if kind is "op".
157-
return InstHeader(kind, name, [], [])
160+
return InstHeader(register, kind, name, [], [])
158161
return None
159162

160163
def io_effect(self) -> tuple[list[InputEffect], list[OutputEffect]]:

0 commit comments

Comments
 (0)