Skip to content

Commit ea8117d

Browse files
committed
[GR-40894] Tweak bytecode interpreter inlining to get better host inlined code
PullRequest: graalpython/2401
2 parents bb58e77 + f5db440 commit ea8117d

File tree

17 files changed

+520
-262
lines changed

17 files changed

+520
-262
lines changed
Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
# Copyright (c) 2019, 2022, Oracle and/or its affiliates. All rights reserved.
2+
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
3+
#
4+
# The Universal Permissive License (UPL), Version 1.0
5+
#
6+
# Subject to the condition set forth below, permission is hereby granted to any
7+
# person obtaining a copy of this software, associated documentation and/or
8+
# data (collectively the "Software"), free of charge and under any and all
9+
# copyright rights in the Software, and any and all patent rights owned or
10+
# freely licensable by each licensor hereunder covering either (i) the
11+
# unmodified Software as contributed to or provided by such licensor, or (ii)
12+
# the Larger Works (as defined below), to deal in both
13+
#
14+
# (a) the Software, and
15+
#
16+
# (b) any piece of software and/or hardware listed in the lrgrwrks.txt file if
17+
# one is included with the Software each a "Larger Work" to which the Software
18+
# is contributed by such licensors),
19+
#
20+
# without restriction, including without limitation the rights to copy, create
21+
# derivative works of, display, perform, and distribute the Software and make,
22+
# use, sell, offer for sale, import, export, have made, and have sold the
23+
# Software and the Larger Work(s), and to sublicense the foregoing rights on
24+
# either these or other terms.
25+
#
26+
# This license is subject to the following condition:
27+
#
28+
# The above copyright notice and either this complete permission notice or at a
29+
# minimum a reference to the UPL must be included in all copies or substantial
30+
# portions of the Software.
31+
#
32+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
33+
# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
34+
# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
35+
# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
36+
# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
37+
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
38+
# SOFTWARE.
39+
40+
41+
"""Handy bytecode-heavy benchmark, inspired by the Squeak version"""
42+
43+
# 77 instructions on CPython 3.10.0
44+
# 75 instructions on CPython 2.7.18
45+
46+
# useful IGV filters when focusing on the bytecode switch:
47+
#
48+
# Colorize by frequency
49+
# > colorizeGradientWithMode("relativeFrequency", 0, 7, "logarithmic");
50+
#
51+
# Remove low frequency bytecode branches (less than 0.4 relativeFrequency)
52+
# > remove("relativeFrequency", "^(0\\.(0|1|2|3).+|.+E-.+)$");
53+
54+
55+
def __benchmark__(num=10):
56+
size = 8191
57+
iter = 0
58+
while iter < num:
59+
count = 0
60+
flags = [True] * size
61+
i = 0
62+
while i < size:
63+
if flags[i]:
64+
prime = i + 2
65+
k = i + prime
66+
while k < size:
67+
flags[k] = False
68+
k = k + prime
69+
count += 1
70+
i += 1
71+
iter += 1
72+
assert count == 1028, count

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/common/SequenceStorageNodes.java

