Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add P4-14 type checker logging #343

Merged
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
74 changes: 53 additions & 21 deletions frontends/p4-14/typecheck.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,16 @@ limitations under the License.
// - set type for Member and HeaderStackItemRefs
class TypeCheck::AssignInitialTypes : public Transform {
const IR::V1Program *global = nullptr;

template <typename NodeType, typename TypeType>
void setType(NodeType* currentNode, const TypeType* type) {
BUG_CHECK(currentNode == getCurrentNode<NodeType>(),
"Expected to be called on the visitor's current node");
currentNode->type = type;
if (type != getOriginal<NodeType>()->type)
LOG1("Set initial type " << type << " for expression " << currentNode);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably be LOG2 or even LOG3

( see https://github.com/p4lang/p4c/blob/master/docs/README.md -- towards the end)

}

const IR::Node *preorder(IR::V1Program *glob) override { global = glob; return glob; }
const IR::Node *preorder(IR::PathExpression *ref) override {
if (auto af = findContext<IR::ActionFunction>())
Expand All @@ -49,17 +59,17 @@ class TypeCheck::AssignInitialTypes : public Transform {
const IR::Node *preorder(IR::Metadata *m) override {
if (!global) return m;
if (auto ht = global->get<IR::v1HeaderType>(m->type_name))
m->type = ht->as_metadata;
setType(m, ht->as_metadata);
else
error("%s: No header type %s defined", m->srcInfo, m->type_name);
return m; }
const IR::Node *preorder(IR::BoolLiteral* b) override {
b->type = IR::Type_Boolean::get();
setType(b, IR::Type_Boolean::get());
return b; }
const IR::Node *preorder(IR::HeaderOrMetadata *hm) override {
if (!global) return hm;
if (auto ht = global->get<IR::v1HeaderType>(hm->type_name))
hm->type = ht->as_header;
setType(hm, ht->as_header);
else
error("%s: No header type %s defined", hm->srcInfo, hm->type_name);
return hm; }
Expand Down Expand Up @@ -123,7 +133,7 @@ class TypeCheck::AssignInitialTypes : public Transform {
if (auto hdr = findContext<IR::Type_StructLike>()) {
if (auto field = hdr->getField(ref->path->name)) {
/* FIXME -- Should this be converted to something else? */
ref->type = field->type;
setType(ref, field->type);
visit(ref->type);
return ref; } }
error("%s: No defintion for %s", ref->srcInfo, ref->path->name); }
Expand All @@ -138,21 +148,21 @@ class TypeCheck::AssignInitialTypes : public Transform {
return ref; }
const IR::Node *postorder(IR::HeaderStackItemRef *ref) override {
if (auto ht = ref->base()->type->to<IR::Type_StructLike>())
ref->type = ht;
setType(ref, ht);
else if (auto hst = ref->base()->type->to<IR::Type_Stack>())
ref->type = hst->elementType;
setType(ref, hst->elementType);
else
error("%s: %s is not a header", ref->base()->srcInfo, ref->base()->toString());
visit(ref->type);
return ref; }
const IR::Node *postorder(IR::Member *ref) override {
if (ref->member.toString()[0] == '$') {
if (ref->member == "$valid")
ref->type = IR::Type::Boolean::get();
setType(ref, IR::Type::Boolean::get());
} else if (auto ht = ref->expr->type->to<IR::Type_StructLike>()) {
auto f = ht->getField(ref->member);
if (f != nullptr) {
ref->type = f->type;
setType(ref, f->type);
visit(ref->type);
return ref; }
error("%s: No field named %s in %s", ref->srcInfo, ref->member, ht->name); }
Expand Down Expand Up @@ -187,37 +197,50 @@ combineTypes(const Util::SourceInfo &loc, const IR::Type *a, const IR::Type *b)
// bottom up type inferencing -- set the types of expression nodes based on operands
class TypeCheck::InferExpressionsBottomUp : public Modifier {
TypeCheck &self;
void setType(IR::Expression* currentNode, const IR::Type* type) {
BUG_CHECK(currentNode == getCurrentNode<IR::Expression>(),
"Expected to be called on the visitor's current node");
currentNode->type = type;
if (type != getOriginal<IR::Expression>()->type)
LOG1("Inferred type " << type << " for expression " << currentNode);
}
void postorder(IR::Operation_Binary *op) override {
if (op->left->type->is<IR::Type_InfInt>()) {
op->type = op->right->type;
setType(op, op->right->type);
} else if (op->right->type->is<IR::Type_InfInt>()) {
op->type = op->left->type;
setType(op, op->left->type);
} else if (op->left->type == op->right->type) {
op->type = op->left->type;
setType(op, op->left->type);
} else {
auto *lt = op->left->type->to<IR::Type::Bits>();
auto *rt = op->right->type->to<IR::Type::Bits>();
if (lt && rt) {
if (lt->size < rt->size)
op->left = new IR::Cast(rt, op->left);
else if (rt->size < lt->size)
op->right = new IR::Cast(lt, op->right); } } }
op->right = new IR::Cast(lt, op->right);
LOG1("Inserted cast in " << op);
}
}
}
void logic_operand(const IR::Expression *&op) {
if (auto *bit = op->type->to<IR::Type::Bits>())
op = new IR::Neq(IR::Type::Boolean::get(), op, new IR::Constant(bit, 0)); }
if (auto *bit = op->type->to<IR::Type::Bits>()) {
LOG1("Inserted bool conversion for " << op);
op = new IR::Neq(IR::Type::Boolean::get(), op, new IR::Constant(bit, 0));
} }
void postorder(IR::LAnd *op) override {
logic_operand(op->left);
logic_operand(op->right);
op->type = IR::Type::Boolean::get(); }
setType(op, IR::Type::Boolean::get()); }
void postorder(IR::LOr *op) override {
logic_operand(op->left);
logic_operand(op->right);
op->type = IR::Type::Boolean::get(); }
setType(op, IR::Type::Boolean::get()); }
void postorder(IR::LNot *op) override {
logic_operand(op->expr);
op->type = IR::Type::Boolean::get(); }
setType(op, IR::Type::Boolean::get()); }
void postorder(IR::Operation_Relation *op) override {
op->type = IR::Type::Boolean::get(); }
setType(op, IR::Type::Boolean::get()); }

