mirror of
				https://github.com/python/cpython.git
				synced 2025-10-30 21:21:22 +00:00 
			
		
		
		
	 dc8fdf5fd5
			
		
	
	
		dc8fdf5fd5
		
			
		
	
	
	
	
		
			
			* Split `CALL_PY_EXACT_ARGS` into uops This is only the first step for doing `CALL` in Tier 2. The next step involves tracing into the called code object and back. After that we'll have to do the remaining `CALL` specialization. Finally we'll have to deal with `KW_NAMES`. Note: this moves setting `frame->return_offset` directly in front of `DISPATCH_INLINED()`, to make it easier to move it into `_PUSH_FRAME`.
		
			
				
	
	
		
			102 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			102 lines
		
	
	
	
		
			3.3 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| import dataclasses
 | |
| 
 | |
| from formatting import Formatter
 | |
| import lexer as lx
 | |
| import parsing
 | |
| 
 | |
| 
 | |
| @dataclasses.dataclass
 | |
| class InstructionFlags:
 | |
|     """Construct and manipulate instruction flags"""
 | |
| 
 | |
|     HAS_ARG_FLAG: bool
 | |
|     HAS_CONST_FLAG: bool
 | |
|     HAS_NAME_FLAG: bool
 | |
|     HAS_JUMP_FLAG: bool
 | |
|     HAS_FREE_FLAG: bool
 | |
|     HAS_LOCAL_FLAG: bool
 | |
| 
 | |
|     def __post_init__(self):
 | |
|         self.bitmask = {name: (1 << i) for i, name in enumerate(self.names())}
 | |
| 
 | |
|     @staticmethod
 | |
|     def fromInstruction(instr: parsing.Node):
 | |
| 
 | |
|         has_free = (
 | |
|             variable_used(instr, "PyCell_New")
 | |
|             or variable_used(instr, "PyCell_GET")
 | |
|             or variable_used(instr, "PyCell_SET")
 | |
|         )
 | |
| 
 | |
|         return InstructionFlags(
 | |
|             HAS_ARG_FLAG=variable_used(instr, "oparg"),
 | |
|             HAS_CONST_FLAG=variable_used(instr, "FRAME_CO_CONSTS"),
 | |
|             HAS_NAME_FLAG=variable_used(instr, "FRAME_CO_NAMES"),
 | |
|             HAS_JUMP_FLAG=variable_used(instr, "JUMPBY"),
 | |
|             HAS_FREE_FLAG=has_free,
 | |
|             HAS_LOCAL_FLAG=(
 | |
|                 variable_used(instr, "GETLOCAL") or variable_used(instr, "SETLOCAL")
 | |
|             )
 | |
|             and not has_free,
 | |
|         )
 | |
| 
 | |
|     @staticmethod
 | |
|     def newEmpty():
 | |
|         return InstructionFlags(False, False, False, False, False, False)
 | |
| 
 | |
|     def add(self, other: "InstructionFlags") -> None:
 | |
|         for name, value in dataclasses.asdict(other).items():
 | |
|             if value:
 | |
|                 setattr(self, name, value)
 | |
| 
 | |
|     def names(self, value=None) -> list[str]:
 | |
|         if value is None:
 | |
|             return list(dataclasses.asdict(self).keys())
 | |
|         return [n for n, v in dataclasses.asdict(self).items() if v == value]
 | |
| 
 | |
|     def bitmap(self) -> int:
 | |
|         flags = 0
 | |
|         for name in self.names():
 | |
|             if getattr(self, name):
 | |
|                 flags |= self.bitmask[name]
 | |
|         return flags
 | |
| 
 | |
|     @classmethod
 | |
|     def emit_macros(cls, out: Formatter):
 | |
|         flags = cls.newEmpty()
 | |
|         for name, value in flags.bitmask.items():
 | |
|             out.emit(f"#define {name} ({value})")
 | |
| 
 | |
|         for name, value in flags.bitmask.items():
 | |
|             out.emit(
 | |
|                 f"#define OPCODE_{name[:-len('_FLAG')]}(OP) "
 | |
|                 f"(_PyOpcode_opcode_metadata[OP].flags & ({name}))"
 | |
|             )
 | |
| 
 | |
| 
 | |
| def variable_used(node: parsing.Node, name: str) -> bool:
 | |
|     """Determine whether a variable with a given name is used in a node."""
 | |
|     return any(
 | |
|         token.kind == "IDENTIFIER" and token.text == name for token in node.tokens
 | |
|     )
 | |
| 
 | |
| 
 | |
| def variable_used_unspecialized(node: parsing.Node, name: str) -> bool:
 | |
|     """Like variable_used(), but skips #if ENABLE_SPECIALIZATION blocks."""
 | |
|     tokens: list[lx.Token] = []
 | |
|     skipping = False
 | |
|     for i, token in enumerate(node.tokens):
 | |
|         if token.kind == "MACRO":
 | |
|             text = "".join(token.text.split())
 | |
|             # TODO: Handle nested #if
 | |
|             if text == "#if":
 | |
|                 if (
 | |
|                     i + 1 < len(node.tokens)
 | |
|                     and node.tokens[i + 1].text in ("ENABLE_SPECIALIZATION", "TIER_ONE")
 | |
|                 ):
 | |
|                     skipping = True
 | |
|             elif text in ("#else", "#endif"):
 | |
|                 skipping = False
 | |
|         if not skipping:
 | |
|             tokens.append(token)
 | |
|     return any(token.kind == "IDENTIFIER" and token.text == name for token in tokens)
 |