Resolve type and size cast targets during elaboration
A SystemVerilog cast target can be either a type or a constant size expression. Currently the parser commits to `PECastType` or `PECastSize` based on how the target identifier is classified while parsing. This is too early for identifiers whose meaning is only known after symbol lookup. As a result, corner cases are handled incorrectly when parser-time classification does not match the result of elaboration. For example, the parser can not decide whether an identifier inherited from a base class is a type or a constant size expression. Supporting the inherited lookup is separate, but the cast target must remain unresolved until elaboration for that lookup to be used. Parse both forms through `expr_primary_or_typename` and represent them with one `PECast`. Keep atomic types wrapped in `PETypename` and preserve named targets as `PEIdent`. Resolve the target during elaboration. First use `test_type()` to distinguish a type target from a constant size expression. For a type target, use a contextual `elaborate_type()` call to resolve the type. Diagnose dimensions after a type identifier directly from `PEIdent::elaborate_type()` when it is used as a cast target. A failed type elaboration returns `nullptr` and does not fall back to interpreting the target as a size expression. Dimensions contained in the named type remain valid. Cache the resolved target information during width checking because ordinary expression elaboration needs the same information. Tag the cache with the `NetScope` and recompute it when the scope changes since type parameters can give the same cast expression a different target type in each instance. Typed elaboration can bypass width checking, so resolve into a local value when no matching cache is available. This avoids modifying the parsed expression from a const elaboration method while still avoiding repeated diagnostics between the normal width checking and expression elaboration phases. Share the type and size conversion paths between width-based and typed elaboration. Use the explicit cast target when constructing a dynamic array instead of the enclosing expression type. Own the cast target and operand with `std::unique_ptr`. Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
This commit is contained in:
parent
506eaa5415
commit
bea0fdeb3c
25
PExpr.cc
25
PExpr.cc
|
|
@ -139,31 +139,12 @@ bool PEBinary::has_aa_term(Design*des, NetScope*scope) const
|
|||
return left_->has_aa_term(des, scope) || right_->has_aa_term(des, scope);
|
||||
}
|
||||
|
||||
PECastSize::PECastSize(PExpr*si, PExpr*b)
|
||||
: size_(si), base_(b)
|
||||
PECast::PECast(PExpr *target, PExpr *base)
|
||||
: target_(target), base_(base)
|
||||
{
|
||||
}
|
||||
|
||||
PECastSize::~PECastSize()
|
||||
{
|
||||
}
|
||||
|
||||
bool PECastSize::has_aa_term(Design *des, NetScope *scope) const
|
||||
{
|
||||
return base_->has_aa_term(des, scope);
|
||||
}
|
||||
|
||||
PECastType::PECastType(data_type_t*t, PExpr*b)
|
||||
: target_(t), base_(b)
|
||||
{
|
||||
target_type_ = nullptr;
|
||||
}
|
||||
|
||||
PECastType::~PECastType()
|
||||
{
|
||||
}
|
||||
|
||||
bool PECastType::has_aa_term(Design *des, NetScope *scope) const
|
||||
bool PECast::has_aa_term(Design *des, NetScope *scope) const
|
||||
{
|
||||
return base_->has_aa_term(des, scope);
|
||||
}
|
||||
|
|
|
|||
104
PExpr.h
104
PExpr.h
|
|
@ -51,6 +51,11 @@ class PExpr : public LineInfo {
|
|||
// Mode values used by test_width() (see below for description).
|
||||
enum width_mode_t { SIZED, UNSIZED, EXPAND, LOSSLESS, UPSIZE };
|
||||
|
||||
enum class type_elaboration_context_t {
|
||||
DEFAULT,
|
||||
CAST_TARGET
|
||||
};
|
||||
|
||||
// Flag values that can be passed to elaborate_expr().
|
||||
static const unsigned NO_FLAGS = 0x0;
|
||||
static const unsigned NEED_CONST = 0x1;
|
||||
|
|
@ -132,8 +137,12 @@ class PExpr : public LineInfo {
|
|||
// may cache lookup state for a subsequent elaborate_type() call.
|
||||
virtual bool test_type(Design *des, NetScope *scope);
|
||||
|
||||
// Elaborate this expression as a type. Return null on failure.
|
||||
virtual ivl_type_t elaborate_type(Design *des, NetScope *scope) const;
|
||||
// Elaborate this expression as a type in a specific context. Return
|
||||
// null if the expression is not a type or elaboration fails.
|
||||
virtual ivl_type_t elaborate_type(
|
||||
Design *des, NetScope *scope,
|
||||
type_elaboration_context_t context =
|
||||
type_elaboration_context_t::DEFAULT) const;
|
||||
|
||||
// After the test_width method is complete, these methods
|
||||
// return valid results.
|
||||
|
|
@ -385,7 +394,10 @@ class PEIdent : public PExpr {
|
|||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const override;
|
||||
bool test_type(Design *des, NetScope *scope) override;
|
||||
ivl_type_t elaborate_type(Design *des, NetScope *scope) const override;
|
||||
ivl_type_t elaborate_type(
|
||||
Design *des, NetScope *scope,
|
||||
type_elaboration_context_t context =
|
||||
type_elaboration_context_t::DEFAULT) const override;
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const override;
|
||||
|
|
@ -732,7 +744,10 @@ class PETypename : public PExpr {
|
|||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const override;
|
||||
bool test_type(Design *des, NetScope *scope) override;
|
||||
ivl_type_t elaborate_type(Design *des, NetScope *scope) const override;
|
||||
ivl_type_t elaborate_type(
|
||||
Design *des, NetScope *scope,
|
||||
type_elaboration_context_t context =
|
||||
type_elaboration_context_t::DEFAULT) const override;
|
||||
|
||||
private:
|
||||
data_type_t*data_type_;
|
||||
|
|
@ -1041,57 +1056,64 @@ class PECallFunction : public PExpr {
|
|||
unsigned test_width_chain_(Design*des, NetScope*scope, width_mode_t&mode);
|
||||
};
|
||||
|
||||
/*
|
||||
* Support the SystemVerilog cast to size.
|
||||
*/
|
||||
class PECastSize : public PExpr {
|
||||
/* Support SystemVerilog size and type casts. */
|
||||
class PECast : public PExpr {
|
||||
|
||||
public:
|
||||
explicit PECastSize(PExpr*size, PExpr*base);
|
||||
~PECastSize() override;
|
||||
explicit PECast(PExpr *target, PExpr *base);
|
||||
~PECast() override = default;
|
||||
|
||||
void dump(std::ostream &out) const override;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid,
|
||||
unsigned flags) const override;
|
||||
NetExpr *elaborate_expr(Design *des, NetScope *scope,
|
||||
ivl_type_t type, unsigned int flags) const override;
|
||||
|
||||
virtual bool has_aa_term(Design *des, NetScope *scope) const override;
|
||||
NetExpr *elaborate_expr(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
unsigned int flags) const override;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
width_mode_t&mode) override;
|
||||
bool has_aa_term(Design *des, NetScope *scope) const override;
|
||||
|
||||
unsigned int test_width(Design *des, NetScope *scope,
|
||||
width_mode_t &mode) override;
|
||||
|
||||
private:
|
||||
PExpr* size_;
|
||||
PExpr* base_;
|
||||
};
|
||||
NetExpr *elaborate_size_cast_(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
unsigned int target_width,
|
||||
bool signed_flag,
|
||||
unsigned int flags) const;
|
||||
NetExpr *elaborate_type_cast_(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
ivl_type_t target_type,
|
||||
unsigned int target_width,
|
||||
bool signed_flag,
|
||||
unsigned int flags) const;
|
||||
|
||||
/*
|
||||
* Support the SystemVerilog cast to a different type.
|
||||
*/
|
||||
class PECastType : public PExpr {
|
||||
enum class target_kind_t {
|
||||
ERROR,
|
||||
SIZE,
|
||||
TYPE
|
||||
};
|
||||
|
||||
public:
|
||||
explicit PECastType(data_type_t*target, PExpr*base);
|
||||
~PECastType() override;
|
||||
struct target_info_t {
|
||||
target_kind_t kind = target_kind_t::ERROR;
|
||||
ivl_type_t type = nullptr;
|
||||
unsigned int width = 0;
|
||||
};
|
||||
|
||||
void dump(std::ostream &out) const override;
|
||||
target_info_t resolve_target_(Design *des, NetScope *scope) const;
|
||||
target_info_t target_for_scope_(Design *des, NetScope *scope) const;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const override;
|
||||
std::unique_ptr<PExpr> target_;
|
||||
std::unique_ptr<PExpr> base_;
|
||||
|
||||
virtual NetExpr*elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const override;
|
||||
|
||||
virtual bool has_aa_term(Design *des, NetScope *scope) const override;
|
||||
|
||||
virtual unsigned test_width(Design*des, NetScope*scope,
|
||||
width_mode_t&mode) override;
|
||||
|
||||
private:
|
||||
data_type_t* target_;
|
||||
ivl_type_t target_type_;
|
||||
PExpr* base_;
|
||||
// Cast targets can depend on parameters in the instance scope. Width
|
||||
// testing and expression elaboration run sequentially for one scope, so
|
||||
// retain only the most recent result.
|
||||
const NetScope *target_scope_ = nullptr;
|
||||
target_info_t target_info_;
|
||||
bool target_resolved_ = false;
|
||||
};
|
||||
|
||||
/*
|
||||
|
|
|
|||
370
elab_expr.cc
370
elab_expr.cc
|
|
@ -488,7 +488,8 @@ unsigned PExpr::test_width(Design*des, NetScope*, width_mode_t&)
|
|||
return 1;
|
||||
}
|
||||
|
||||
ivl_type_t PExpr::elaborate_type(Design *, NetScope *) const
|
||||
ivl_type_t PExpr::elaborate_type(
|
||||
Design *, NetScope *, type_elaboration_context_t) const
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
|
|
@ -4219,151 +4220,263 @@ NetExpr* PECallFunction::elaborate_expr_method_par_(Design*des, const NetScope*s
|
|||
return 0;
|
||||
}
|
||||
|
||||
unsigned PECastSize::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
struct cast_type_info_t {
|
||||
ivl_variable_type_t expr_type;
|
||||
unsigned int width;
|
||||
};
|
||||
|
||||
static cast_type_info_t cast_type_info(ivl_type_t type)
|
||||
{
|
||||
ivl_assert(*this, size_);
|
||||
if (auto darray = dynamic_cast<const netdarray_t *>(type)) {
|
||||
return { darray->element_base_type(),
|
||||
static_cast<unsigned int>(darray->element_width()) };
|
||||
}
|
||||
|
||||
if (auto string_type = dynamic_cast<const netstring_t *>(type)) {
|
||||
return { string_type->base_type(), 8 };
|
||||
}
|
||||
|
||||
return { type->base_type(),
|
||||
static_cast<unsigned int>(type->packed_width()) };
|
||||
}
|
||||
|
||||
static unsigned int evaluate_cast_size(Design *des, NetScope *scope,
|
||||
PExpr *target, const LineInfo &loc)
|
||||
{
|
||||
unsigned int width = 0;
|
||||
auto size_expr = elab_and_eval(des, scope, target, -1, true);
|
||||
auto size_const = dynamic_cast<NetEConst *>(size_expr);
|
||||
if (size_const && !size_const->value().is_negative())
|
||||
width = size_const->value().as_ulong();
|
||||
delete size_expr;
|
||||
|
||||
if (width == 0) {
|
||||
cerr << loc.get_fileline() << ": error: Cast size expression "
|
||||
<< "must be constant and greater than zero." << endl;
|
||||
des->errors += 1;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
static bool test_size_cast_base(Design *des, NetScope *scope, PExpr *base,
|
||||
const LineInfo &loc)
|
||||
{
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
base->test_width(des, scope, mode);
|
||||
|
||||
if (type_is_vectorable(base->expr_type()))
|
||||
return true;
|
||||
|
||||
cerr << loc.get_fileline() << ": error: Cast base expression "
|
||||
<< "must be a vector type." << endl;
|
||||
des->errors += 1;
|
||||
return false;
|
||||
}
|
||||
|
||||
PECast::target_info_t PECast::resolve_target_(Design *des,
|
||||
NetScope *scope) const
|
||||
{
|
||||
target_info_t target_info;
|
||||
|
||||
if (target_->test_type(des, scope)) {
|
||||
auto type = target_->elaborate_type(
|
||||
des, scope, PExpr::type_elaboration_context_t::CAST_TARGET);
|
||||
if (!type)
|
||||
return target_info;
|
||||
|
||||
target_info.kind = target_kind_t::TYPE;
|
||||
target_info.type = type;
|
||||
return target_info;
|
||||
}
|
||||
|
||||
target_info.width = evaluate_cast_size(
|
||||
des, scope, target_.get(), *this);
|
||||
if (target_info.width != 0)
|
||||
target_info.kind = target_kind_t::SIZE;
|
||||
|
||||
return target_info;
|
||||
}
|
||||
|
||||
PECast::target_info_t PECast::target_for_scope_(Design *des,
|
||||
NetScope *scope) const
|
||||
{
|
||||
if (target_resolved_ && target_scope_ == scope)
|
||||
return target_info_;
|
||||
|
||||
return resolve_target_(des, scope);
|
||||
}
|
||||
|
||||
unsigned int PECast::test_width(Design *des, NetScope *scope, width_mode_t &)
|
||||
{
|
||||
ivl_assert(*this, target_);
|
||||
ivl_assert(*this, base_);
|
||||
|
||||
expr_width_ = 0;
|
||||
|
||||
NetExpr*size_ex = elab_and_eval(des, scope, size_, -1, true);
|
||||
const NetEConst*size_ce = dynamic_cast<NetEConst*>(size_ex);
|
||||
if (size_ce && !size_ce->value().is_negative())
|
||||
expr_width_ = size_ce->value().as_ulong();
|
||||
delete size_ex;
|
||||
if (expr_width_ == 0) {
|
||||
cerr << get_fileline() << ": error: Cast size expression "
|
||||
"must be constant and greater than zero." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
if (!target_resolved_ || target_scope_ != scope) {
|
||||
target_info_ = resolve_target_(des, scope);
|
||||
target_scope_ = scope;
|
||||
target_resolved_ = true;
|
||||
}
|
||||
|
||||
width_mode_t tmp_mode = PExpr::SIZED;
|
||||
base_->test_width(des, scope, tmp_mode);
|
||||
|
||||
if (!type_is_vectorable(base_->expr_type())) {
|
||||
cerr << get_fileline() << ": error: Cast base expression "
|
||||
"must be a vector type." << endl;
|
||||
des->errors += 1;
|
||||
const auto &target_info = target_info_;
|
||||
if (target_info.kind == target_kind_t::ERROR)
|
||||
return 0;
|
||||
|
||||
if (target_info.kind == target_kind_t::TYPE) {
|
||||
width_mode_t mode = PExpr::SIZED;
|
||||
base_->test_width(des, scope, mode);
|
||||
|
||||
auto type_info = cast_type_info(target_info.type);
|
||||
expr_type_ = type_info.expr_type;
|
||||
expr_width_ = type_info.width;
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = target_info.type->get_signed();
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
expr_type_ = base_->expr_type();
|
||||
min_width_ = expr_width_;
|
||||
ivl_assert(*this, target_info.kind == target_kind_t::SIZE);
|
||||
expr_width_ = target_info.width;
|
||||
if (!test_size_cast_base(des, scope, base_.get(), *this))
|
||||
return 0;
|
||||
|
||||
expr_type_ = base_->expr_type();
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = base_->has_sign();
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
NetExpr* PECastSize::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
NetExpr *PECast::elaborate_expr(Design *des, NetScope *scope, ivl_type_t,
|
||||
unsigned int flags) const
|
||||
{
|
||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||
|
||||
ivl_assert(*this, size_);
|
||||
ivl_assert(*this, target_);
|
||||
ivl_assert(*this, base_);
|
||||
|
||||
auto target_info = target_for_scope_(des, scope);
|
||||
if (target_info.kind == target_kind_t::ERROR)
|
||||
return nullptr;
|
||||
|
||||
if (target_info.kind == target_kind_t::TYPE) {
|
||||
width_mode_t mode = PExpr::SIZED;
|
||||
base_->test_width(des, scope, mode);
|
||||
|
||||
auto type_info = cast_type_info(target_info.type);
|
||||
return elaborate_type_cast_(des, scope, type_info.width,
|
||||
target_info.type, type_info.width,
|
||||
target_info.type->get_signed(),
|
||||
flags);
|
||||
}
|
||||
|
||||
ivl_assert(*this, target_info.kind == target_kind_t::SIZE);
|
||||
return elaborate_size_cast_(des, scope, target_info.width,
|
||||
target_info.width,
|
||||
base_->has_sign(), flags);
|
||||
}
|
||||
|
||||
NetExpr *PECast::elaborate_expr(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
unsigned int flags) const
|
||||
{
|
||||
ivl_assert(*this, target_);
|
||||
ivl_assert(*this, base_);
|
||||
|
||||
auto target_info = target_for_scope_(des, scope);
|
||||
if (target_info.kind == target_kind_t::ERROR)
|
||||
return nullptr;
|
||||
|
||||
if (target_info.kind == target_kind_t::TYPE) {
|
||||
auto type_info = cast_type_info(target_info.type);
|
||||
return elaborate_type_cast_(des, scope, expr_wid, target_info.type,
|
||||
type_info.width, signed_flag_,
|
||||
flags);
|
||||
}
|
||||
|
||||
ivl_assert(*this, target_info.kind == target_kind_t::SIZE);
|
||||
return elaborate_size_cast_(des, scope, expr_wid, target_info.width,
|
||||
signed_flag_, flags);
|
||||
}
|
||||
|
||||
NetExpr *PECast::elaborate_size_cast_(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
unsigned int target_width,
|
||||
bool signed_flag,
|
||||
unsigned int flags) const
|
||||
{
|
||||
flags &= ~SYS_TASK_ARG;
|
||||
|
||||
// A cast behaves exactly like an assignment to a temporary variable,
|
||||
// so the temporary result size may affect the sub-expression width.
|
||||
unsigned cast_width = base_->expr_width();
|
||||
if (cast_width < expr_width_)
|
||||
cast_width = expr_width_;
|
||||
unsigned int cast_width = base_->expr_width();
|
||||
if (cast_width < target_width)
|
||||
cast_width = target_width;
|
||||
|
||||
NetExpr*sub = base_->elaborate_expr(des, scope, cast_width, flags);
|
||||
if (sub == 0)
|
||||
return 0;
|
||||
auto sub = base_->elaborate_expr(des, scope, cast_width, flags);
|
||||
if (!sub)
|
||||
return nullptr;
|
||||
|
||||
// Perform the cast. The extension method (zero/sign), if needed,
|
||||
// depends on the type of the base expression.
|
||||
NetExpr*tmp = cast_to_width(sub, expr_width_, base_->has_sign(), *this);
|
||||
auto tmp = cast_to_width(sub, target_width, base_->has_sign(), *this);
|
||||
|
||||
// Pad up to the expression width. The extension method (zero/sign)
|
||||
// depends on the type of enclosing expression.
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this);
|
||||
return pad_to_width(tmp, expr_wid, signed_flag, *this);
|
||||
}
|
||||
|
||||
unsigned PECastType::test_width(Design*des, NetScope*scope, width_mode_t&)
|
||||
NetExpr *PECast::elaborate_type_cast_(Design *des, NetScope *scope,
|
||||
unsigned int expr_wid,
|
||||
ivl_type_t target_type,
|
||||
unsigned int target_width,
|
||||
bool signed_flag,
|
||||
unsigned int flags) const
|
||||
{
|
||||
target_type_ = target_->elaborate_type(des, scope);
|
||||
auto darray = dynamic_cast<const netdarray_t *>(target_type);
|
||||
auto vector = darray
|
||||
? dynamic_cast<const netvector_t *>(darray->element_type())
|
||||
: nullptr;
|
||||
if (vector) {
|
||||
unsigned int use_width = base_->expr_width();
|
||||
auto base_expr = base_->elaborate_expr(des, scope, use_width,
|
||||
NO_FLAGS);
|
||||
if (!base_expr)
|
||||
return nullptr;
|
||||
|
||||
width_mode_t tmp_mode = PExpr::SIZED;
|
||||
base_->test_width(des, scope, tmp_mode);
|
||||
ivl_assert(*this, vector->packed_width() > 0);
|
||||
ivl_assert(*this, base_expr->expr_width() > 0);
|
||||
|
||||
if (const netdarray_t*use_darray = dynamic_cast<const netdarray_t*>(target_type_)) {
|
||||
expr_type_ = use_darray->element_base_type();
|
||||
expr_width_ = use_darray->element_width();
|
||||
// Find the number of elements needed to contain the source value.
|
||||
int length = base_expr->expr_width() + vector->packed_width() - 1;
|
||||
if (base_expr->expr_width() >
|
||||
static_cast<unsigned int>(vector->packed_width()))
|
||||
length /= vector->packed_width();
|
||||
else
|
||||
length /= base_expr->expr_width();
|
||||
|
||||
} else if (const netstring_t*use_string = dynamic_cast<const netstring_t*>(target_type_)) {
|
||||
expr_type_ = use_string->base_type();
|
||||
expr_width_ = 8;
|
||||
|
||||
} else {
|
||||
expr_type_ = target_type_->base_type();
|
||||
expr_width_ = target_type_->packed_width();
|
||||
auto length_expr = new NetEConst(verinum(length));
|
||||
return new NetENew(target_type, length_expr, base_expr);
|
||||
}
|
||||
min_width_ = expr_width_;
|
||||
signed_flag_ = target_type_->get_signed();
|
||||
|
||||
return expr_width_;
|
||||
}
|
||||
|
||||
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
||||
ivl_type_t type, unsigned flags) const
|
||||
{
|
||||
const netdarray_t*darray = NULL;
|
||||
const netvector_t*vector = NULL;
|
||||
|
||||
// Casting array of vectors to dynamic array type
|
||||
if((darray = dynamic_cast<const netdarray_t*>(type)) &&
|
||||
(vector = dynamic_cast<const netvector_t*>(darray->element_type()))) {
|
||||
PExpr::width_mode_t mode = PExpr::SIZED;
|
||||
unsigned use_wid = base_->test_width(des, scope, mode);
|
||||
NetExpr*base = base_->elaborate_expr(des, scope, use_wid, NO_FLAGS);
|
||||
|
||||
ivl_assert(*this, vector->packed_width() > 0);
|
||||
ivl_assert(*this, base->expr_width() > 0);
|
||||
|
||||
// Find rounded up length that can fit the whole casted array of vectors
|
||||
int len = base->expr_width() + vector->packed_width() - 1;
|
||||
if(base->expr_width() > (unsigned)vector->packed_width()) {
|
||||
len /= vector->packed_width();
|
||||
} else {
|
||||
len /= base->expr_width();
|
||||
}
|
||||
|
||||
// Number of words in the created dynamic array
|
||||
NetEConst*len_expr = new NetEConst(verinum(len));
|
||||
return new NetENew(type, len_expr, base);
|
||||
}
|
||||
|
||||
// Fallback
|
||||
return elaborate_expr(des, scope, (unsigned) 0, flags);
|
||||
}
|
||||
|
||||
NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
||||
unsigned expr_wid, unsigned flags) const
|
||||
{
|
||||
flags &= ~SYS_TASK_ARG; // don't propagate the SYS_TASK_ARG flag
|
||||
flags &= ~SYS_TASK_ARG;
|
||||
|
||||
// A cast behaves exactly like an assignment to a temporary variable,
|
||||
// so the temporary result size may affect the sub-expression width.
|
||||
unsigned cast_width = base_->expr_width();
|
||||
if (type_is_vectorable(base_->expr_type()) && (cast_width < expr_width_))
|
||||
cast_width = expr_width_;
|
||||
unsigned int cast_width = base_->expr_width();
|
||||
if (type_is_vectorable(base_->expr_type()) &&
|
||||
cast_width < target_width)
|
||||
cast_width = target_width;
|
||||
|
||||
NetExpr*sub = base_->elaborate_expr(des, scope, cast_width, flags);
|
||||
if (sub == 0)
|
||||
return 0;
|
||||
auto sub = base_->elaborate_expr(des, scope, cast_width, flags);
|
||||
if (!sub)
|
||||
return nullptr;
|
||||
|
||||
NetExpr*tmp = 0;
|
||||
if (dynamic_cast<const netreal_t*>(target_type_)) {
|
||||
NetExpr *tmp = nullptr;
|
||||
if (dynamic_cast<const netreal_t *>(target_type)) {
|
||||
switch (sub->expr_type()) {
|
||||
case IVL_VT_REAL:
|
||||
return sub;
|
||||
case IVL_VT_LOGIC:
|
||||
case IVL_VT_BOOL:
|
||||
return cast_to_real(sub);
|
||||
default:
|
||||
default:
|
||||
break;
|
||||
}
|
||||
cerr << get_fileline() << " error: Expression of type `"
|
||||
|
|
@ -4371,40 +4484,42 @@ NetExpr* PECastType::elaborate_expr(Design*des, NetScope*scope,
|
|||
<< endl;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
} else if (dynamic_cast<const netstring_t*>(target_type_)) {
|
||||
}
|
||||
|
||||
if (dynamic_cast<const netstring_t *>(target_type)) {
|
||||
if (base_->expr_type() == IVL_VT_STRING)
|
||||
return sub; // no conversion
|
||||
return sub;
|
||||
if (base_->expr_type() == IVL_VT_LOGIC ||
|
||||
base_->expr_type() == IVL_VT_BOOL)
|
||||
return sub; // handled by the target as special cases
|
||||
} else if (target_type_ && target_type_->packed()) {
|
||||
switch (target_type_->base_type()) {
|
||||
return sub;
|
||||
} else if (target_type->packed()) {
|
||||
switch (target_type->base_type()) {
|
||||
case IVL_VT_BOOL:
|
||||
tmp = cast_to_int2(sub, expr_width_);
|
||||
tmp = cast_to_int2(sub, target_width);
|
||||
break;
|
||||
|
||||
case IVL_VT_LOGIC:
|
||||
tmp = cast_to_int4(sub, expr_width_);
|
||||
tmp = cast_to_int4(sub, target_width);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (tmp) {
|
||||
if (tmp == sub) {
|
||||
// We already had the correct base type, so we just need to
|
||||
// fix the size. Note that even if the size is already correct,
|
||||
// we still need to isolate the sub-expression from changes in
|
||||
// the signedness pushed down from the main expression.
|
||||
tmp = cast_to_width(sub, expr_width_, sub->has_sign(), *this);
|
||||
// we still need to isolate the sub-expression from changes in
|
||||
// the signedness pushed down from the main expression.
|
||||
tmp = cast_to_width(sub, target_width, sub->has_sign(), *this);
|
||||
}
|
||||
return pad_to_width(tmp, expr_wid, signed_flag_, *this, target_type_);
|
||||
return pad_to_width(tmp, expr_wid, signed_flag, *this, target_type);
|
||||
}
|
||||
|
||||
cerr << get_fileline() << ": sorry: This cast operation is not yet supported." << endl;
|
||||
cerr << get_fileline()
|
||||
<< ": sorry: This cast operation is not yet supported." << endl;
|
||||
des->errors += 1;
|
||||
return 0;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
unsigned PECastSign::test_width(Design *des, NetScope *scope, width_mode_t &mode)
|
||||
|
|
@ -5078,7 +5193,9 @@ static bool elaborate_type_dimensions(Design *des, NetScope *scope,
|
|||
return dimensions_ok;
|
||||
}
|
||||
|
||||
ivl_type_t PEIdent::elaborate_type(Design *des, NetScope *scope) const
|
||||
ivl_type_t PEIdent::elaborate_type(
|
||||
Design *des, NetScope *scope,
|
||||
type_elaboration_context_t context) const
|
||||
{
|
||||
symbol_search_results search_results;
|
||||
NetScope *declaration_scope;
|
||||
|
|
@ -5110,11 +5227,21 @@ ivl_type_t PEIdent::elaborate_type(Design *des, NetScope *scope) const
|
|||
return nullptr;
|
||||
}
|
||||
|
||||
const auto &name = path_.name.front();
|
||||
if (context == type_elaboration_context_t::CAST_TARGET &&
|
||||
!name.index.empty()) {
|
||||
cerr << get_fileline() << ": error: Dimensions after a type "
|
||||
<< "identifier are not allowed in a cast target." << endl;
|
||||
cerr << type_def->get_fileline()
|
||||
<< ": : The type was declared here." << endl;
|
||||
des->errors++;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
ivl_type_t base_type = type_def->elaborate_type(des, declaration_scope);
|
||||
if (!base_type)
|
||||
return nullptr;
|
||||
|
||||
const auto &name = path_.name.front();
|
||||
netranges_t packed_dimensions;
|
||||
if (!elaborate_type_dimensions(des, scope, name.index,
|
||||
packed_dimensions))
|
||||
|
|
@ -8023,7 +8150,8 @@ NetExpr* PETernary::elab_and_eval_alternative_(Design*des, NetScope*scope,
|
|||
* A typename expression is only legal in very narrow cases. This is
|
||||
* just a placeholder.
|
||||
*/
|
||||
ivl_type_t PETypename::elaborate_type(Design *des, NetScope *scope) const
|
||||
ivl_type_t PETypename::elaborate_type(
|
||||
Design *des, NetScope *scope, type_elaboration_context_t) const
|
||||
{
|
||||
return data_type_->elaborate_type(des, scope);
|
||||
}
|
||||
|
|
|
|||
51
parse.y
51
parse.y
|
|
@ -1235,7 +1235,7 @@ Module::port_t *module_declare_interface_port(const YYLTYPE&loc, char *type,
|
|||
%type <data_type> data_type data_type_opt data_type_or_implicit data_type_or_implicit_or_void
|
||||
%type <data_type> block_reg_data_type
|
||||
%type <data_type> implicit_type
|
||||
%type <data_type> reg_prefixed_atomic_type simple_type_or_string let_formal_type
|
||||
%type <data_type> reg_prefixed_atomic_type let_formal_type
|
||||
%type <data_type> packed_array_data_type atomic_type
|
||||
|
||||
%type <data_type> ps_type_identifier ps_type_identifier_dim
|
||||
|
|
@ -2900,35 +2900,6 @@ simple_immediate_assertion_statement /* IEEE1800-2012 A.6.10 */
|
|||
}
|
||||
;
|
||||
|
||||
simple_type_or_string /* IEEE1800-2005: A.2.2.1 */
|
||||
: integer_vector_type
|
||||
{ vector_type_t*tmp = new vector_type_t($1, false, 0);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| non_integer_type
|
||||
{ real_type_t*tmp = new real_type_t($1);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| atom_type
|
||||
{ atom_type_t*tmp = new atom_type_t($1, true);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_time
|
||||
{ atom_type_t*tmp = new atom_type_t(atom_type_t::TIME, false);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| K_string
|
||||
{ string_type_t*tmp = new string_type_t;
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
}
|
||||
| ps_type_identifier
|
||||
;
|
||||
|
||||
/* Many places where statements are allowed can actually take a
|
||||
statement or a null statement marked with a naked semi-colon. */
|
||||
|
||||
|
|
@ -4983,24 +4954,14 @@ expr_primary
|
|||
|
||||
/* Cast expressions are primaries */
|
||||
|
||||
| expr_primary '\'' '(' expression ')'
|
||||
{ PExpr*base = $4;
|
||||
if (pform_requires_sv(@1, "Size cast")) {
|
||||
PECastSize*tmp = new PECastSize($1, base);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
$$ = base;
|
||||
}
|
||||
}
|
||||
|
||||
| simple_type_or_string '\'' '(' expression ')'
|
||||
{ PExpr*base = $4;
|
||||
if (pform_requires_sv(@1, "Type cast")) {
|
||||
PECastType*tmp = new PECastType($1, base);
|
||||
| expr_primary_or_typename '\'' '(' expression ')'
|
||||
{ auto base = $4;
|
||||
if (pform_requires_sv(@1, "Cast expression")) {
|
||||
auto tmp = new PECast($1, base);
|
||||
FILE_NAME(tmp, @1);
|
||||
$$ = tmp;
|
||||
} else {
|
||||
delete $1;
|
||||
$$ = base;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -431,16 +431,9 @@ void PECallFunction::dump(ostream &out) const
|
|||
}
|
||||
}
|
||||
|
||||
void PECastSize::dump(ostream &out) const
|
||||
void PECast::dump(ostream &out) const
|
||||
{
|
||||
out << *size_ << "'(";
|
||||
base_->dump(out);
|
||||
out << ")";
|
||||
}
|
||||
|
||||
void PECastType::dump(ostream &out) const
|
||||
{
|
||||
target_->pform_dump(out, 0);
|
||||
target_->dump(out);
|
||||
out << "'(";
|
||||
base_->dump(out);
|
||||
out << ")";
|
||||
|
|
@ -533,7 +526,7 @@ void PETernary::dump(ostream&out) const
|
|||
|
||||
void PETypename::dump(ostream&fd) const
|
||||
{
|
||||
fd << "<type>";
|
||||
data_type_->pform_dump(fd, 0);
|
||||
}
|
||||
|
||||
void PEUnary::dump(ostream&out) const
|
||||
|
|
|
|||
Loading…
Reference in New Issue