public:
explicit InferExpressionsBottomUp(TypeCheck &s) : self(s) {}
Expand Down Expand Up @@ -265,8 +288,12 @@ class TypeCheck::InferExpressionsTopDown : public Modifier {
bool preorder(IR::Expression *op) override {
if (op->type == IR::Type::Unknown::get() || op->type->is<IR::Type_InfInt>()) {
auto *type = inferTypeFromContext(getContext(), global);
if (type != IR::Type::Unknown::get())
op->type = type; }
if (type != IR::Type::Unknown::get() &&
type != getOriginal<IR::Expression>()->type) {
op->type = type;
LOG1("Inferred type " << type << " for expression " << op);
}
}
return true; }

public:
Expand Down Expand Up @@ -368,7 +395,12 @@ class TypeCheck::AssignActionArgTypes : public Modifier {
// Assign the type we computed in the previous passes.
BUG_CHECK(self.actionArgUseTypes.count(getOriginal()) > 0,
"Didn't compute a type for action arg %1%", getOriginal());
arg->type = self.actionArgUseTypes[getOriginal()];
auto type = self.actionArgUseTypes[getOriginal()];
if (type != getOriginal<IR::ActionArg>()->type) {
arg->type = type;
LOG1("Inferred type " << arg->type << " for action argument " << arg);
}

return true;
}

Expand Down
8 changes: 8 additions & 0 deletions ir/visitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ class Visitor {
const Context *c = ctxt;
return findOrigCtxt<T>(c); }

/// @return the current node - i.e., the node that was passed to preorder()
/// or postorder(). For Modifiers and Transforms, this is a clone of the
/// node returned by getOriginal().
const IR::Node* getCurrentNode() const { return ctxt->node; }
template <class T>
const T* getCurrentNode() const {
return ctxt->node ? ctxt->node->to<T>() : nullptr; }

protected:
// if visitDagOnce is set to 'false' (usually in the derived Visitor
// class constructor), nodes that appear multiple times in the tree
Expand Down