Skip to content

Commit 14aaf56

Browse files
authored
lcb: Refactored predicates (#367)
* lcb: Removed case distinction for predicates when rendering * lcb: Generate predicate with encoding function This commit only handles the trivial encodings. * lcb: Generated predicates for arithmetical field access functions * lcb: Generate predices for shifted immediates * lcb: Setup tests for predicates * lcb: Refactored into separate classes * lcb: Setup more tests * lcb: Fixed mask by 1 * lcb: Fixed tests * viam: Don't create default predicates * lcb: Removed printing of file * chore: Make CheckStyle happy * lcb: Removed unencodable instructions * lcb: Updated tests * lcb: Changed API
1 parent 0c2ff3b commit 14aaf56

25 files changed

+950
-541
lines changed

vadl/main/vadl/ast/ViamLowering.java

Lines changed: 22 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1062,19 +1062,7 @@ public Optional<vadl.viam.Definition> visit(FormatDefinition definition) {
10621062
var identifier = generateIdentifier(derivedField.viamId, derivedField.identifier());
10631063
var access = getFieldAccessFunction(derivedField);
10641064

1065-
// construct a default predicate that just returns true.
1066-
// if there is a user-specified predicate, this will be overwritten by the one provided
1067-
// (in setFieldAccessPredicate).
1068-
var predName = identifier.name() + "::predicate";
1069-
var predicateGraph =
1070-
new BehaviorLowering(this).getFunctionGraph(
1071-
new BoolLiteral(true, SourceLocation.INVALID_SOURCE_LOCATION), predName);
1072-
var predicate = new Function(
1073-
generateIdentifier(predName, derivedField.identifier),
1074-
new vadl.viam.Parameter[] {}, Type.bool(), predicateGraph
1075-
);
1076-
1077-
var field = new Format.FieldAccess(identifier, access, predicate);
1065+
var field = new Format.FieldAccess(identifier, access, null);
10781066
formatFieldCache.put(derivedField, field);
10791067

10801068
return field;
@@ -1100,10 +1088,31 @@ public Optional<vadl.viam.Definition> visit(FormatDefinition definition) {
11001088
format.setFieldEncodings(encodings);
11011089

11021090
checkFormatFieldEncodings(format);
1091+
checkIfPredicateIsRequired(format);
11031092

11041093
return Optional.of(format);
11051094
}
11061095

1096+
/**
1097+
* The user has to specify a predicate when she specifies an encoding function.
1098+
*/
1099+
private void checkIfPredicateIsRequired(Format format) {
1100+
var fieldAccesses = format.fieldAccesses();
1101+
1102+
for (var fieldAccess : fieldAccesses) {
1103+
if (fieldAccess.predicate() != null) {
1104+
var encodings = format.fieldEncodingsOf(Set.of(fieldAccess));
1105+
if (encodings.isEmpty()) {
1106+
DeferredDiagnosticStore.add(
1107+
Diagnostic.error("A predicate is required", fieldAccess.location())
1108+
.help(
1109+
"When a custom encoding function is specified, "
1110+
+ "a predicate function is required."));
1111+
}
1112+
}
1113+
}
1114+
}
1115+
11071116
private Function getFieldAccessFunction(DerivedFormatField derivedField) {
11081117
var accessName = derivedField.viamId + "::decode";
11091118
var accessGraph =

vadl/main/vadl/cppCodeGen/common/GcbAccessOrPredicateFunctionCodeGenerator.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,10 +35,10 @@ public class GcbAccessOrPredicateFunctionCodeGenerator extends AccessFunctionCod
3535
/**
3636
* Constructor.
3737
*/
38-
public GcbAccessOrPredicateFunctionCodeGenerator(GcbCppFunctionBodyLess accessFunction,
38+
public GcbAccessOrPredicateFunctionCodeGenerator(GcbCppFunctionBodyLess functionHeader,
3939
Format.FieldAccess fieldAccess,
4040
String functionName) {
41-
super(accessFunction, fieldAccess, functionName);
41+
super(functionHeader, fieldAccess, functionName);
4242
}
4343

4444
/**

vadl/main/vadl/gcb/passes/encodingGeneration/GenerateFieldAccessEncodingFunctionPass.java renamed to vadl/main/vadl/gcb/passes/encodingGeneration/GenerateFieldAccessEncodingAndPredicateFunctionsPass.java

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -20,12 +20,10 @@
2020
import java.util.Set;
2121
import javax.annotation.Nullable;
2222
import vadl.configuration.GcbConfiguration;
23-
import vadl.error.Diagnostic;
24-
import vadl.error.DiagnosticList;
25-
import vadl.gcb.passes.encodingGeneration.strategies.EncodingGenerationStrategy;
26-
import vadl.gcb.passes.encodingGeneration.strategies.impl.ArithmeticImmediateStrategy;
27-
import vadl.gcb.passes.encodingGeneration.strategies.impl.ShiftedImmediateStrategy;
28-
import vadl.gcb.passes.encodingGeneration.strategies.impl.TrivialImmediateStrategy;
23+
import vadl.gcb.passes.encodingGeneration.strategies.EncodingPredicateGenerationStrategy;
24+
import vadl.gcb.passes.encodingGeneration.strategies.impl.ArithmeticImmediateStrategyPredicate;
25+
import vadl.gcb.passes.encodingGeneration.strategies.impl.ShiftedImmediateStrategyPredicate;
26+
import vadl.gcb.passes.encodingGeneration.strategies.impl.TrivialImmediateStrategyPredicate;
2927
import vadl.pass.Pass;
3028
import vadl.pass.PassName;
3129
import vadl.pass.PassResults;
@@ -50,14 +48,14 @@
5048
* }
5149
* }</pre>
5250
*/
53-
public class GenerateFieldAccessEncodingFunctionPass extends Pass {
51+
public class GenerateFieldAccessEncodingAndPredicateFunctionsPass extends Pass {
5452

55-
public static final List<EncodingGenerationStrategy> strategies = List.of(
56-
new TrivialImmediateStrategy(),
57-
new ShiftedImmediateStrategy(),
58-
new ArithmeticImmediateStrategy());
53+
public static final List<EncodingPredicateGenerationStrategy> strategies = List.of(
54+
new TrivialImmediateStrategyPredicate(),
55+
new ShiftedImmediateStrategyPredicate(),
56+
new ArithmeticImmediateStrategyPredicate());
5957

60-
public GenerateFieldAccessEncodingFunctionPass(GcbConfiguration gcbConfiguration) {
58+
public GenerateFieldAccessEncodingAndPredicateFunctionsPass(GcbConfiguration gcbConfiguration) {
6159
super(gcbConfiguration);
6260
}
6361

@@ -77,7 +75,7 @@ public Object execute(PassResults passResults, Specification viam) {
7775
// Different field access functions require different heuristics for the encoding.
7876
for (var strategy : strategies) {
7977
if (strategy.checkIfApplicable(fieldAccess)) {
80-
strategy.generateEncoding(instruction, fieldAccess);
78+
strategy.generateEncodingAndPredicateFunction(instruction, fieldAccess);
8179
break;
8280
}
8381
}

vadl/main/vadl/gcb/passes/encodingGeneration/strategies/EncodingGenerationStrategy.java

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
// SPDX-FileCopyrightText : © 2025 TU Wien <vadl@tuwien.ac.at>
2+
// SPDX-License-Identifier: GPL-3.0-or-later
3+
//
4+
// This program is free software: you can redistribute it and/or modify
5+
// it under the terms of the GNU General Public License as published by
6+
// the Free Software Foundation, either version 3 of the License, or
7+
// (at your option) any later version.
8+
//
9+
// This program is distributed in the hope that it will be useful,
10+
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11+
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12+
// GNU General Public License for more details.
13+
//
14+
// You should have received a copy of the GNU General Public License
15+
// along with this program. If not, see <https://www.gnu.org/licenses/>.
16+
17+
package vadl.gcb.passes.encodingGeneration.strategies;
18+
19+
import java.math.BigInteger;
20+
import vadl.gcb.passes.GenerateValueRangeImmediatePass;
21+
import vadl.types.BuiltInTable;
22+
import vadl.types.Type;
23+
import vadl.utils.GraphUtils;
24+
import vadl.utils.SourceLocation;
25+
import vadl.viam.Constant;
26+
import vadl.viam.Format;
27+
import vadl.viam.Function;
28+
import vadl.viam.Identifier;
29+
import vadl.viam.Instruction;
30+
import vadl.viam.Parameter;
31+
import vadl.viam.graph.Graph;
32+
import vadl.viam.graph.control.ReturnNode;
33+
import vadl.viam.graph.control.StartNode;
34+
import vadl.viam.graph.dependency.ConstantNode;
35+
import vadl.viam.graph.dependency.FuncParamNode;
36+
37+
/**
38+
* The implementor of this interface can generate a field access encoding / predicate functions.
39+
*/
40+
public interface EncodingPredicateGenerationStrategy {
41+
42+
String PARAM = "param";
43+
44+
/**
45+
* Check if the strategy can be applied. Returns {@code true} when it is applicable.
46+
*/
47+
boolean checkIfApplicable(Format.FieldAccess fieldAccess);
48+
49+
/**
50+
* Create the inverse behavior graph of a field access function.
51+
* It also adds the created nodes to {@code vadl.viam.Format.FieldAccess#encoding}.
52+
* Based on the encoding functions, it automatically detects the value range which is encodable
53+
* into the {@link Format.Field}.
54+
*/
55+
void generateEncodingAndPredicateFunction(Instruction instruction,
56+
Format.FieldAccess fieldAccess);
57+
58+
/**
59+
* Creates a new {@link vadl.viam.Format.FieldEncoding} for the given field
60+
* and the behavior graph.
61+
* It assumes that there is only a single field references by the field access.
62+
*/
63+
default void setFieldEncoding(Instruction instruction,
64+
Format.FieldAccess fieldAccess,
65+
Format.Field fieldToBeEncoded,
66+
Graph behavior) {
67+
var ident = fieldAccess.identifier.last().prepend(instruction.identifier());
68+
var format = fieldAccess.format();
69+
var encoding = new Format.FieldEncoding(ident, fieldToBeEncoded, behavior);
70+
format.setFieldEncoding(encoding);
71+
}
72+
73+
/**
74+
* Creates a new predicate function for the given field
75+
* and the behavior graph.
76+
* It assumes that there is only a single field references by the field access.
77+
*/
78+
default void setPredicate(Instruction instruction,
79+
Format.FieldAccess fieldAccess,
80+
Graph behavior) {
81+
var ident = instruction.identifier().append(fieldAccess.identifier.last()
82+
.parts());
83+
var predicate = new Function(ident, new Parameter[] {}, Type.bool(), behavior);
84+
fieldAccess.setPredicate(predicate);
85+
}
86+
87+
/**
88+
* Template method for generation a predicate function.
89+
*/
90+
default void generatePredicate(Instruction instruction, Format.FieldAccess fieldAccess) {
91+
var trueCase = new ConstantNode(Constant.Value.fromBoolean(true));
92+
var falseCase = new ConstantNode(Constant.Value.fromBoolean(false));
93+
94+
var fieldRef = fieldAccess.fieldRefs().getFirst();
95+
96+
var paramNode = new FuncParamNode(
97+
new Parameter(new Identifier(PARAM, SourceLocation.INVALID_SOURCE_LOCATION),
98+
fieldAccess.type()));
99+
100+
var lowestValue = new ConstantNode(Constant.Value.fromInteger(
101+
BigInteger.valueOf(
102+
GenerateValueRangeImmediatePass.lowestPossibleValue(fieldRef.type().toBitsType(),
103+
true)),
104+
Type.signedInt(64)));
105+
var highestValue = new ConstantNode(Constant.Value.fromInteger(
106+
BigInteger.valueOf(
107+
GenerateValueRangeImmediatePass.highestPossibleValue(fieldRef.type().toBitsType(),
108+
true)),
109+
Type.signedInt(64)));
110+
111+
var lowestExpr =
112+
GraphUtils.binaryOp(BuiltInTable.SGEQ, paramNode, lowestValue);
113+
var highestExpr =
114+
GraphUtils.binaryOp(BuiltInTable.SLEQ, paramNode, highestValue);
115+
116+
var conditional =
117+
GraphUtils.select(GraphUtils.and(lowestExpr, highestExpr), trueCase, falseCase);
118+
var returnNode = new ReturnNode(conditional);
119+
var startNode = new StartNode(returnNode);
120+
var behavior = new Graph("Generated predicate of " + fieldAccess.simpleName());
121+
behavior.addWithInputs(returnNode);
122+
behavior.add(startNode);
123+
setPredicate(instruction, fieldAccess, behavior);
124+
}
125+
}

vadl/main/vadl/gcb/passes/encodingGeneration/strategies/impl/ArithmeticImmediateStrategy.java renamed to vadl/main/vadl/gcb/passes/encodingGeneration/strategies/impl/ArithmeticImmediateStrategyPredicate.java

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -17,13 +17,13 @@
1717
package vadl.gcb.passes.encodingGeneration.strategies.impl;
1818

1919
import javax.annotation.Nullable;
20-
import vadl.gcb.passes.encodingGeneration.strategies.EncodingGenerationStrategy;
20+
import vadl.gcb.passes.encodingGeneration.strategies.EncodingPredicateGenerationStrategy;
2121
import vadl.types.BitsType;
2222
import vadl.types.BuiltInTable;
2323
import vadl.types.DataType;
2424
import vadl.viam.Constant;
2525
import vadl.viam.Format;
26-
import vadl.viam.PrintableInstruction;
26+
import vadl.viam.Instruction;
2727
import vadl.viam.graph.GraphVisitor;
2828
import vadl.viam.graph.Node;
2929
import vadl.viam.graph.control.ReturnNode;
@@ -52,7 +52,7 @@
5252
* }
5353
* }</pre>
5454
*/
55-
public class ArithmeticImmediateStrategy implements EncodingGenerationStrategy {
55+
public class ArithmeticImmediateStrategyPredicate implements EncodingPredicateGenerationStrategy {
5656
@Override
5757
public boolean checkIfApplicable(Format.FieldAccess fieldAccess) {
5858
// Check if only one field
@@ -70,7 +70,13 @@ public boolean checkIfApplicable(Format.FieldAccess fieldAccess) {
7070
}
7171

7272
@Override
73-
public void generateEncoding(PrintableInstruction instruction, Format.FieldAccess fieldAccess) {
73+
public void generateEncodingAndPredicateFunction(Instruction instruction,
74+
Format.FieldAccess fieldAccess) {
75+
generateEncoding(instruction, fieldAccess);
76+
generatePredicate(instruction, fieldAccess);
77+
}
78+
79+
private void generateEncoding(Instruction instruction, Format.FieldAccess fieldAccess) {
7480
var accessFunction = fieldAccess.accessFunction();
7581
var copy = accessFunction.behavior().copy();
7682
final var returnNode = copy.getNodes(ReturnNode.class).findFirst().get();
@@ -86,7 +92,7 @@ public void generateEncoding(PrintableInstruction instruction, Format.FieldAcces
8692

8793
// After that we need to find the field and add it to the other side.
8894
var fieldRefs = copy.getNodes(FieldRefNode.class).toList();
89-
var fieldRef = fieldRefs.get(0);
95+
var fieldRef = fieldRefs.getFirst();
9096
var fieldRefBits = (BitsType) fieldRef.type();
9197

9298
// Example

0 commit comments

Comments
 (0)