use of com.oracle.truffle.dsl.processor.model.GuardExpression in project graal by oracle.
the class FlatNodeGenFactory method createMethodGuardCheck.
private List<IfTriple> createMethodGuardCheck(FrameState frameState, SpecializationGroup group, List<GuardExpression> guardExpressions, NodeExecutionMode mode) {
List<IfTriple> triples = new ArrayList<>();
for (GuardExpression guard : guardExpressions) {
if (mode.isSlowPath() && !guard.isConstantTrueInSlowPath(context)) {
CodeTreeBuilder builder = new CodeTreeBuilder(null);
boolean guardStateBit = false;
List<IfTriple> innerTriples = new ArrayList<>();
if (guardNeedsStateBit(group.getSpecialization(), guard)) {
if (group.getSpecialization() == null) {
throw new AssertionError();
}
builder.startIf().tree(state.createNotContains(frameState, new Object[] { guard })).end().startBlock();
innerTriples.addAll(initializeSpecializationClass(frameState, group.getSpecialization()));
innerTriples.addAll(persistSpecializationClass(frameState, group.getSpecialization()));
guardStateBit = true;
}
innerTriples.addAll(initializeCaches(frameState, group, group.getSpecialization().getBoundCaches(guard.getExpression()), mode, !guardStateBit, guardStateBit));
innerTriples.addAll(initializeCasts(frameState, group, guard.getExpression(), mode));
IfTriple.materialize(builder, innerTriples, true);
if (guardStateBit) {
builder.tree(state.createSet(frameState, new Object[] { guard }, true, true));
builder.end();
}
triples.add(new IfTriple(builder.build(), null, null));
} else if (mode.isGuardFallback()) {
triples.addAll(initializeCasts(frameState, group, guard.getExpression(), mode));
}
triples.add(createMethodGuardCheck(frameState, group.getSpecialization(), guard, mode));
}
return triples;
}
use of com.oracle.truffle.dsl.processor.model.GuardExpression in project graal by oracle.
the class FlatNodeGenFactory method getGuardThatNeedsStateBit.
private static GuardExpression getGuardThatNeedsStateBit(SpecializationData specialization, GuardExpression guard) {
if (guardNeedsStateBit(specialization, guard)) {
return guard;
}
List<GuardExpression> guards = specialization.getGuards();
int index = guards.indexOf(guard);
if (index < 0) {
throw new AssertionError("guard must be contained");
}
for (int i = index - 1; i >= 0; i--) {
GuardExpression otherGuard = guards.get(i);
if (guardNeedsStateBit(specialization, otherGuard)) {
return otherGuard;
}
}
return null;
}
use of com.oracle.truffle.dsl.processor.model.GuardExpression in project graal by oracle.
the class FlatNodeGenFactory method visitSpecializationGroup.
private CodeTree visitSpecializationGroup(CodeTreeBuilder parent, SpecializationGroup group, ExecutableTypeData forType, FrameState frameState, List<SpecializationData> allowedSpecializations, NodeExecutionMode mode) {
CodeTreeBuilder builder = parent.create();
boolean hasFallthrough = false;
boolean hasImplicitCast = false;
List<IfTriple> cachedTriples = new ArrayList<>();
for (TypeGuard guard : group.getTypeGuards()) {
IfTriple triple = createTypeCheckOrCast(frameState, group, guard, mode, false, true);
if (triple != null) {
cachedTriples.add(triple);
}
hasImplicitCast = hasImplicitCast || node.getTypeSystem().hasImplicitSourceTypes(guard.getType());
if (!mode.isGuardFallback()) {
triple = createTypeCheckOrCast(frameState, group, guard, mode, true, true);
if (triple != null) {
cachedTriples.add(triple);
}
}
}
SpecializationData specialization = group.getSpecialization();
SpecializationData[] specializations = group.collectSpecializations().toArray(new SpecializationData[0]);
List<GuardExpression> guardExpressions = new ArrayList<>(group.getGuards());
// out of the loop.
if (specialization != null && specialization.hasMultipleInstances()) {
List<GuardExpression> unboundGuards = new ArrayList<>();
for (GuardExpression guard : guardExpressions) {
if (!specialization.isGuardBoundWithCache(guard)) {
unboundGuards.add(guard);
} else {
// we need to stop as we need to ensure guard execution order
break;
}
}
cachedTriples.addAll(createMethodGuardCheck(frameState, group, unboundGuards, mode));
guardExpressions.removeAll(unboundGuards);
}
boolean useSpecializationClass = specialization != null && useSpecializationClass(specialization);
if (mode.isFastPath()) {
int ifCount = 0;
final boolean stateGuaranteed = group.isLast() && allowedSpecializations != null && allowedSpecializations.size() == 1 && group.getAllSpecializations().size() == allowedSpecializations.size();
if ((!group.isEmpty() || specialization != null)) {
CodeTree stateCheck = state.createContains(frameState, specializations);
CodeTree stateGuard = null;
CodeTree assertCheck = null;
if (stateGuaranteed) {
assertCheck = CodeTreeBuilder.createBuilder().startAssert().tree(stateCheck).end().build();
} else {
stateGuard = stateCheck;
}
cachedTriples.add(0, new IfTriple(null, stateGuard, assertCheck));
}
ifCount += IfTriple.materialize(builder, IfTriple.optimize(cachedTriples), false);
// reset current triples
cachedTriples = new ArrayList<>();
String specializationLocalName = null;
if (useSpecializationClass) {
specializationLocalName = createSpecializationLocalName(specialization);
builder.tree(loadSpecializationClass(frameState, specialization));
if (specialization.getMaximumNumberOfInstances() > 1) {
builder.startWhile();
} else {
builder.startIf();
}
builder.string(specializationLocalName, " != null");
builder.end();
builder.startBlock();
ifCount++;
}
if (specialization != null) {
if (!specialization.getAssumptionExpressions().isEmpty()) {
builder.tree(createFastPathAssumptionCheck(builder, specialization, forType, frameState));
}
}
cachedTriples = createMethodGuardCheck(frameState, group, guardExpressions, mode);
int innerIfCount = IfTriple.materialize(builder, IfTriple.optimize(cachedTriples), false);
SpecializationGroup prev = null;
for (SpecializationGroup child : group.getChildren()) {
if (prev != null && !prev.hasFallthrough()) {
break;
}
builder.tree(visitSpecializationGroup(builder, child, forType, frameState.copy(), allowedSpecializations, mode));
}
if (specialization != null && (prev == null || prev.hasFallthrough())) {
builder.tree(createFastPathExecute(builder, forType, specialization, frameState));
}
builder.end(innerIfCount);
hasFallthrough |= innerIfCount > 0;
if (useSpecializationClass && specialization.getMaximumNumberOfInstances() > 1) {
String name = createSpecializationLocalName(specialization);
builder.startStatement().string(name, " = ", name, ".next_").end();
}
builder.end(ifCount);
hasFallthrough |= ifCount > 0;
} else if (mode.isSlowPath()) {
if (specialization != null && mayBeExcluded(specialization)) {
CodeTree excludeCheck = exclude.createNotContains(frameState, specializations);
cachedTriples.add(0, new IfTriple(null, excludeCheck, null));
}
int outerIfCount = 0;
if (specialization == null) {
cachedTriples.addAll(createMethodGuardCheck(frameState, group, guardExpressions, mode));
outerIfCount += IfTriple.materialize(builder, IfTriple.optimize(cachedTriples), false);
SpecializationGroup prev = null;
for (SpecializationGroup child : group.getChildren()) {
if (prev != null && !prev.hasFallthrough()) {
break;
}
builder.tree(visitSpecializationGroup(builder, child, forType, frameState.copy(), allowedSpecializations, mode));
prev = child;
}
} else {
outerIfCount += IfTriple.materialize(builder, IfTriple.optimize(cachedTriples), false);
String countName = specialization != null ? "count" + specialization.getIndex() + "_" : null;
boolean needsDuplicationCheck = specialization.isGuardBindsCache() || specialization.hasMultipleInstances();
boolean useDuplicateFlag = specialization.isGuardBindsCache() && !specialization.hasMultipleInstances();
String duplicateFoundName = specialization.getId() + "_duplicateFound_";
int innerIfCount = 0;
String specializationLocalName = createSpecializationLocalName(specialization);
if (needsDuplicationCheck) {
builder.tree(createDuplicationCheck(builder, frameState, group, guardExpressions, useDuplicateFlag, countName, duplicateFoundName, specializationLocalName));
builder.startIf();
if (useDuplicateFlag) {
// we reuse the specialization class local name instead of a duplicate found
// name
builder.string("!", duplicateFoundName);
} else {
builder.string(createSpecializationLocalName(specialization), " == null");
}
builder.end().startBlock();
innerIfCount++;
}
List<IfTriple> innerTripples = createMethodGuardCheck(frameState, group, guardExpressions, mode);
List<AssumptionExpression> assumptions = specialization.getAssumptionExpressions();
if (!assumptions.isEmpty()) {
for (AssumptionExpression assumption : assumptions) {
innerTripples.addAll(createAssumptionSlowPathTriples(frameState, group, assumption));
}
}
if (specialization.hasMultipleInstances()) {
DSLExpression limit = specialization.getLimitExpression();
innerTripples.addAll(initializeCaches(frameState, group, specialization.getBoundCaches(limit), NodeExecutionMode.SLOW_PATH, true, false));
CodeTree limitExpression = DSLExpressionGenerator.write(limit, null, castBoundTypes(bindExpressionValues(frameState, limit, specialization)));
CodeTree limitCondition = CodeTreeBuilder.createBuilder().string(countName).string(" < ").tree(limitExpression).build();
innerTripples.add(new IfTriple(null, limitCondition, null));
// assert that specialization is not initialized
// otherwise we have been inserting invalid instances
assertSpecializationClassNotInitialized(frameState, specialization);
} else if (needsDuplicationCheck) {
innerTripples.add(new IfTriple(null, state.createNotContains(frameState, new Object[] { specialization }), null));
}
innerIfCount += IfTriple.materialize(builder, IfTriple.optimize(innerTripples), false);
builder.tree(createSpecialize(builder, frameState, group, specialization));
if (needsDuplicationCheck) {
hasFallthrough = true;
if (useDuplicateFlag) {
builder.startStatement().string(duplicateFoundName, " = true").end();
}
builder.end(innerIfCount);
// need to ensure that we update the implicit cast specializations on duplicates
CodeTree updateImplicitCast = createUpdateImplicitCastState(builder, frameState, specialization);
if (updateImplicitCast != null) {
builder.startElseBlock();
builder.tree(createUpdateImplicitCastState(builder, frameState, specialization));
builder.tree(state.createSet(frameState, new Object[] { specialization }, true, true));
builder.end();
}
builder.startIf();
if (useDuplicateFlag) {
builder.string(duplicateFoundName);
} else {
builder.string(createSpecializationLocalName(specialization), " != null");
}
builder.end().startBlock();
builder.tree(createExecute(builder, frameState, executeAndSpecializeType, specialization, mode));
builder.end();
} else {
builder.tree(createExecute(builder, frameState, executeAndSpecializeType, specialization, mode));
builder.end(innerIfCount);
hasFallthrough |= innerIfCount > 0;
}
}
builder.end(outerIfCount);
hasFallthrough |= outerIfCount > 0;
} else if (mode.isGuardFallback()) {
int ifCount = 0;
if (specialization != null && specialization.getMaximumNumberOfInstances() > 1) {
throw new AssertionError("unsupported path. should be caught by parser..");
}
int innerIfCount = 0;
cachedTriples.addAll(createMethodGuardCheck(frameState, group, guardExpressions, mode));
cachedTriples.addAll(createAssumptionCheckTriples(frameState, specialization));
cachedTriples = IfTriple.optimize(cachedTriples);
if (specialization != null && !hasImplicitCast) {
IfTriple singleCondition = null;
if (cachedTriples.size() == 1) {
singleCondition = cachedTriples.get(0);
}
if (singleCondition != null) {
int index = cachedTriples.indexOf(singleCondition);
CodeTree stateCheck = state.createNotContains(frameState, specializations);
cachedTriples.set(index, new IfTriple(singleCondition.prepare, combineTrees(" && ", stateCheck, singleCondition.condition), singleCondition.statements));
fallbackNeedsState = true;
}
}
innerIfCount += IfTriple.materialize(builder, cachedTriples, false);
SpecializationGroup prev = null;
for (SpecializationGroup child : group.getChildren()) {
if (prev != null && !prev.hasFallthrough()) {
break;
}
builder.tree(visitSpecializationGroup(builder, child, forType, frameState.copy(), allowedSpecializations, mode));
prev = child;
}
if (specialization != null) {
builder.returnFalse();
}
builder.end(innerIfCount);
builder.end(ifCount);
hasFallthrough |= ifCount > 0 || innerIfCount > 0;
} else {
throw new AssertionError("unexpected path");
}
group.setFallthrough(hasFallthrough);
return builder.build();
}
use of com.oracle.truffle.dsl.processor.model.GuardExpression in project graal by oracle.
the class FlatNodeGenFactory method accessesCachedState.
private static boolean accessesCachedState(List<SpecializationData> specializations) {
final AtomicBoolean needsState = new AtomicBoolean(false);
for (final SpecializationData specialization : specializations) {
if (!specialization.getAssumptionExpressions().isEmpty()) {
needsState.set(true);
break;
}
for (GuardExpression expression : specialization.getGuards()) {
expression.getExpression().accept(new DSLExpressionVisitor() {
public void visitVariable(Variable binary) {
if (!needsState.get() && isVariableAccessMember(binary)) {
needsState.set(true);
}
}
private boolean isVariableAccessMember(Variable variable) {
if (variable.getName().equals("null") && variable.getReceiver() == null) {
return false;
}
Parameter p = specialization.findByVariable(variable.getResolvedVariable());
if (p == null && !variable.getResolvedVariable().getModifiers().contains(STATIC)) {
DSLExpression receiver = variable.getReceiver();
if (receiver instanceof Variable) {
return isVariableAccessMember((Variable) receiver);
} else if (receiver instanceof Call) {
return isMethodAccessMember((Call) receiver);
}
return true;
} else if (p != null && p.getSpecification().isCached()) {
return true;
}
return false;
}
public void visitBooleanLiteral(BooleanLiteral binary) {
}
public void visitNegate(Negate negate) {
}
public void visitIntLiteral(IntLiteral binary) {
}
private boolean isMethodAccessMember(Call call) {
if (!call.getResolvedMethod().getModifiers().contains(STATIC)) {
DSLExpression receiver = call.getReceiver();
if (receiver instanceof Variable) {
return isVariableAccessMember((Variable) receiver);
} else if (receiver instanceof Call) {
return isMethodAccessMember((Call) receiver);
}
return true;
}
return false;
}
public void visitCall(Call call) {
if (!needsState.get() && isMethodAccessMember(call)) {
needsState.set(true);
}
}
public void visitBinary(Binary binary) {
}
});
}
}
boolean needsStat = needsState.get();
return needsStat;
}
use of com.oracle.truffle.dsl.processor.model.GuardExpression in project graal by oracle.
the class NodeParser method initializeFallbackReachability.
private static void initializeFallbackReachability(NodeData node) {
List<SpecializationData> specializations = node.getSpecializations();
SpecializationData fallback = null;
for (int i = specializations.size() - 1; i >= 0; i--) {
SpecializationData specialization = specializations.get(i);
if (specialization.isFallback() && specialization.getMethod() != null) {
fallback = specialization;
break;
}
}
if (fallback == null) {
// no need to compute reachability
return;
}
for (int index = 0; index < specializations.size(); index++) {
SpecializationData specialization = specializations.get(index);
SpecializationData lastReachable = specialization;
for (int searchIndex = index + 1; searchIndex < specializations.size(); searchIndex++) {
SpecializationData search = specializations.get(searchIndex);
if (search == fallback) {
// reached the end of the specialization
break;
}
assert lastReachable != search;
if (!lastReachable.isReachableAfter(search)) {
lastReachable = search;
} else if (search.getReplaces().contains(specialization)) {
lastReachable = search;
}
}
specialization.setReachesFallback(lastReachable == specialization);
List<SpecializationData> failedSpecializations = null;
if (specialization.isReachesFallback() && !specialization.getCaches().isEmpty() && !specialization.getGuards().isEmpty()) {
boolean guardBoundByCache = false;
for (GuardExpression guard : specialization.getGuards()) {
if (specialization.isGuardBoundWithCache(guard)) {
guardBoundByCache = true;
break;
}
}
if (guardBoundByCache && specialization.getMaximumNumberOfInstances() > 1) {
if (failedSpecializations == null) {
failedSpecializations = new ArrayList<>();
}
failedSpecializations.add(specialization);
}
}
if (failedSpecializations != null) {
List<String> specializationIds = failedSpecializations.stream().map((e) -> e.getId()).collect(Collectors.toList());
fallback.addError("Some guards for the following specializations could not be negated for the @%s specialization: %s. " + "Guards cannot be negated for the @%s when they bind @%s parameters and the specialization may consist of multiple instances. " + "To fix this limit the number of instances to '1' or " + "introduce a more generic specialization declared between this specialization and the fallback. " + "Alternatively the use of @%s can be avoided by declaring a @%s with manually specified negated guards.", Fallback.class.getSimpleName(), specializationIds, Fallback.class.getSimpleName(), Cached.class.getSimpleName(), Fallback.class.getSimpleName(), Specialization.class.getSimpleName());
}
}
}
Aggregations