|
19 | 19 | #include "cinderx/Interpreter/cinder_opcode.h" |
20 | 20 | #include "cinderx/Jit/containers.h" |
21 | 21 | #include "cinderx/Jit/context.h" |
| 22 | +#include "cinderx/Jit/iterator_types.h" |
22 | 23 | #include "cinderx/Jit/hir/annotation_index.h" |
23 | 24 | #include "cinderx/Jit/hir/ssa.h" |
24 | 25 | #include "cinderx/Jit/hir/type.h" |
@@ -1555,7 +1556,7 @@ void HIRBuilder::translate( |
1555 | 1556 | break; |
1556 | 1557 | } |
1557 | 1558 | case GET_ITER: { |
1558 | | - emitGetIter(tc); |
| 1559 | + emitGetIter(tc, bc_instr); |
1559 | 1560 | break; |
1560 | 1561 | } |
1561 | 1562 | case GET_YIELD_FROM_ITER: { |
@@ -3180,7 +3181,8 @@ void HIRBuilder::emitLoadAttr( |
3180 | 3181 | tc.emit<GuardType>(receiver, type, receiver, tc.frame); |
3181 | 3182 | break; |
3182 | 3183 | } |
3183 | | - case LOAD_ATTR_SLOT: { |
| 3184 | + case LOAD_ATTR_SLOT: |
| 3185 | + case LOAD_ATTR_INSTANCE_VALUE: { |
3184 | 3186 | // Read the type version from CPython's inline cache. |
3185 | 3187 | // The cache follows the instruction word in the bytecode array. |
3186 | 3188 | // Layout: _PyAttrCache { counter, version[2], index } |
@@ -4250,6 +4252,30 @@ void HIRBuilder::emitStoreAttr( |
4250 | 4252 | const jit::BytecodeInstruction& bc_instr) { |
4251 | 4253 | Register* receiver = tc.frame.stack.pop(); |
4252 | 4254 | Register* value = tc.frame.stack.pop(); |
| 4255 | + |
| 4256 | + if (getConfig().specialized_opcodes) { |
| 4257 | + switch (bc_instr.specializedOpcode()) { |
| 4258 | + case STORE_ATTR_INSTANCE_VALUE: |
| 4259 | + case STORE_ATTR_SLOT: { |
| 4260 | + _Py_CODEUNIT* code_units = codeUnit(code_); |
| 4261 | + int instr_idx = bc_instr.opcodeIndex().value(); |
| 4262 | + const _PyAttrCache* cache = |
| 4263 | + reinterpret_cast<const _PyAttrCache*>(&code_units[instr_idx + 1]); |
| 4264 | + uint32_t type_version = |
| 4265 | + cache->version[0] | |
| 4266 | + (static_cast<uint32_t>(cache->version[1]) << 16); |
| 4267 | + PyTypeObject* attr_type = findTypeByVersionTag(type_version); |
| 4268 | + if (attr_type != nullptr) { |
| 4269 | + Type type = Type::fromTypeExact(attr_type); |
| 4270 | + tc.emit<GuardType>(receiver, type, receiver, tc.frame); |
| 4271 | + } |
| 4272 | + break; |
| 4273 | + } |
| 4274 | + default: |
| 4275 | + break; |
| 4276 | + } |
| 4277 | + } |
| 4278 | + |
4253 | 4279 | tc.emit<StoreAttr>(receiver, value, bc_instr.oparg(), tc.frame); |
4254 | 4280 | } |
4255 | 4281 |
|
@@ -4362,10 +4388,36 @@ void HIRBuilder::emitStoreSubscr( |
4362 | 4388 | tc.emit<StoreSubscr>(container, sub, value, tc.frame); |
4363 | 4389 | } |
4364 | 4390 |
|
4365 | | -void HIRBuilder::emitGetIter(TranslationContext& tc) { |
| 4391 | +void HIRBuilder::emitGetIter( |
| 4392 | + TranslationContext& tc, |
| 4393 | + const jit::BytecodeInstruction& bc_instr) { |
4366 | 4394 | Register* iterable = tc.frame.stack.pop(); |
4367 | 4395 | Register* result = temps_.AllocateStack(); |
4368 | 4396 | tc.emit<GetIter>(result, iterable, tc.frame); |
| 4397 | + // FOR_ITER specialisation: if the next instruction is a specialised FOR_ITER, |
| 4398 | + // guard the iterator type here (once, before the loop) rather than inside |
| 4399 | + // the loop body. This enables the Simplify pass to replace generic |
| 4400 | + // InvokeIterNext with CallStatic(JITRT_InvokeIterNext). |
| 4401 | + if (getConfig().specialized_opcodes) { |
| 4402 | + auto next_instr = bc_instr.nextInstr(); |
| 4403 | + auto next_opcode = next_instr.specializedOpcode(); |
| 4404 | + if (next_opcode == FOR_ITER_RANGE && |
| 4405 | + jit::g_range_iterator_type != nullptr) { |
| 4406 | + Type range_iter_type = |
| 4407 | + Type::fromTypeExact(jit::g_range_iterator_type); |
| 4408 | + tc.emit<GuardType>(result, range_iter_type, result, tc.frame); |
| 4409 | + } else if (next_opcode == FOR_ITER_LIST && |
| 4410 | + jit::g_list_iterator_type != nullptr) { |
| 4411 | + Type list_iter_type = |
| 4412 | + Type::fromTypeExact(jit::g_list_iterator_type); |
| 4413 | + tc.emit<GuardType>(result, list_iter_type, result, tc.frame); |
| 4414 | + } else if (next_opcode == FOR_ITER_TUPLE && |
| 4415 | + jit::g_tuple_iterator_type != nullptr) { |
| 4416 | + Type tuple_iter_type = |
| 4417 | + Type::fromTypeExact(jit::g_tuple_iterator_type); |
| 4418 | + tc.emit<GuardType>(result, tuple_iter_type, result, tc.frame); |
| 4419 | + } |
| 4420 | + } |
4369 | 4421 | tc.frame.stack.push(result); |
4370 | 4422 | if constexpr (PY_VERSION_HEX >= 0x030F0000) { |
4371 | 4423 | // TASK(T243355471): We should support virtual indexing |
|
0 commit comments