Skip to content

Commit fb9f164

Browse files
committed
Conditionally explode loop when loop bound <= 32
1 parent b7dbd07 commit fb9f164

File tree

1 file changed

+166
-19
lines changed

1 file changed

+166
-19
lines changed

Diff for: graalpython/com.oracle.graal.python/src/com/oracle/graal/python/nodes/bytecode_dsl/PBytecodeDSLRootNode.java

+166-19
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,7 @@
252252
@ShortCircuitOperation(name = "PrimitiveBoolOr", booleanConverter = PBytecodeDSLRootNode.BooleanIdentity.class, operator = Operator.OR_RETURN_CONVERTED)
253253
@SuppressWarnings("unused")
254254
public abstract class PBytecodeDSLRootNode extends PRootNode implements BytecodeRootNode {
255+
private static final int EXPLODE_LOOP_THRESHOLD = 32;
255256

256257
@Child protected transient PythonObjectFactory factory = PythonObjectFactory.create();
257258
@Child private transient CalleeContext calleeContext = CalleeContext.create();
@@ -1474,7 +1475,6 @@ public static PList perform(Object[] elements,
14741475
@Operation
14751476
public static final class MakeSet {
14761477
@Specialization
1477-
@ExplodeLoop
14781478
public static PSet perform(VirtualFrame frame, Object[] elements,
14791479
@Bind("$root") PBytecodeDSLRootNode rootNode,
14801480
@Bind("this") Node node,
@@ -1485,11 +1485,26 @@ public static PSet perform(VirtualFrame frame, Object[] elements,
14851485
assert elements.length == length;
14861486

14871487
PSet set = rootNode.factory.createSet();
1488+
if (length <= EXPLODE_LOOP_THRESHOLD) {
1489+
doExploded(frame, set, elements, length, addNode, setItemNode);
1490+
} else {
1491+
doRegular(frame, set, elements, length, addNode, setItemNode);
1492+
}
1493+
return set;
1494+
}
1495+
1496+
@ExplodeLoop
1497+
private static void doExploded(VirtualFrame frame, PSet set, Object[] elements, int length, SetNodes.AddNode addNode, HashingCollectionNodes.SetItemNode setItemNode) {
1498+
CompilerAsserts.partialEvaluationConstant(length);
14881499
for (int i = 0; i < length; i++) {
14891500
SetNodes.AddNode.add(frame, set, elements[i], addNode, setItemNode);
14901501
}
1502+
}
14911503

1492-
return set;
1504+
private static void doRegular(VirtualFrame frame, PSet set, Object[] elements, int length, SetNodes.AddNode addNode, HashingCollectionNodes.SetItemNode setItemNode) {
1505+
for (int i = 0; i < length; i++) {
1506+
SetNodes.AddNode.add(frame, set, elements[i], addNode, setItemNode);
1507+
}
14931508
}
14941509
}
14951510

@@ -1505,22 +1520,43 @@ public static PSet perform(VirtualFrame frame,
15051520
@Operation
15061521
public static final class MakeFrozenSet {
15071522
@Specialization
1508-
@ExplodeLoop
1509-
public static PFrozenSet doFrozenSet(VirtualFrame frame, @Variadic Object[] elements,
1523+
public static PFrozenSet perform(VirtualFrame frame, @Variadic Object[] elements,
15101524
@Cached(value = "elements.length", neverDefault = false) int length,
15111525
@Cached HashingStorageSetItem hashingStorageLibrary,
15121526
@Bind("$root") PBytecodeDSLRootNode rootNode,
15131527
@Bind("this") Node inliningTarget) {
15141528
// TODO (GR-52217): make length a DSL constant.
15151529
assert elements.length == length;
15161530

1531+
HashingStorage setStorage;
1532+
if (length <= EXPLODE_LOOP_THRESHOLD) {
1533+
setStorage = doExploded(frame, inliningTarget, elements, length, hashingStorageLibrary);
1534+
} else {
1535+
setStorage = doRegular(frame, inliningTarget, elements, length, hashingStorageLibrary);
1536+
}
1537+
return rootNode.factory.createFrozenSet(setStorage);
1538+
}
1539+
1540+
@ExplodeLoop
1541+
private static HashingStorage doExploded(VirtualFrame frame, Node inliningTarget, Object[] elements, int length, HashingStorageSetItem hashingStorageLibrary) {
1542+
CompilerAsserts.partialEvaluationConstant(length);
15171543
HashingStorage setStorage = EmptyStorage.INSTANCE;
15181544
for (int i = 0; i < length; ++i) {
15191545
Object o = elements[i];
15201546
setStorage = hashingStorageLibrary.execute(frame, inliningTarget, setStorage, o, PNone.NONE);
15211547
}
1522-
return rootNode.factory.createFrozenSet(setStorage);
1548+
return setStorage;
1549+
}
1550+
1551+
private static HashingStorage doRegular(VirtualFrame frame, Node inliningTarget, Object[] elements, int length, HashingStorageSetItem hashingStorageLibrary) {
1552+
HashingStorage setStorage = EmptyStorage.INSTANCE;
1553+
for (int i = 0; i < length; ++i) {
1554+
Object o = elements[i];
1555+
setStorage = hashingStorageLibrary.execute(frame, inliningTarget, setStorage, o, PNone.NONE);
1556+
}
1557+
return setStorage;
15231558
}
1559+
15241560
}
15251561

15261562
@Operation
@@ -1534,13 +1570,24 @@ public static PList perform(@Bind("$root") PBytecodeDSLRootNode rootNode) {
15341570
@Operation
15351571
public static final class MakeTuple {
15361572
@Specialization
1537-
@ExplodeLoop
15381573
public static Object perform(@Variadic Object[] elements,
15391574
@Cached(value = "elements.length", neverDefault = false) int length,
15401575
@Bind("$root") PBytecodeDSLRootNode rootNode) {
15411576
// TODO (GR-52217): make length a DSL constant.
15421577
assert elements.length == length;
15431578

1579+
Object[] elts;
1580+
if (length <= EXPLODE_LOOP_THRESHOLD) {
1581+
elts = doExploded(elements, length);
1582+
} else {
1583+
elts = doRegular(elements, length);
1584+
}
1585+
return rootNode.factory.createTuple(elts);
1586+
}
1587+
1588+
@ExplodeLoop
1589+
private static Object[] doExploded(Object[] elements, int length) {
1590+
CompilerAsserts.partialEvaluationConstant(length);
15441591
int totalLength = 0;
15451592
for (int i = 0; i < length; i++) {
15461593
totalLength += ((Object[]) elements[i]).length;
@@ -1554,8 +1601,24 @@ public static Object perform(@Variadic Object[] elements,
15541601
System.arraycopy(arr, 0, elts, idx, len);
15551602
idx += len;
15561603
}
1604+
return elts;
1605+
}
15571606

1558-
return rootNode.factory.createTuple(elts);
1607+
private static Object[] doRegular(Object[] elements, int length) {
1608+
int totalLength = 0;
1609+
for (int i = 0; i < length; i++) {
1610+
totalLength += ((Object[]) elements[i]).length;
1611+
}
1612+
1613+
Object[] elts = new Object[totalLength];
1614+
int idx = 0;
1615+
for (int i = 0; i < length; i++) {
1616+
Object[] arr = (Object[]) elements[i];
1617+
int len = arr.length;
1618+
System.arraycopy(arr, 0, elts, idx, len);
1619+
idx += len;
1620+
}
1621+
return elts;
15591622
}
15601623
}
15611624

@@ -1697,13 +1760,31 @@ public static Object doGeneric(Object start, Object end, Object step,
16971760
@Operation
16981761
public static final class MakeKeywords {
16991762
@Specialization
1700-
@ExplodeLoop
17011763
public static PKeyword[] perform(@Variadic Object[] keysAndValues,
17021764
@Cached(value = "keysAndValues.length", neverDefault = true) int length) {
17031765
// TODO (GR-52217): make length a DSL constant.
17041766
assert keysAndValues.length == length;
17051767
assert length % 2 == 0;
17061768

1769+
if (length <= EXPLODE_LOOP_THRESHOLD) {
1770+
return doExploded(keysAndValues, length);
1771+
} else {
1772+
return doRegular(keysAndValues, length);
1773+
}
1774+
}
1775+
1776+
@ExplodeLoop
1777+
private static PKeyword[] doExploded(Object[] keysAndValues, int length) {
1778+
CompilerAsserts.partialEvaluationConstant(length);
1779+
PKeyword[] result = new PKeyword[length / 2];
1780+
for (int i = 0; i < length; i += 2) {
1781+
CompilerAsserts.compilationConstant(keysAndValues[i]);
1782+
result[i / 2] = new PKeyword((TruffleString) keysAndValues[i], keysAndValues[i + 1]);
1783+
}
1784+
return result;
1785+
}
1786+
1787+
private static PKeyword[] doRegular(Object[] keysAndValues, int length) {
17071788
PKeyword[] result = new PKeyword[length / 2];
17081789
for (int i = 0; i < length; i += 2) {
17091790
CompilerAsserts.compilationConstant(keysAndValues[i]);
@@ -1727,7 +1808,6 @@ public static PKeyword[] perform(Object sourceCollection,
17271808
@Operation
17281809
public static final class MakeDict {
17291810
@Specialization
1730-
@ExplodeLoop
17311811
public static PDict perform(VirtualFrame frame, @Variadic Object[] keysAndValues,
17321812
@Bind("$root") PBytecodeDSLRootNode rootNode,
17331813
@Cached(value = "keysAndValues.length", neverDefault = true) int length,
@@ -1736,6 +1816,17 @@ public static PDict perform(VirtualFrame frame, @Variadic Object[] keysAndValues
17361816
assert keysAndValues.length == length;
17371817

17381818
PDict dict = rootNode.factory.createDict();
1819+
if (length <= EXPLODE_LOOP_THRESHOLD) {
1820+
doExploded(frame, keysAndValues, length, updateNode, dict);
1821+
} else {
1822+
doRegular(frame, keysAndValues, length, updateNode, dict);
1823+
}
1824+
return dict;
1825+
}
1826+
1827+
@ExplodeLoop
1828+
private static void doExploded(VirtualFrame frame, Object[] keysAndValues, int length, DictNodes.UpdateNode updateNode, PDict dict) {
1829+
CompilerAsserts.partialEvaluationConstant(length);
17391830
for (int i = 0; i < length; i += 2) {
17401831
Object key = keysAndValues[i];
17411832
Object value = keysAndValues[i + 1];
@@ -1745,8 +1836,18 @@ public static PDict perform(VirtualFrame frame, @Variadic Object[] keysAndValues
17451836
dict.setItem(key, value);
17461837
}
17471838
}
1839+
}
17481840

1749-
return dict;
1841+
private static void doRegular(VirtualFrame frame, Object[] keysAndValues, int length, DictNodes.UpdateNode updateNode, PDict dict) {
1842+
for (int i = 0; i < length; i += 2) {
1843+
Object key = keysAndValues[i];
1844+
Object value = keysAndValues[i + 1];
1845+
if (key == PNone.NO_VALUE) {
1846+
updateNode.execute(frame, dict, value);
1847+
} else {
1848+
dict.setItem(key, value);
1849+
}
1850+
}
17501851
}
17511852
}
17521853

@@ -2569,18 +2670,27 @@ public static PCell[] doLoadClosure(VirtualFrame frame) {
25692670

25702671
@Operation
25712672
public static final class StoreRange {
2572-
@Specialization(guards = {"locals.length <= 32"})
2673+
@Specialization
2674+
public static void perform(VirtualFrame frame, Object[] values,
2675+
LocalSetterRange locals) {
2676+
if (values.length <= EXPLODE_LOOP_THRESHOLD) {
2677+
doExploded(frame, values, locals);
2678+
} else {
2679+
doRegular(frame, values, locals);
2680+
}
2681+
}
2682+
25732683
@ExplodeLoop
2574-
public static void doExploded(VirtualFrame frame, Object[] values,
2684+
private static void doExploded(VirtualFrame frame, Object[] values,
25752685
LocalSetterRange locals) {
2686+
CompilerAsserts.partialEvaluationConstant(values.length);
25762687
assert values.length == locals.getLength();
25772688
for (int i = 0; i < locals.length; i++) {
25782689
locals.setObject(frame, i, values[i]);
25792690
}
25802691
}
25812692

2582-
@Specialization(replaces = "doExploded")
2583-
public static void doRegular(VirtualFrame frame, Object[] values,
2693+
private static void doRegular(VirtualFrame frame, Object[] values,
25842694
LocalSetterRange locals) {
25852695
assert values.length == locals.getLength();
25862696
for (int i = 0; i < locals.length; i++) {
@@ -2603,12 +2713,21 @@ public static PCell[] doMakeCellArray(@Variadic Object[] cells) {
26032713
@Operation
26042714
public static final class Unstar {
26052715
@Specialization
2606-
@ExplodeLoop
2607-
public static Object[] doUnstar(@Variadic Object[] values,
2716+
public static Object[] perform(@Variadic Object[] values,
26082717
@Cached(value = "values.length", neverDefault = false) int length) {
26092718
// TODO (GR-52217): make length a DSL constant.
26102719
assert values.length == length;
26112720

2721+
if (length <= EXPLODE_LOOP_THRESHOLD) {
2722+
return doExploded(values, length);
2723+
} else {
2724+
return doRegular(values, length);
2725+
}
2726+
}
2727+
2728+
@ExplodeLoop
2729+
private static Object[] doExploded(Object[] values, int length) {
2730+
CompilerAsserts.partialEvaluationConstant(length);
26122731
int totalLength = 0;
26132732
for (int i = 0; i < length; i++) {
26142733
totalLength += ((Object[]) values[i]).length;
@@ -2620,7 +2739,21 @@ public static Object[] doUnstar(@Variadic Object[] values,
26202739
System.arraycopy(values[i], 0, result, idx, nl);
26212740
idx += nl;
26222741
}
2742+
return result;
2743+
}
26232744

2745+
private static Object[] doRegular(Object[] values, int length) {
2746+
int totalLength = 0;
2747+
for (int i = 0; i < length; i++) {
2748+
totalLength += ((Object[]) values[i]).length;
2749+
}
2750+
Object[] result = new Object[totalLength];
2751+
int idx = 0;
2752+
for (int i = 0; i < length; i++) {
2753+
int nl = ((Object[]) values[i]).length;
2754+
System.arraycopy(values[i], 0, result, idx, nl);
2755+
idx += nl;
2756+
}
26242757
return result;
26252758
}
26262759
}
@@ -3112,8 +3245,7 @@ public static void doExceptional(VirtualFrame frame,
31123245
@Operation
31133246
public static final class BuildString {
31143247
@Specialization
3115-
@ExplodeLoop
3116-
public static Object doBuildString(@Variadic Object[] strings,
3248+
public static Object perform(@Variadic Object[] strings,
31173249
@Cached(value = "strings.length", neverDefault = false) int length,
31183250
@Cached TruffleStringBuilder.AppendStringNode appendNode,
31193251
@Cached TruffleStringBuilder.ToStringNode toString) {
@@ -3122,11 +3254,26 @@ public static Object doBuildString(@Variadic Object[] strings,
31223254

31233255
TruffleStringBuilder tsb = TruffleStringBuilder.create(PythonUtils.TS_ENCODING);
31243256

3257+
if (length <= EXPLODE_LOOP_THRESHOLD) {
3258+
doExploded(strings, length, appendNode, tsb);
3259+
} else {
3260+
doRegular(strings, length, appendNode, tsb);
3261+
}
3262+
return toString.execute(tsb);
3263+
}
3264+
3265+
@ExplodeLoop
3266+
private static void doExploded(Object[] strings, int length, TruffleStringBuilder.AppendStringNode appendNode, TruffleStringBuilder tsb) {
3267+
CompilerAsserts.partialEvaluationConstant(length);
31253268
for (int i = 0; i < length; i++) {
31263269
appendNode.execute(tsb, (TruffleString) strings[i]);
31273270
}
3271+
}
31283272

3129-
return toString.execute(tsb);
3273+
private static void doRegular(Object[] strings, int length, TruffleStringBuilder.AppendStringNode appendNode, TruffleStringBuilder tsb) {
3274+
for (int i = 0; i < length; i++) {
3275+
appendNode.execute(tsb, (TruffleString) strings[i]);
3276+
}
31303277
}
31313278
}
31323279

0 commit comments

Comments
 (0)