Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
176 changes: 151 additions & 25 deletions vadl-frontend/main/vadl/ast/AnnotationTable.java
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
import com.google.errorprone.annotations.concurrent.LazyInit;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
Expand All @@ -47,6 +48,7 @@
import vadl.ast.nodes.DerivedFormatField;
import vadl.ast.nodes.EncodingDefinition;
import vadl.ast.nodes.Expr;
import vadl.ast.nodes.FloatTypeDefinition;
import vadl.ast.nodes.FormatField;
import vadl.ast.nodes.GroupDefinition;
import vadl.ast.nodes.Identifier;
Expand All @@ -69,6 +71,7 @@
import vadl.types.BitsType;
import vadl.types.Type;
import vadl.utils.Pair;
import vadl.utils.functionInterfaces.QuadConsumer;
import vadl.utils.functionInterfaces.TriConsumer;
import vadl.viam.Abi;
import vadl.viam.ArtificialResource;
Expand All @@ -77,6 +80,8 @@
import vadl.viam.Counter;
import vadl.viam.Encoding;
import vadl.viam.Endianness;
import vadl.viam.FloatExceptionFlag;
import vadl.viam.FloatFormat;
import vadl.viam.Format;
import vadl.viam.Group;
import vadl.viam.Instruction;
Expand Down Expand Up @@ -204,7 +209,7 @@ public class AnnotationTable {
// this handled in the VIAM lowering when constructing the ArtificialResource
.build();

annotationOn(RegisterDefinition.class, "execution state", FormatFieldAnnotation::new)
annotationOn(RegisterDefinition.class, "execution state", ExecutionStateAnnotation::new)
.check((def, annotation, lowering) -> annotation.typeCheckTarget(def))
.applyAst((def, annotation) -> annotation.calcBitSlice(def))
.applyViam((def, annotation, lowering) -> {
Expand Down Expand Up @@ -330,6 +335,56 @@ public class AnnotationTable {
})
.build();

/// FLOAT RELATED ///

annotationOn(FloatTypeDefinition.class, "IEEE", ConstantAnnotation::new)
.applyAst((def, annotation) -> def.size = annotation.constant.value().intValue())
.applyViam((def, annotation, lowering) -> {
var encoding = FloatFormat.Encoding.ieee(annotation.constant.value().intValue());
ensure(encoding != null,
() -> error("Invalid IEEE encoding size", annotation)
.description("The following sizes are supported: %s",
Arrays.stream(FloatFormat.Encoding.values())
.map(e -> Integer.toString(e.size)).collect(Collectors.joining(", ")))
);
((FloatFormat) def).setEncoding(encoding);
}).build();

QuadConsumer<RegisterTensor, FloatFlagAnnotation, Boolean, FloatExceptionFlag>
applyViamFloatFlag;
applyViamFloatFlag = (reg, annotation, sticky, flag) -> {
var idx = annotation.index;
if (reg.hasAnnotation(vadl.viam.annotations.FloatFlagAnnotation.class)) {
var ann = reg.expectAnnotation(vadl.viam.annotations.FloatFlagAnnotation.class);
var setFlag = ann.get(idx);
ensure(setFlag == null, () -> error(
"Bit already mapped as " + (ann.isSticky(idx) ? "" : "non ")
+ "sticky " + requireNonNull(setFlag).name + " flag",
annotation
));
ann.set(idx, sticky, flag);
} else {
var ann = new vadl.viam.annotations.FloatFlagAnnotation();
ann.set(idx, sticky, flag);
reg.addAnnotation(ann);
}
};

for (var flag : FloatExceptionFlag.values()) {
annotationOn(RegisterDefinition.class, "fe flag " + flag.name, FloatFlagAnnotation::new)
.check((def, annotation, lowering) -> annotation.typeCheckTarget(def))
.applyViam((def, annotation, lowering) ->
applyViamFloatFlag.accept((RegisterTensor) def, annotation, false, flag))
.build();

annotationOn(RegisterDefinition.class, "sticky fe flag " + flag.name,
FloatFlagAnnotation::new)
.check((def, annotation, lowering) -> annotation.typeCheckTarget(def))
.applyViam((def, annotation, lowering) ->
applyViamFloatFlag.accept((RegisterTensor) def, annotation, true, flag))
.build();
}

/// PROCESSOR RELATED ///

annotationOn(ProcessorDefinition.class, "htif", EnableAnnotation::new)
Expand Down Expand Up @@ -1103,6 +1158,95 @@ public String usageString() {
}
}

/**
* An annotation that can be applied to registers of type {@link FormatType}. It can be used
* to reference one format field of the type. The bit-size of the format field must be 1.
*
* <p>Usage examples:
* <pre>
* [ sticky fe flag overflow : ov ]
* register reg : Format
* format Format : Bits<8> { ov [7], ... }
* </pre>
*/
class FloatFlagAnnotation extends FormatFieldAnnotation {

@LazyInit
Identifier field;

@LazyInit
int index;

@Override
void typeCheck(AnnotationDefinition definition, TypeChecker typeChecker) {
super.typeCheck(definition, typeChecker);
verifyValuesCnt(definition, 1);
field = (Identifier) definition.values.getFirst();
}

@Override
void typeCheckTarget(TypedNode target) {
super.typeCheckTarget(target);
var format = ((FormatType) target.type()).format;
var range = requireNonNull(format.getFieldRange(field.name));
Diagnostic.ensure(range.from() == range.to(), () ->
error("Float flag can only be one bit", field));
index = range.from();
}

@Override
String annotationName() {
return "Float exception flag annotation";
}

@Override
public String usageString() {
return "[ " + name + " : <format-field> ]";
}
}

/**
* An annotation that can be applied to registers of type {@link BitsType}. If the register's
* type is a {@link FormatType}, then this annotation can be used to reference its format fields.
*
* <p>Usage examples:
* <pre>
* [ execution state ]
* register reg : Bits<8>
*
* [ execution state : f0, f1 ]
* register reg : Format
* format Format : Bits<8> { f0 [7], f1 [6], ... }
* </pre>
*/
class ExecutionStateAnnotation extends FormatFieldAnnotation {

void calcBitSlice(TypedNode target) {
if (fields.isEmpty()) {
var width = ((BitsType) target.type()).bitWidth();
slice = Constant.BitSlice.of(width - 1, 0);
return;
}
var format = requireNonNull((FormatType) target.type()).format;
slice = new Constant.BitSlice(
fields.stream()
.map(field -> requireNonNull(format.getFieldRange(field.name)))
.map(range -> new Constant.BitSlice.Part(range.from(), range.to()))
.toArray(Constant.BitSlice.Part[]::new)
);
}

@Override
String annotationName() {
return "Execution state annotation";
}

@Override
public String usageString() {
return "[ " + name + " : <ident>, ... ]";
}
}

/**
* An annotation that can be applied to anything that has a type which is a {@link BitsType}.
* If the target's type is a {@link FormatType}, then this annotation can be used to reference
Expand All @@ -1118,7 +1262,7 @@ public String usageString() {
* format Format : Bits<8> { f0 [7], f1 [6], ... }
* </pre>
*/
class FormatFieldAnnotation extends Annotation {
abstract class FormatFieldAnnotation extends Annotation {

@LazyInit
List<Identifier> fields;
Expand All @@ -1145,14 +1289,14 @@ void typeCheckTarget(TypedNode target) {
if (fields.isEmpty()) {
Diagnostic.ensure(target.type() instanceof BitsType,
() -> error("Annotation target has invalid type", this).description("""
Execution state annotation can only be applied to simple \
register definitions (no register files or tensors)"""));
%s can only be applied to simple register \
definitions (no register files or tensors)""", annotationName()));
return;
}
Diagnostic.ensure(target.type() instanceof FormatType,
() -> error("Annotation target has invalid type", this).description("""
Execution state annotation with format fields can only \
be applied to register definitions with a format type"""));
%s with format fields can only be applied \
to register definitions with a format type""", annotationName()));

var format = ((FormatType) target.type()).format;
fields.forEach(field -> {
Expand All @@ -1170,25 +1314,7 @@ void typeCheckTarget(TypedNode target) {
});
}

void calcBitSlice(TypedNode target) {
if (fields.isEmpty()) {
var width = ((BitsType) target.type()).bitWidth();
slice = Constant.BitSlice.of(width - 1, 0);
return;
}
var format = requireNonNull((FormatType) target.type()).format;
slice = new Constant.BitSlice(
fields.stream()
.map(field -> requireNonNull(format.getFieldRange(field.name)))
.map(range -> new Constant.BitSlice.Part(range.from(), range.to()))
.toArray(Constant.BitSlice.Part[]::new)
);
}

@Override
public String usageString() {
return "[ " + name + " : <ident>, ... ]";
}
abstract String annotationName();
}

/**
Expand Down
4 changes: 1 addition & 3 deletions vadl-frontend/main/vadl/ast/AstUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -73,9 +73,7 @@ static BuiltInTable.BuiltIn getBuiltIn(String name, List<Type> argTypes) {
name = "sdec";
}

String finalBuiltinName = name;
var matchingBuiltin = nameLookupTable.get(finalBuiltinName);
return matchingBuiltin;
return nameLookupTable.get(name);
}

static BuiltInTable.BuiltIn getOperatorBuiltIn(Operator operator, List<Type> argTypes) {
Expand Down
51 changes: 40 additions & 11 deletions vadl-frontend/main/vadl/ast/BehaviorLowering.java
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@
import vadl.ast.nodes.ExpandedSequenceCallExpr;
import vadl.ast.nodes.Expr;
import vadl.ast.nodes.ExprVisitor;
import vadl.ast.nodes.FloatTypeDefinition;
import vadl.ast.nodes.ForallExpr;
import vadl.ast.nodes.ForallStatement;
import vadl.ast.nodes.ForallThenExpr;
Expand Down Expand Up @@ -125,13 +126,13 @@
import vadl.utils.BigIntUtils;
import vadl.utils.Either;
import vadl.utils.Pair;
import vadl.utils.SourceLocation;
import vadl.utils.WithLocation;
import vadl.viam.ArtificialResource;
import vadl.viam.Constant;
import vadl.viam.Counter;
import vadl.viam.Definition;
import vadl.viam.ExceptionDef;
import vadl.viam.FloatFormat;
import vadl.viam.Format;
import vadl.viam.Function;
import vadl.viam.Instruction;
Expand Down Expand Up @@ -912,6 +913,11 @@ private ExpressionNode visitIdentifiable(Expr expr) {
return new ConstantNode(value);
}

if (computedTarget instanceof FloatTypeDefinition floatType) {
var format = (FloatFormat) viamLowering.fetch(floatType).orElseThrow();
return new ConstantNode(new Constant.FloatType(format));
}

// Enum field
if (computedTarget instanceof EnumerationDefinition.Entry enumField) {
// Inline the value of the enum
Expand Down Expand Up @@ -1376,6 +1382,26 @@ public ExpressionNode visitStageCall(CallIndexExpr expr, StageDefinition stageDe
return new ReadStageOutputNode(output);
}

private Constant visitConstArg(Expr expr) {
Node origin = null;
if (expr instanceof Identifier identifier) {
origin = requireNonNull(identifier.target());
} else if (expr instanceof IdentifierPath path) {
origin = requireNonNull(path.target());
}

// TODO: the constant evaluator can only evaluate integers currently. Once other stuff like
// strings and float-types are supported, we do not need this function anymore and can
// directly call the constant evaluator.
// !!! There is a similar method in TypeChecker
if (origin instanceof FloatTypeDefinition floatType) {
var format = (FloatFormat) viamLowering.fetch(floatType).orElseThrow();
return new Constant.FloatType(format);
}

return constantEvaluator.eval(expr).toViamConstant();
}

@Override
public ExpressionNode visit(CallIndexExpr expr) {

Expand All @@ -1385,6 +1411,12 @@ public ExpressionNode visit(CallIndexExpr expr) {
return visitStageCall(expr, stageDefinition);
}

var symbolArgs = expr.symbolArgs();

var constArgs = symbolArgs != null
? symbolArgs.stream().map(this::visitConstArg).toList()
: List.<Constant>of();

var argGroups = expr.args();
final var args = new NodeList<ExpressionNode>(AstUtils.argumentCount(argGroups));
AstUtils.forEachArgument(argGroups, arg -> args.add(this.fetch(arg)));
Expand All @@ -1395,11 +1427,9 @@ public ExpressionNode visit(CallIndexExpr expr) {
// Builtin Call
if (expr.computedBuiltIn != null) {
if (BuiltInTable.ASM_PARSER_BUILT_INS.contains(expr.computedBuiltIn)) {
exprBeforeSlice = new AsmBuiltInCall(expr.computedBuiltIn, args,
typeBeforeSlice);
exprBeforeSlice = new AsmBuiltInCall(expr.computedBuiltIn, args, typeBeforeSlice);
} else {
exprBeforeSlice = new BuiltInCall(expr.computedBuiltIn, args,
typeBeforeSlice);
exprBeforeSlice = new BuiltInCall(expr.computedBuiltIn, constArgs, args, typeBeforeSlice);
}
} else {
exprBeforeSlice = switch (expr.computedTarget()) {
Expand Down Expand Up @@ -1432,9 +1462,8 @@ yield readRegisterTensorDirect(((Counter) lowered).registerTensor(), aliasArgs,
}

case MemoryDefinition memDef -> {
var sizeExpr = expr.target.size();
var words = sizeExpr != null
? constantEvaluator.eval(sizeExpr).value().intValueExact()
var words = symbolArgs != null
? constantEvaluator.eval(symbolArgs.getFirst()).value().intValueExact()
: 1;
yield new ReadMemNode((Memory) viamLowering.fetch(memDef).orElseThrow(),
words, args.getFirst(), typeBeforeSlice.asDataType());
Expand Down Expand Up @@ -1745,9 +1774,9 @@ public SubgraphContext visit(AssignmentStatement statement) {
}
});

var sizeExpr = callTarget.target.size();
callSize = sizeExpr != null
? constantEvaluator.eval(sizeExpr).value().intValueExact()
var symbolArgs = callTarget.target.symbolArgs();
callSize = symbolArgs != null
? constantEvaluator.eval(symbolArgs.getFirst()).value().intValueExact()
: null;
} else if (statement.target instanceof Identifier identTarget) {
targetDef = (vadl.ast.nodes.Definition) requireNonNull(identTarget.target());
Expand Down
10 changes: 9 additions & 1 deletion vadl-frontend/main/vadl/ast/ConstantEvaluator.java
Original file line number Diff line number Diff line change
Expand Up @@ -164,10 +164,18 @@ public ConstantValue evalBuiltin(BuiltInTable.BuiltIn builtin, List<ConstantValu
}
}

if (!builtin.signature().constArgTypeClass().isEmpty()) {
throw new EvaluationError(
"Built-in function `%s` cannot be constant evaluated (yet)."
.formatted(builtin.name()),
loc
);
}

// NOTE: If you are seeing this issue, someone forgot to add the `compute` method for a
// built-in function. Look to into BuiltInTable.
var val = builtin
.compute(args.stream().map(c -> (Constant) c.toViamConstant()).toList())
.compute(List.of(), args.stream().map(c -> (Constant) c.toViamConstant()).toList())
.orElseThrow(() -> new EvaluationError(
"Built-in function `%s` cannot be constant evaluated (yet).".formatted(
builtin.name()),
Expand Down
Loading
Loading