Skip to content

Commit 245dc7f

Browse files
chumerDSouzaM
authored andcommitted
Implement automatic quickening for boxing elimination.
1 parent af36a32 commit 245dc7f

File tree

3 files changed

+77
-32
lines changed

3 files changed

+77
-32
lines changed

truffle/src/com.oracle.truffle.api.bytecode.test/src/com/oracle/truffle/api/bytecode/test/BoxingEliminationTest.java

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -397,13 +397,11 @@ protected BoxingEliminationTestRootNode(TruffleLanguage<?> language, FrameDescri
397397
@Operation
398398
static final class Add {
399399
@Specialization
400-
@ForceQuickening
401400
public static long doLong(long lhs, long rhs) {
402401
return lhs + rhs;
403402
}
404403

405404
@Specialization
406-
@ForceQuickening
407405
public static int doInt(int lhs, int rhs) {
408406
return lhs + rhs;
409407
}
@@ -419,21 +417,18 @@ public static String doString(String lhs, String rhs) {
419417
static final class Abs {
420418

421419
@Specialization(guards = "v >= 0")
422-
@ForceQuickening
423420
@ForceQuickening("positiveAndNegative")
424421
public static long doGreaterZero(long v) {
425422
return v;
426423
}
427424

428425
@Specialization(guards = "v < 0")
429-
@ForceQuickening
430426
@ForceQuickening("positiveAndNegative")
431427
public static long doLessThanZero(long v) {
432428
return -v;
433429
}
434430

435431
@Specialization
436-
@ForceQuickening
437432
public static int doInt(int v) {
438433
return -v;
439434
}

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/model/BytecodeDSLModel.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -431,6 +431,10 @@ public boolean isBoxingEliminated(TypeMirror mirror) {
431431
return boxingEliminatedTypes.contains(mirror);
432432
}
433433

434+
public OperationModel getOperationByName(String name) {
435+
return operations.get(name);
436+
}
437+
434438
public Collection<OperationModel> getOperations() {
435439
return operations.values();
436440
}

truffle/src/com.oracle.truffle.dsl.processor/src/com/oracle/truffle/dsl/processor/bytecode/parser/BytecodeDSLParser.java

Lines changed: 73 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,7 @@ private void parseBytecodeDSLModel(TypeElement typeElement, BytecodeDSLModel mod
202202
model.enableYield = ElementUtils.getAnnotationValue(Boolean.class, generateBytecodeMirror, "enableYield");
203203
model.storeBciInFrame = ElementUtils.getAnnotationValue(Boolean.class, generateBytecodeMirror, "storeBciInFrame");
204204
model.enableQuickening = ElementUtils.getAnnotationValue(Boolean.class, generateBytecodeMirror, "enableQuickening");
205-
model.specializationDebugListener = types.SpecializationDebugListener == null ? false : ElementUtils.isAssignable(typeElement.asType(), types.SpecializationDebugListener);
205+
model.specializationDebugListener = types.BytecodeDebugListener == null ? false : ElementUtils.isAssignable(typeElement.asType(), types.BytecodeDebugListener);
206206
model.addDefault();
207207

208208
// check basic declaration properties
@@ -523,45 +523,91 @@ private void parseBytecodeDSLModel(TypeElement typeElement, BytecodeDSLModel mod
523523
if (operation.kind != OperationKind.CUSTOM_SIMPLE) {
524524
continue;
525525
}
526-
InstructionModel instruction = operation.instruction;
527-
boolean autoQuicken = false;
528-
for (int valueIndex = 0; valueIndex < instruction.signature.valueCount; valueIndex++) {
529-
TypeMirror type = instruction.signature.getSpecializedType(valueIndex);
526+
InstructionModel genericInstruction = operation.instruction;
527+
boolean autoOperationQuicken = false;
528+
for (int valueIndex = 0; valueIndex < genericInstruction.signature.valueCount; valueIndex++) {
529+
TypeMirror type = genericInstruction.signature.getSpecializedType(valueIndex);
530530
if (model.isBoxingEliminated(type)) {
531-
autoQuicken = true;
531+
autoOperationQuicken = true;
532532
break;
533533
}
534534
}
535-
if (autoQuicken) {
535+
if (autoOperationQuicken) {
536536
List<String> allIds = operation.instruction.nodeData.getSpecializations().stream().filter((s) -> s.getMethod() != null).map((s) -> s.getMethodName()).toList();
537537
quickenings.add(new QuickenDecision(operation.name, new HashSet<>(allIds)));
538538
}
539+
540+
boolean genericReturnBoxingElimanted = model.isBoxingEliminated(genericInstruction.signature.returnType);
541+
542+
if (operation.instruction.nodeData.getSpecializations().size() > 1) {
543+
for (SpecializationData specialization : operation.instruction.nodeData.getSpecializations()) {
544+
if (specialization.getMethod() == null || specialization.isFallback()) {
545+
continue;
546+
}
547+
boolean autoQuickenSpecialization = false;
548+
if (model.isBoxingEliminated(specialization.getMethod().getReturnType()) && //
549+
/*
550+
* Unexpected result specializations effectively have an
551+
* Object return type. This could probably be directly
552+
* handled by the bytecode DSL.
553+
*/
554+
!specialization.hasUnexpectedResultRewrite() && //
555+
/*
556+
* If the instruction signature is already boxing eliminated
557+
* we do not need to automatically quicken each
558+
* specialization for its return type. This avoids automatic
559+
* quickening of specializations if only the return type
560+
* needs quickening.
561+
*/
562+
!genericReturnBoxingElimanted) {
563+
autoQuickenSpecialization = true;
564+
}
565+
for (int valueIndex = 0; valueIndex < genericInstruction.signature.valueCount; valueIndex++) {
566+
TypeMirror type = specialization.getSignatureParameters().get(valueIndex).getType();
567+
if (model.isBoxingEliminated(type)) {
568+
autoQuickenSpecialization = true;
569+
break;
570+
}
571+
}
572+
573+
if (autoQuickenSpecialization) {
574+
List<String> allIds = List.of(specialization.getMethodName());
575+
quickenings.add(new QuickenDecision(operation.name, new HashSet<>(allIds)));
576+
}
577+
}
578+
}
539579
}
540580
}
541581

542-
Set<QuickenDecision> uniqueQuickenings = new LinkedHashSet<>(quickenings);
543-
for (QuickenDecision decision : uniqueQuickenings) {
544-
OperationModel operation = null;
545-
for (OperationModel current : model.getOperations()) {
546-
if (current.name.equals(decision.operation())) {
547-
operation = current;
548-
break;
582+
Map<String, List<QuickenDecision>> quickeningsByOperation = quickenings.stream().distinct().collect(Collectors.groupingBy(QuickenDecision::operation));
583+
for (var groupedDecision : quickeningsByOperation.entrySet()) {
584+
String operationName = groupedDecision.getKey();
585+
List<QuickenDecision> decisions = groupedDecision.getValue();
586+
OperationModel operation = model.getOperationByName(operationName);
587+
List<List<SpecializationData>> resolvedQuickenings = decisions.stream().map((d) -> operation.instruction.nodeData.findSpecializationsByName(d.specializations())).sorted(
588+
(s0, s1) -> {
589+
if (s0.size() != s1.size()) {
590+
// sort by size we want to check single specialization
591+
// quickenings first
592+
return Integer.compare(s0.size(), s1.size());
593+
}
594+
return 0;
595+
}).toList();
596+
597+
for (List<SpecializationData> includedSpecializations : resolvedQuickenings) {
598+
String name;
599+
if (includedSpecializations.size() == operation.instruction.nodeData.getSpecializations().size()) {
600+
// all specializations included
601+
name = "#";
602+
} else {
603+
name = String.join("#", includedSpecializations.stream().map((s) -> s.getId()).toList());
549604
}
550-
}
551605

552-
List<SpecializationData> includedSpecializations = operation.instruction.nodeData.findSpecializationsByName(decision.specializations());
553-
String name;
554-
if (includedSpecializations.size() == operation.instruction.nodeData.getSpecializations().size()) {
555-
// all specializations included
556-
name = "#";
557-
} else {
558-
name = String.join("#", includedSpecializations.stream().map((s) -> s.getId()).toList());
606+
Signature signature = CustomOperationParser.createPolymorphicSignature(includedSpecializations.stream().map(s -> s.getMethod()).toList(), null);
607+
InstructionModel baseInstruction = operation.instruction;
608+
InstructionModel quickenedInstruction = model.quickenInstruction(baseInstruction, signature, ElementUtils.firstLetterUpperCase(name));
609+
quickenedInstruction.filteredSpecializations = includedSpecializations;
559610
}
560-
561-
Signature signature = CustomOperationParser.createPolymorphicSignature(includedSpecializations.stream().map(s -> s.getMethod()).toList(), null);
562-
InstructionModel baseInstruction = operation.instruction;
563-
InstructionModel quickenedInstruction = model.quickenInstruction(baseInstruction, signature, ElementUtils.firstLetterUpperCase(name));
564-
quickenedInstruction.filteredSpecializations = includedSpecializations;
565611
}
566612

567613
if (model.usesBoxingElimination()) {

0 commit comments

Comments
 (0)