Skip to content
Merged
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
11 changes: 8 additions & 3 deletions compiler/lib/Compiler/FinalEmitCpp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,14 +61,19 @@ LogicalResult emitRecord(HardwareEmitContext &context, ac::StructOp record,
SmallVector<std::string> pointers;
for (auto raw : record.getFields()) {
auto field = cast<DictionaryAttr>(raw);
auto type =
context.cppType(field.getAs<TypeAttr>("type").getValue(), record);
Type fieldType = field.getAs<TypeAttr>("type").getValue();
auto type = context.cppType(fieldType, record);
auto source = field.getAs<StringAttr>("name");
auto member = legalizeIdentifier(source.getValue(),
[&] { return record.emitOpError(); });
if (failed(type) || failed(member))
return failure();
out << " " << *type << " " << *member << "{};\n";
out << " " << *type << " " << *member;
// Nested records default-construct their initialized leaves. Repeating an
// empty member initializer at every record level is unnecessary.
if (!isa<ac::StructType>(fieldType))
out << "{}";
out << ";\n";
pointers.push_back("&" + *name + "::" + *member);
}
out << "};\n";
Expand Down
54 changes: 46 additions & 8 deletions compiler/lib/Compiler/PythonImportAST.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,11 +201,14 @@ LogicalResult verifyCapturedNode(Attribute raw,
auto body = fields.getAs<DictionaryAttr>("body");
StringRef bodyKind = body.getAs<StringAttr>("kind").getValue();
if (!llvm::is_contained(
ArrayRef<StringRef>{"BoolOp", "NamedExpr", "BinOp", "UnaryOp",
"Lambda", "IfExp", "Dict", "Set", "ListComp", "SetComp",
"DictComp", "GeneratorExp", "Await", "Yield", "YieldFrom",
"Compare", "Call", "FormattedValue", "JoinedStr", "Constant",
"Attribute", "Subscript", "Starred", "Name", "List", "Tuple"},
ArrayRef<StringRef>{
"BoolOp", "NamedExpr", "BinOp", "UnaryOp",
"Lambda", "IfExp", "Dict", "Set",
"ListComp", "SetComp", "DictComp", "GeneratorExp",
"Await", "Yield", "YieldFrom", "Compare",
"Call", "FormattedValue", "JoinedStr", "Constant",
"Attribute", "Subscript", "Starred", "Name",
"List", "Tuple"},
bodyKind))
return emitError() << "captured Lambda body must be an expression";
if (failed(validateTableQueryLambda(AstNode{node, {}}, emitError,
Expand Down Expand Up @@ -273,6 +276,12 @@ LogicalResult verifyCapturedNode(Attribute raw,
failed(verifyRequiredArray(fields, "body", form, emitError)) ||
failed(verifyRequiredArray(fields, "orelse", form, emitError)))
return failure();
} else if (form == "For") {
if (failed(verifyRequiredNode(fields, "target", form, emitError)) ||
failed(verifyRequiredNode(fields, "iter", form, emitError)) ||
failed(verifyNodeArray(fields, "body", form, {}, true, emitError)) ||
failed(verifyNodeArray(fields, "orelse", form, {}, false, emitError)))
return failure();
} else if (form == "UnaryOp") {
if (failed(verifyRequiredNode(fields, "op", form, emitError)) ||
failed(verifyRequiredNode(fields, "operand", form, emitError)))
Expand Down Expand Up @@ -437,7 +446,8 @@ bool sourceBindingShadowed(const CapturedSource &source, const AstNode &node,
if (step.index)
return false;
if ((ancestor.kind() == "FunctionDef" || ancestor.kind() == "ClassDef" ||
ancestor.kind() == "Lambda") && step.field == "body") {
ancestor.kind() == "Lambda") &&
step.field == "body") {
if (scopeBinds(ancestor))
return true;
}
Expand Down Expand Up @@ -525,8 +535,35 @@ DictionaryAttr sourceSpan(OpBuilder &builder, StringRef sourcePath,
});
}

FailureOr<LiteralForSyntax>
readLiteralForSyntax(const AstNode &node, ac::detail::EmitError emitError) {
auto target = node.child("target");
auto iterable = node.child("iter");
auto function = iterable.child("func");
if (node.kind() != "For" || target.kind() != "Name" ||
target.string("id").empty() || iterable.kind() != "Call" ||
function.kind() != "Name" || function.string("id") != "range" ||
!iterable.array("args") || iterable.array("args").size() != 1 ||
!iterable.array("keywords") || !iterable.array("keywords").empty() ||
!node.array("orelse") || !node.array("orelse").empty())
return emitError() << "bounded for requires a Name target and exact "
"range(Integer literal), without loop else";
auto bound = iterable.item("args", 0);
auto encoded = bound.kind() == "Constant"
? dyn_cast_or_null<DictionaryAttr>(bound.get("value"))
: DictionaryAttr();
auto integer = encoded ? encoded.getAs<StringAttr>("integer") : StringAttr();
if (!integer || integer.getValue().empty() ||
llvm::any_of(integer.getValue(),
[](char digit) { return digit < '0' || digit > '9'; }))
return emitError() << "bounded for stop requires a nonnegative "
"non-Boolean Integer literal";
return LiteralForSyntax{target, bound, integer.getValue()};
}

DictionaryAttr occurrence(OpBuilder &builder, FlatSymbolRefAttr definition,
const AstNode &node) {
const AstNode &node,
ArrayRef<DictionaryAttr> expansion) {
SmallVector<Attribute> components;
for (const AstStep &step : node.path) {
if (step.index) {
Expand All @@ -545,9 +582,10 @@ DictionaryAttr occurrence(OpBuilder &builder, FlatSymbolRefAttr definition,
builder.getNamedAttr("definition", definition),
builder.getNamedAttr("ast_path", builder.getArrayAttr(components)),
});
SmallVector<Attribute> frames(expansion.begin(), expansion.end());
return builder.getDictionaryAttr({
builder.getNamedAttr("site", site),
builder.getNamedAttr("expansion", builder.getArrayAttr({})),
builder.getNamedAttr("expansion", builder.getArrayAttr(frames)),
});
}

Expand Down
15 changes: 12 additions & 3 deletions compiler/lib/Compiler/PythonImportAST.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,21 @@ mlir::LogicalResult validateTableQueryLambda(const AstNode &node,
mlir::FailureOr<CapturedSource>
readSingleCapture(mlir::ModuleOp transport, ac::detail::EmitError emitError);

struct LiteralForSyntax {
AstNode target;
AstNode bound;
llvm::StringRef spelling;
};
mlir::FailureOr<LiteralForSyntax>
readLiteralForSyntax(const AstNode &node, ac::detail::EmitError emitError);

mlir::DictionaryAttr sourceSpan(mlir::OpBuilder &builder,
llvm::StringRef sourcePath,
const AstNode &node);
mlir::DictionaryAttr occurrence(mlir::OpBuilder &builder,
mlir::FlatSymbolRefAttr definition,
const AstNode &node);
mlir::DictionaryAttr
occurrence(mlir::OpBuilder &builder, mlir::FlatSymbolRefAttr definition,
const AstNode &node,
llvm::ArrayRef<mlir::DictionaryAttr> expansion = {});

} // namespace acir::compiler::detail

Expand Down
62 changes: 32 additions & 30 deletions compiler/lib/Compiler/PythonImportAggregates.inc
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,8 @@ bool Importer::fixedAnnotation(const AstNode &node) const {
return true;
auto binding = lookupBinding(node);
return binding && binding->category == BindingCategory::Marker &&
fixedBitsAliasWidth(binding->importedModule, binding->remote).has_value();
fixedBitsAliasWidth(binding->importedModule, binding->remote)
.has_value();
}
bool Importer::hasDecorator(const AstNode &node, StringRef name) const {
return ruleWrites.hasDecorator(node, name);
Expand All @@ -160,7 +161,7 @@ ac::StaticExprAttr Importer::literal(uint64_t value, const AstNode &node,
ac::MathIntAttr::get(
b.getContext(),
llvm::APSInt::getUnsigned(value)))})),
b.getNamedAttr("origin", occurrence(b, symbol, node)),
b.getNamedAttr("origin", sourceOccurrence(b, symbol, node)),
b.getNamedAttr("location", sourceSpan(b, source.path, node))}));
}
Type Importer::bits(unsigned width, const AstNode &node,
Expand Down Expand Up @@ -449,8 +450,8 @@ StringRef Importer::fixedResultCall(const AstNode &node) const {
// This only recognizes a potential fixed-result syntax producer. The query
// dispatcher resolves the actual receiver and Table contract before typing
// callbacks or constructing any row-domain operation.
if (function.kind() == "Attribute" &&
(function.string("attr") == "first" || function.string("attr") == "argmin"))
if (function.kind() == "Attribute" && (function.string("attr") == "first" ||
function.string("attr") == "argmin"))
return function.string("attr");
if (function.kind() == "Subscript")
function = function.child("value");
Expand Down Expand Up @@ -691,17 +692,17 @@ LogicalResult Importer::scanStructs() {
auto type = portType(annotation, symbol);
if (failed(type))
return failure();
if (!isa<ac::BitsType, ac::StructType, ac::EnumType, ac::TableType>(*type))
if (!isa<ac::BitsType, ac::StructType, ac::EnumType, ac::TableType>(
*type))
return error() << "struct field requires bits, struct, enum or table";
if (auto table = dyn_cast<ac::TableType>(*type)) {
auto shape = ac::HardwareAnalysis(*body).resolveShape(
table.getShape(), {}, body->getOperation());
if (failed(shape))
return failure();
if (shape->size() != 1)
return error()
<< "struct Table field requires a positive closed "
"one-dimensional shape";
return error() << "struct Table field requires a positive closed "
"one-dimensional shape";
}
defaults.push_back(field.child("value"));
fields.push_back(
Expand Down Expand Up @@ -799,7 +800,7 @@ FailureOr<Value> Importer::select(Value guard, Value yes, Value no,
fixedValues.insert(result);
refineSelectFacts(result, guard, yes, no, node, symbol);
} else if (valueInfo(yes).sourceKind == ac::detail::ValueKind::Boolean &&
valueInfo(no).sourceKind == ac::detail::ValueKind::Boolean)
valueInfo(no).sourceKind == ac::detail::ValueKind::Boolean)
remember(result, ac::detail::ValueKind::Boolean);
return result;
}
Expand Down Expand Up @@ -880,9 +881,10 @@ LogicalResult Importer::proveIndex(Value table, Value index,
if (failed(size) || failed(width))
return failure();
if (info.interval && !info.interval->lower.isNegative() &&
llvm::APSInt::compareValues(info.interval->lower, info.interval->upper) < 0 &&
llvm::APSInt::compareValues(info.interval->lower, info.interval->upper) <
0 &&
llvm::APSInt::compareValues(info.interval->upper,
llvm::APSInt::getUnsigned(*size)) <= 0)
llvm::APSInt::getUnsigned(*size)) <= 0)
return success();
if (*width >= 64 || (uint64_t(1) << *width) > *size)
return mlir::emitError(node.location(b.getContext(), source.path))
Expand All @@ -892,8 +894,7 @@ LogicalResult Importer::proveIndex(Value table, Value index,
FailureOr<Value> Importer::tableUpdate(Value table, Value index,
Value replacement,
ArrayRef<Attribute> fieldPath,
const AstNode &node,
OpBuilder &at,
const AstNode &node, OpBuilder &at,
FlatSymbolRefAttr symbol,
std::optional<size_t> domainSlot) {
if (failed(proveIndex(table, index, node)))
Expand Down Expand Up @@ -948,18 +949,20 @@ FailureOr<Value> Importer::tableUpdate(Value table, Value index,
if (failed(equivalent))
return failure();
if (!*equivalent)
return error() << "table index comparison requires equivalent equal-width types";
return error()
<< "table index comparison requires equivalent equal-width types";
idx = boundaryBitsIdentity(idx, ordinalType, node, nested, symbol);
} else if (*width < ordinalWidth) {
idx = createOp(nested, loc, ac::BitsResizeOp::getOperationName(), {idx},
TypeRange{ordinalType},
{nested.getNamedAttr("mode", nested.getStringAttr("zext"))})
->getResult(0);
} else if (*width > ordinalWidth) {
ordinal = createOp(nested, loc, ac::BitsResizeOp::getOperationName(), {ordinal},
TypeRange{idx.getType()},
{nested.getNamedAttr("mode", nested.getStringAttr("zext"))})
->getResult(0);
ordinal =
createOp(nested, loc, ac::BitsResizeOp::getOperationName(), {ordinal},
TypeRange{idx.getType()},
{nested.getNamedAttr("mode", nested.getStringAttr("zext"))})
->getResult(0);
}
auto equal =
createOp(nested, loc, ac::BitsCompareOp::getOperationName(),
Expand All @@ -976,14 +979,15 @@ FailureOr<Value> Importer::tableUpdate(Value table, Value index,
// The index equality masks data only; the source owner enable is separate.
// Use each current element as the base so untouched fields never read
// through the possibly unknown index.
value = createOp(
nested, loc, ac::ValueMergeOp::getOperationName(),
{old, equal, next}, TypeRange{old.getType(), equal.getType()},
{nested.getNamedAttr(
"paths", nested.getArrayAttr({nested.getArrayAttr(fieldPath)})),
nested.getNamedAttr("operandSegmentSizes",
nested.getDenseI32ArrayAttr({1, 1, 1}))})
->getResult(0);
value =
createOp(nested, loc, ac::ValueMergeOp::getOperationName(),
{old, equal, next}, TypeRange{old.getType(), equal.getType()},
{nested.getNamedAttr(
"paths",
nested.getArrayAttr({nested.getArrayAttr(fieldPath)})),
nested.getNamedAttr("operandSegmentSizes",
nested.getDenseI32ArrayAttr({1, 1, 1}))})
->getResult(0);
}
SmallVector<Value> yields{value};
if (domainSlot) {
Expand Down Expand Up @@ -1036,17 +1040,15 @@ FailureOr<Value> Importer::unsignedBoundary(Value value, Type target,
if (failed(converted))
return failure();
value = *converted;
} else if (*equivalent && targetBits &&
isa<ac::BitsType>(value.getType()) &&
} else if (*equivalent && targetBits && isa<ac::BitsType>(value.getType()) &&
fixedValues.contains(value) &&
!ac::areEquivalentHardwareTypes(value.getType(), target)) {
// Only the width spelling changes. Keep the producer's kind and value facts
// while giving this boundary wire the declared destination type.
return boundaryBitsIdentity(value, target, node, at, symbol);
} else if (allowFixedWidening && targetBits &&
isa<ac::BitsType>(value.getType()) &&
fixedValues.contains(value) &&
!*equivalent) {
fixedValues.contains(value) && !*equivalent) {
ac::HardwareAnalysis analysis(*body);
auto *owner = at.getBlock()->getParentOp();
auto sourceWidth = analysis.getPackedWidth(value.getType(), {}, owner);
Expand Down
Loading
Loading