mirror of
				https://github.com/python/cpython.git
				synced 2025-10-31 13:41:24 +00:00 
			
		
		
		
	gh-104584: Allow unspecialized instructions in superblocks (#106497)
This adds several of unspecialized opcodes to superblocks: TO_BOOL, BINARY_SUBSCR, STORE_SUBSCR, UNPACK_SEQUENCE, LOAD_GLOBAL, LOAD_ATTR, COMPARE_OP, BINARY_OP. While we may not want that eventually, for now this helps finding bugs. There is a rudimentary test checking for UNPACK_SEQUENCE. Once we're ready to undo this, that would be simple: just replace the call to variable_used_unspecialized with a call to variable_used (as shown in a comment). Or add individual opcdes to FORBIDDEN_NAMES_IN_UOPS.
This commit is contained in:
		
							parent
							
								
									11038c56ad
								
							
						
					
					
						commit
						b3648f036e
					
				
					 4 changed files with 490 additions and 128 deletions
				
			
		|  | @ -2499,6 +2499,34 @@ def many_vars(): | ||||||
|             ex = get_first_executor(many_vars.__code__) |             ex = get_first_executor(many_vars.__code__) | ||||||
|             self.assertIn(("LOAD_FAST", 259), list(ex)) |             self.assertIn(("LOAD_FAST", 259), list(ex)) | ||||||
| 
 | 
 | ||||||
|  |     def test_unspecialized_unpack(self): | ||||||
|  |         # An example of an unspecialized opcode | ||||||
|  |         def testfunc(x): | ||||||
|  |             i = 0 | ||||||
|  |             while i < x: | ||||||
|  |                 i += 1 | ||||||
|  |                 a, b = {1: 2, 3: 3} | ||||||
|  |             assert a == 1 and b == 3 | ||||||
|  |             i = 0 | ||||||
|  |             while i < x: | ||||||
|  |                 i += 1 | ||||||
|  | 
 | ||||||
|  |         opt = _testinternalcapi.get_uop_optimizer() | ||||||
|  | 
 | ||||||
|  |         with temporary_optimizer(opt): | ||||||
|  |             testfunc(10) | ||||||
|  | 
 | ||||||
|  |         ex = None | ||||||
|  |         for offset in range(0, len(testfunc.__code__.co_code), 2): | ||||||
|  |             try: | ||||||
|  |                 ex = _testinternalcapi.get_executor(testfunc.__code__, offset) | ||||||
|  |                 break | ||||||
|  |             except ValueError: | ||||||
|  |                 pass | ||||||
|  |         self.assertIsNotNone(ex) | ||||||
|  |         uops = {opname for opname, _ in ex} | ||||||
|  |         self.assertIn("UNPACK_SEQUENCE", uops) | ||||||
|  | 
 | ||||||
| 
 | 
 | ||||||
| if __name__ == "__main__": | if __name__ == "__main__": | ||||||
|     unittest.main() |     unittest.main() | ||||||
|  |  | ||||||
							
								
								
									
										556
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										556
									
								
								Python/executor_cases.c.h
									
										
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load diff
											
										
									
								
							
							
								
								
									
										8
									
								
								Python/opcode_metadata.h
									
										
									
										generated
									
									
									
								
							
							
						
						
									
										8
									
								
								Python/opcode_metadata.h
									
										
									
										generated
									
									
									
								
							|  | @ -1182,6 +1182,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, |     [END_SEND] = { .nuops = 1, .uops = { { END_SEND, 0, 0 } } }, | ||||||
|     [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, |     [UNARY_NEGATIVE] = { .nuops = 1, .uops = { { UNARY_NEGATIVE, 0, 0 } } }, | ||||||
|     [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, |     [UNARY_NOT] = { .nuops = 1, .uops = { { UNARY_NOT, 0, 0 } } }, | ||||||
|  |     [TO_BOOL] = { .nuops = 1, .uops = { { TO_BOOL, 0, 0 } } }, | ||||||
|     [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } }, |     [TO_BOOL_BOOL] = { .nuops = 1, .uops = { { TO_BOOL_BOOL, 0, 0 } } }, | ||||||
|     [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } }, |     [TO_BOOL_INT] = { .nuops = 1, .uops = { { TO_BOOL_INT, 0, 0 } } }, | ||||||
|     [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } }, |     [TO_BOOL_LIST] = { .nuops = 1, .uops = { { TO_BOOL_LIST, 0, 0 } } }, | ||||||
|  | @ -1196,6 +1197,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, |     [BINARY_OP_ADD_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_ADD_FLOAT, 0, 0 } } }, | ||||||
|     [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, |     [BINARY_OP_SUBTRACT_FLOAT] = { .nuops = 2, .uops = { { _GUARD_BOTH_FLOAT, 0, 0 }, { _BINARY_OP_SUBTRACT_FLOAT, 0, 0 } } }, | ||||||
|     [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, |     [BINARY_OP_ADD_UNICODE] = { .nuops = 2, .uops = { { _GUARD_BOTH_UNICODE, 0, 0 }, { _BINARY_OP_ADD_UNICODE, 0, 0 } } }, | ||||||
|  |     [BINARY_SUBSCR] = { .nuops = 1, .uops = { { BINARY_SUBSCR, 0, 0 } } }, | ||||||
|     [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, |     [BINARY_SLICE] = { .nuops = 1, .uops = { { BINARY_SLICE, 0, 0 } } }, | ||||||
|     [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, |     [STORE_SLICE] = { .nuops = 1, .uops = { { STORE_SLICE, 0, 0 } } }, | ||||||
|     [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, |     [BINARY_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_LIST_INT, 0, 0 } } }, | ||||||
|  | @ -1203,6 +1205,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, |     [BINARY_SUBSCR_DICT] = { .nuops = 1, .uops = { { BINARY_SUBSCR_DICT, 0, 0 } } }, | ||||||
|     [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, |     [LIST_APPEND] = { .nuops = 1, .uops = { { LIST_APPEND, 0, 0 } } }, | ||||||
|     [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, |     [SET_ADD] = { .nuops = 1, .uops = { { SET_ADD, 0, 0 } } }, | ||||||
|  |     [STORE_SUBSCR] = { .nuops = 1, .uops = { { STORE_SUBSCR, 1, 0 } } }, | ||||||
|     [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, |     [STORE_SUBSCR_LIST_INT] = { .nuops = 1, .uops = { { STORE_SUBSCR_LIST_INT, 0, 0 } } }, | ||||||
|     [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, |     [STORE_SUBSCR_DICT] = { .nuops = 1, .uops = { { STORE_SUBSCR_DICT, 0, 0 } } }, | ||||||
|     [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, |     [DELETE_SUBSCR] = { .nuops = 1, .uops = { { DELETE_SUBSCR, 0, 0 } } }, | ||||||
|  | @ -1216,6 +1219,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } }, |     [LOAD_BUILD_CLASS] = { .nuops = 1, .uops = { { LOAD_BUILD_CLASS, 0, 0 } } }, | ||||||
|     [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } }, |     [STORE_NAME] = { .nuops = 1, .uops = { { STORE_NAME, 0, 0 } } }, | ||||||
|     [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } }, |     [DELETE_NAME] = { .nuops = 1, .uops = { { DELETE_NAME, 0, 0 } } }, | ||||||
|  |     [UNPACK_SEQUENCE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE, 0, 0 } } }, | ||||||
|     [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } }, |     [UNPACK_SEQUENCE_TWO_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TWO_TUPLE, 0, 0 } } }, | ||||||
|     [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, |     [UNPACK_SEQUENCE_TUPLE] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_TUPLE, 0, 0 } } }, | ||||||
|     [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, |     [UNPACK_SEQUENCE_LIST] = { .nuops = 1, .uops = { { UNPACK_SEQUENCE_LIST, 0, 0 } } }, | ||||||
|  | @ -1226,6 +1230,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, |     [LOAD_LOCALS] = { .nuops = 1, .uops = { { _LOAD_LOCALS, 0, 0 } } }, | ||||||
|     [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, |     [LOAD_NAME] = { .nuops = 2, .uops = { { _LOAD_LOCALS, 0, 0 }, { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, | ||||||
|     [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, |     [LOAD_FROM_DICT_OR_GLOBALS] = { .nuops = 1, .uops = { { _LOAD_FROM_DICT_OR_GLOBALS, 0, 0 } } }, | ||||||
|  |     [LOAD_GLOBAL] = { .nuops = 1, .uops = { { LOAD_GLOBAL, 0, 0 } } }, | ||||||
|     [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, |     [DELETE_FAST] = { .nuops = 1, .uops = { { DELETE_FAST, 0, 0 } } }, | ||||||
|     [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, |     [DELETE_DEREF] = { .nuops = 1, .uops = { { DELETE_DEREF, 0, 0 } } }, | ||||||
|     [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, |     [LOAD_FROM_DICT_OR_DEREF] = { .nuops = 1, .uops = { { LOAD_FROM_DICT_OR_DEREF, 0, 0 } } }, | ||||||
|  | @ -1246,6 +1251,8 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } }, |     [MAP_ADD] = { .nuops = 1, .uops = { { MAP_ADD, 0, 0 } } }, | ||||||
|     [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, |     [LOAD_SUPER_ATTR_ATTR] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_ATTR, 0, 0 } } }, | ||||||
|     [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, |     [LOAD_SUPER_ATTR_METHOD] = { .nuops = 1, .uops = { { LOAD_SUPER_ATTR_METHOD, 0, 0 } } }, | ||||||
|  |     [LOAD_ATTR] = { .nuops = 1, .uops = { { LOAD_ATTR, 0, 0 } } }, | ||||||
|  |     [COMPARE_OP] = { .nuops = 1, .uops = { { COMPARE_OP, 0, 0 } } }, | ||||||
|     [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, |     [COMPARE_OP_FLOAT] = { .nuops = 1, .uops = { { COMPARE_OP_FLOAT, 0, 0 } } }, | ||||||
|     [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, |     [COMPARE_OP_INT] = { .nuops = 1, .uops = { { COMPARE_OP_INT, 0, 0 } } }, | ||||||
|     [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } }, |     [COMPARE_OP_STR] = { .nuops = 1, .uops = { { COMPARE_OP_STR, 0, 0 } } }, | ||||||
|  | @ -1270,6 +1277,7 @@ const struct opcode_macro_expansion _PyOpcode_macro_expansion[256] = { | ||||||
|     [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } }, |     [FORMAT_SIMPLE] = { .nuops = 1, .uops = { { FORMAT_SIMPLE, 0, 0 } } }, | ||||||
|     [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } }, |     [FORMAT_WITH_SPEC] = { .nuops = 1, .uops = { { FORMAT_WITH_SPEC, 0, 0 } } }, | ||||||
|     [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, |     [COPY] = { .nuops = 1, .uops = { { COPY, 0, 0 } } }, | ||||||
|  |     [BINARY_OP] = { .nuops = 1, .uops = { { BINARY_OP, 0, 0 } } }, | ||||||
|     [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, |     [SWAP] = { .nuops = 1, .uops = { { SWAP, 0, 0 } } }, | ||||||
| }; | }; | ||||||
| #ifdef NEED_OPCODE_METADATA | #ifdef NEED_OPCODE_METADATA | ||||||
|  |  | ||||||
|  | @ -425,8 +425,9 @@ def is_viable_uop(self) -> bool: | ||||||
|                 return False |                 return False | ||||||
|         res = True |         res = True | ||||||
|         for forbidden in FORBIDDEN_NAMES_IN_UOPS: |         for forbidden in FORBIDDEN_NAMES_IN_UOPS: | ||||||
|             # TODO: Don't check in '#ifdef ENABLE_SPECIALIZATION' regions |             # NOTE: To disallow unspecialized uops, use | ||||||
|             if variable_used(self.inst, forbidden): |             # if variable_used(self.inst, forbidden): | ||||||
|  |             if variable_used_unspecialized(self.inst, forbidden): | ||||||
|                 # print(f"Skipping {self.name} because it uses {forbidden}") |                 # print(f"Skipping {self.name} because it uses {forbidden}") | ||||||
|                 res = False |                 res = False | ||||||
|         return res |         return res | ||||||
|  | @ -1644,6 +1645,27 @@ def variable_used(node: parser.Node, name: str) -> bool: | ||||||
|     ) |     ) | ||||||
| 
 | 
 | ||||||
| 
 | 
 | ||||||
|  | def variable_used_unspecialized(node: parser.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 == "ENABLE_SPECIALIZATION" | ||||||
|  |                 ): | ||||||
|  |                     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) | ||||||
|  | 
 | ||||||
|  | 
 | ||||||
| def main(): | def main(): | ||||||
|     """Parse command line, parse input, analyze, write output.""" |     """Parse command line, parse input, analyze, write output.""" | ||||||
|     args = arg_parser.parse_args()  # Prints message and sys.exit(2) on error |     args = arg_parser.parse_args()  # Prints message and sys.exit(2) on error | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue
	
	 Guido van Rossum
						Guido van Rossum