Lines changed: 62 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@
156156
import com.oracle.truffle.api.CompilerDirectives;
157157
import com.oracle.truffle.api.CompilerDirectives.CompilationFinal;
158158
import com.oracle.truffle.api.CompilerDirectives.TruffleBoundary;
159+
import com.oracle.truffle.api.HostCompilerDirectives.InliningCutoff;
159160
import com.oracle.truffle.api.dsl.Bind;
160161
import com.oracle.truffle.api.dsl.Cached;
161162
import com.oracle.truffle.api.dsl.Cached.Exclusive;
@@ -278,6 +279,7 @@ abstract static class SequenceStorageBaseNode extends PNodeWithContext {
278279
protected static final int MAX_SEQUENCE_STORAGES = 9;
279280
protected static final int MAX_ARRAY_STORAGES = 7;
280281

282+
@InliningCutoff
281283
protected static boolean isByteStorage(NativeSequenceStorage store) {
282284
return store.getElementType() == ListStorageType.Byte;
283285
}
@@ -312,30 +314,37 @@ protected static boolean isEmpty(LenNode lenNode, SequenceStorage left) {
312314
return lenNode.execute(left) == 0;
313315
}
314316

317+
@InliningCutoff
315318
protected static boolean isBoolean(GetElementType getElementTypeNode, SequenceStorage s) {
316319
return getElementTypeNode.execute(s) == ListStorageType.Boolean;
317320
}
318321

322+
@InliningCutoff
319323
protected static boolean isByte(GetElementType getElementTypeNode, SequenceStorage s) {
320324
return getElementTypeNode.execute(s) == ListStorageType.Byte;
321325
}
322326

327+
@InliningCutoff
323328
protected static boolean isByteLike(GetElementType getElementTypeNode, SequenceStorage s) {
324329
return isByte(getElementTypeNode, s) || isInt(getElementTypeNode, s) || isLong(getElementTypeNode, s);
325330
}
326331

332+
@InliningCutoff
327333
protected static boolean isInt(GetElementType getElementTypeNode, SequenceStorage s) {
328334
return getElementTypeNode.execute(s) == ListStorageType.Int;
329335
}
330336

337+
@InliningCutoff
331338
protected static boolean isLong(GetElementType getElementTypeNode, SequenceStorage s) {
332339
return getElementTypeNode.execute(s) == ListStorageType.Long;
333340
}
334341

342+
@InliningCutoff
335343
protected static boolean isDouble(GetElementType getElementTypeNode, SequenceStorage s) {
336344
return getElementTypeNode.execute(s) == ListStorageType.Double;
337345
}
338346

347+
@InliningCutoff
339348
protected static boolean isObject(GetElementType getElementTypeNode, SequenceStorage s) {
340349
return getElementTypeNode.execute(s) == ListStorageType.Generic;
341350
}
@@ -432,13 +441,10 @@ public abstract static class GetItemNode extends NormalizingNode {
432441

433442
@Child private GetItemScalarNode getItemScalarNode;
434443
@Child private GetItemSliceNode getItemSliceNode;
435-
@Child private PRaiseNode raiseNode;
436-
private final TruffleString keyTypeErrorMessage;
437444
private final BiFunction<SequenceStorage, PythonObjectFactory, Object> factoryMethod;
438445

439-
public GetItemNode(NormalizeIndexNode normalizeIndexNode, TruffleString keyTypeErrorMessage, BiFunction<SequenceStorage, PythonObjectFactory, Object> factoryMethod) {
446+
public GetItemNode(NormalizeIndexNode normalizeIndexNode, BiFunction<SequenceStorage, PythonObjectFactory, Object> factoryMethod) {
440447
super(normalizeIndexNode);
441-
this.keyTypeErrorMessage = keyTypeErrorMessage;
442448
this.factoryMethod = factoryMethod;
443449
}
444450

@@ -462,16 +468,19 @@ protected Object doScalarLong(VirtualFrame frame, SequenceStorage storage, long
462468
return getGetItemScalarNode().execute(storage, normalizeIndex(frame, idx, storage));
463469
}
464470

471+
@InliningCutoff
465472
@Specialization
466473
protected Object doScalarPInt(VirtualFrame frame, SequenceStorage storage, PInt idx) {
467474
return getGetItemScalarNode().execute(storage, normalizeIndex(frame, idx, storage));
468475
}
469476

477+
@InliningCutoff
470478
@Specialization(guards = "!isPSlice(idx)")
471479
protected Object doScalarGeneric(VirtualFrame frame, SequenceStorage storage, Object idx) {
472480
return getGetItemScalarNode().execute(storage, normalizeIndex(frame, idx, storage));
473481
}
474482

483+
@InliningCutoff
475484
@Specialization
476485
protected Object doSlice(VirtualFrame frame, SequenceStorage storage, PSlice slice,
477486
@Cached LenNode lenNode,
@@ -487,11 +496,6 @@ protected Object doSlice(VirtualFrame frame, SequenceStorage storage, PSlice sli
487496
throw new IllegalStateException();
488497
}
489498

490-
@Fallback
491-
protected Object doInvalidKey(@SuppressWarnings("unused") SequenceStorage storage, Object key) {
492-
throw ensureRaiseNode().raise(TypeError, keyTypeErrorMessage, key);
493-
}
494-
495499
private GetItemScalarNode getGetItemScalarNode() {
496500
if (getItemScalarNode == null) {
497501
CompilerDirectives.transferToInterpreterAndInvalidate();
@@ -508,44 +512,20 @@ private GetItemSliceNode getGetItemSliceNode() {
508512
return getItemSliceNode;
509513
}
510514

511-
private PRaiseNode ensureRaiseNode() {
512-
if (raiseNode == null) {
513-
CompilerDirectives.transferToInterpreterAndInvalidate();
514-
raiseNode = insert(PRaiseNode.create());
515-
}
516-
return raiseNode;
517-
}
518-
519515
public static GetItemNode createNotNormalized() {
520-
return GetItemNodeGen.create(null, ErrorMessages.OBJ_INDEX_MUST_BE_INT_OR_SLICES, null);
516+
return GetItemNodeGen.create(null, null);
521517
}
522518

523519
public static GetItemNode create(NormalizeIndexNode normalizeIndexNode) {
524-
return GetItemNodeGen.create(normalizeIndexNode, ErrorMessages.OBJ_INDEX_MUST_BE_INT_OR_SLICES, null);
520+
return GetItemNodeGen.create(normalizeIndexNode, null);
525521
}
526522

527523
public static GetItemNode create() {
528-
return GetItemNodeGen.create(NormalizeIndexNode.create(), ErrorMessages.OBJ_INDEX_MUST_BE_INT_OR_SLICES, null);
529-
}
530-
531-
public static GetItemNode createNotNormalized(TruffleString keyTypeErrorMessage) {
532-
return GetItemNodeGen.create(null, keyTypeErrorMessage, null);
533-
}
534-
535-
public static GetItemNode create(NormalizeIndexNode normalizeIndexNode, TruffleString keyTypeErrorMessage) {
536-
return GetItemNodeGen.create(normalizeIndexNode, keyTypeErrorMessage, null);
537-
}
538-
539-
public static GetItemNode create(TruffleString keyTypeErrorMessage) {
540-
return GetItemNodeGen.create(NormalizeIndexNode.create(), keyTypeErrorMessage, null);
541-
}
542-
543-
public static GetItemNode create(NormalizeIndexNode normalizeIndexNode, TruffleString keyTypeErrorMessage, BiFunction<SequenceStorage, PythonObjectFactory, Object> factoryMethod) {
544-
return GetItemNodeGen.create(normalizeIndexNode, keyTypeErrorMessage, factoryMethod);
524+
return GetItemNodeGen.create(NormalizeIndexNode.create(), null);
545525
}
546526

547527
public static GetItemNode create(NormalizeIndexNode normalizeIndexNode, BiFunction<SequenceStorage, PythonObjectFactory, Object> factoryMethod) {
548-
return GetItemNodeGen.create(normalizeIndexNode, ErrorMessages.OBJ_INDEX_MUST_BE_INT_OR_SLICES, factoryMethod);
528+
return GetItemNodeGen.create(normalizeIndexNode, factoryMethod);
549529
}
550530

551531
}
@@ -682,6 +662,19 @@ protected static Object doMro(MroSequenceStorage storage, int idx) {
682662
return storage.getItemNormalized(idx);
683663
}
684664

665+
@InliningCutoff
666+
@Specialization
667+
protected static Object doNative(NativeSequenceStorage storage, int idx,
668+
@Cached GetNativeItemScalarNode getItem) {
669+
return getItem.execute(storage, idx);
670+
}
671+
}
672+
673+
@GenerateUncached
674+
@ImportStatic(SequenceStorageBaseNode.class)
675+
protected abstract static class GetNativeItemScalarNode extends Node {
676+
public abstract Object execute(NativeSequenceStorage s, int idx);
677+
685678
@Specialization(guards = "isObject(getElementType, storage)", limit = "1")
686679
protected static Object doNativeObject(NativeSequenceStorage storage, int idx,
687680
@CachedLibrary("storage.getPtr()") InteropLibrary lib,
@@ -1134,7 +1127,7 @@ public static SetItemNode create(TruffleString invalidItemErrorMessage) {
11341127
}
11351128

11361129
@GenerateUncached
1137-
@ImportStatic(SequenceStorageBaseNode.class)
1130+
@ImportStatic({SequenceStorageBaseNode.class, PGuards.class})
11381131
public abstract static class SetItemScalarNode extends Node {
11391132

11401133
public abstract void execute(SequenceStorage s, int idx, Object value);
@@ -1151,9 +1144,10 @@ protected static void doByteSimple(ByteSequenceStorage storage, int idx, byte va
11511144
storage.setByteItemNormalized(idx, value);
11521145
}
11531146

1147+
@InliningCutoff
11541148
@Specialization(replaces = "doByteSimple")
11551149
protected static void doByte(ByteSequenceStorage storage, int idx, Object value,
1156-
@Shared("castToByteNode") @Cached CastToByteNode castToByteNode) {
1150+
@Cached CastToByteNode castToByteNode) {
11571151
// TODO: clean this up, we really might need a frame
11581152
storage.setByteItemNormalized(idx, castToByteNode.execute(null, value));
11591153
}
@@ -1168,6 +1162,7 @@ protected static void doIntL(IntSequenceStorage storage, int idx, long value) th
11681162
storage.setIntItemNormalized(idx, PInt.intValueExact(value));
11691163
}
11701164

1165+
@InliningCutoff
11711166
@Specialization(replaces = "doIntL")
11721167
protected static void doIntLOvf(IntSequenceStorage storage, int idx, long value) {
11731168
try {
@@ -1177,7 +1172,8 @@ protected static void doIntLOvf(IntSequenceStorage storage, int idx, long value)
11771172
}
11781173
}
11791174

1180-
@Specialization(guards = "!value.isNative()")
1175+
@InliningCutoff
1176+
@Specialization(guards = "!isNativeWrapper(value)")
11811177
protected static void doInt(IntSequenceStorage storage, int idx, PInt value) {
11821178
try {
11831179
storage.setIntItemNormalized(idx, value.intValueExact());
@@ -1196,7 +1192,8 @@ protected static void doLong(LongSequenceStorage storage, int idx, int value) {
11961192
storage.setLongItemNormalized(idx, value);
11971193
}
11981194

1199-
@Specialization(guards = "!value.isNative()")
1195+
@InliningCutoff
1196+
@Specialization(guards = "!isNativeWrapper(value)")
12001197
protected static void doLong(LongSequenceStorage storage, int idx, PInt value) {
12011198
try {
12021199
storage.setLongItemNormalized(idx, value.longValueExact());
@@ -1215,11 +1212,34 @@ protected static void doObject(ObjectSequenceStorage storage, int idx, Object va
12151212
storage.setItemNormalized(idx, value);
12161213
}
12171214

1215+
@InliningCutoff
1216+
@Specialization
1217+
protected static void doNative(NativeSequenceStorage storage, int idx, Object value,
1218+
@Cached SetNativeItemScalarNode setItem) {
1219+
setItem.execute(storage, idx, value);
1220+
}
1221+
1222+
@Fallback
1223+
@SuppressWarnings("unused")
1224+
static void doError(SequenceStorage s, int idx, Object item) {
1225+
throw new SequenceStoreException(item);
1226+
}
1227+
1228+
public static SetItemScalarNode create() {
1229+
return SetItemScalarNodeGen.create();
1230+
}
1231+
}
1232+
1233+
@GenerateUncached
1234+
@ImportStatic(SequenceStorageBaseNode.class)
1235+
protected abstract static class SetNativeItemScalarNode extends Node {
1236+
public abstract void execute(NativeSequenceStorage s, int idx, Object value);
1237+
12181238
@Specialization(guards = "isByteStorage(storage)")
12191239
protected static void doNativeByte(NativeSequenceStorage storage, int idx, Object value,
12201240
@Shared("raiseNode") @Cached PRaiseNode raiseNode,
12211241
@Shared("lib") @CachedLibrary(limit = "1") InteropLibrary lib,
1222-
@Shared("castToByteNode") @Cached CastToByteNode castToByteNode) {
1242+
@Cached CastToByteNode castToByteNode) {
12231243
try {
12241244
lib.writeArrayElement(storage.getPtr(), idx, castToByteNode.execute(null, value));
12251245
} catch (UnsupportedMessageException | UnsupportedTypeException | InvalidArrayIndexException e) {
@@ -1239,22 +1259,12 @@ protected static void doNative(NativeSequenceStorage storage, int idx, Object va
12391259
}
12401260
}
12411261

1242-
@Fallback
1243-
@SuppressWarnings("unused")
1244-
static void doError(SequenceStorage s, int idx, Object item) {
1245-
throw new SequenceStoreException(item);
1246-
}
1247-
12481262
private static Object verifyValue(NativeSequenceStorage storage, Object item, VerifyNativeItemNode verifyNativeItemNode) {
12491263
if (verifyNativeItemNode.execute(storage.getElementType(), item)) {
12501264
return item;
12511265
}
12521266
throw new SequenceStoreException(item);
12531267
}
1254-
1255-
public static SetItemScalarNode create() {
1256-
return SetItemScalarNodeGen.create();
1257-
}
12581268
}
12591269

12601270
@GenerateUncached

graalpython/com.oracle.graal.python/src/com/oracle/graal/python/builtins/objects/ints/PInt.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,6 @@
3131

3232
import com.oracle.graal.python.builtins.PythonBuiltinClassType;
3333
import com.oracle.graal.python.builtins.modules.SysModuleBuiltins;
34-
import com.oracle.graal.python.builtins.objects.cext.capi.PythonNativeWrapperLibrary;
3534
import com.oracle.graal.python.builtins.objects.object.PythonBuiltinObject;
3635
import com.oracle.graal.python.builtins.objects.type.PythonBuiltinClass;
3736
import com.oracle.graal.python.nodes.ErrorMessages;
@@ -541,10 +540,6 @@ public static BigInteger abs(BigInteger value) {
541540
return value.abs();
542541
}
543542

544-
public boolean isNative() {
545-
return getNativeWrapper() != null && PythonNativeWrapperLibrary.getUncached().isNative(getNativeWrapper());
546-
}
547-
548543
@TruffleBoundary
549544
public BigInteger multiply(BigInteger other) {
550545
return this.value.multiply(other);

0 commit comments

Comments
 (0)