Zero-extend unsized signed based literal numbers when < integer_width bits.

Whilst the wording in the IEEE standards is ambiguous, discussions on
the standards committee mailing lists clarify that an unsized literal is
supposed to be the same size as an integer (as shown in IEEE 1364-2005
table 5-22). The token following the base format character is specified
to be an unsized number. So to maintain compatibility with the standards
and with other tools, if the unsigned number part of an unsized signed
based literal can be represented in less than integer_width bits and the
MSB is a '1', we need to add a leading zero to ensure it is zero-extended
when used in an expression.

This fixes issue #1082.
This commit is contained in:
Martin Whitaker 2024-01-28 11:51:42 +00:00
parent 8ee1d56e1a
commit f31d0dcbc5
1 changed files with 16 additions and 4 deletions

View File

@ -4,7 +4,7 @@
%{
/*
* Copyright (c) 1998-2023 Stephen Williams (steve@icarus.com)
* Copyright (c) 1998-2024 Stephen Williams (steve@icarus.com)
*
* This source code is free software; you can redistribute it
* and/or modify it in source code form under the terms of the GNU
@ -971,7 +971,8 @@ verinum*make_unsized_binary(const char*txt)
if ((based_size > 0) && (size > based_size)) VLwarn(yylloc,
"warning: Extra digits given for sized binary constant.");
verinum::V*bits = new verinum::V[size];
// Allocate one extra bit in case we need to zero-extend.
verinum::V*bits = new verinum::V[size+1];
unsigned idx = size;
while (*ptr) {
@ -1000,6 +1001,9 @@ verinum*make_unsized_binary(const char*txt)
if (gn_strict_expr_width_flag && (based_size == 0))
size = truncate_to_integer_width(bits, size);
if (sign_flag && (size < integer_width) && (bits[size-1] == verinum::V1))
bits[size++] = verinum::V0;
verinum*out = new verinum(bits, size, false);
out->has_sign(sign_flag);
out->is_single(single_flag);
@ -1037,7 +1041,8 @@ verinum*make_unsized_octal(const char*txt)
"warning: Extra digits given for sized octal constant.");
}
verinum::V*bits = new verinum::V[size];
// Allocate one extra bit in case we need to zero-extend.
verinum::V*bits = new verinum::V[size+1];
unsigned idx = size;
while (*ptr) {
@ -1071,6 +1076,9 @@ verinum*make_unsized_octal(const char*txt)
if (gn_strict_expr_width_flag && (based_size == 0))
size = truncate_to_integer_width(bits, size);
if (sign_flag && (size < integer_width) && (bits[size-1] == verinum::V1))
bits[size++] = verinum::V0;
verinum*out = new verinum(bits, size, false);
out->has_sign(sign_flag);
delete[]bits;
@ -1106,7 +1114,8 @@ verinum*make_unsized_hex(const char*txt)
"warning: Extra digits given for sized hex constant.");
}
verinum::V*bits = new verinum::V[size];
// Allocate one extra bit in case we need to zero-extend.
verinum::V*bits = new verinum::V[size+1];
unsigned idx = size;
while (*ptr) {
@ -1151,6 +1160,9 @@ verinum*make_unsized_hex(const char*txt)
if (gn_strict_expr_width_flag && (based_size == 0))
size = truncate_to_integer_width(bits, size);
if (sign_flag && (size < integer_width) && (bits[size-1] == verinum::V1))
bits[size++] = verinum::V0;
verinum*out = new verinum(bits, size, false);
out->has_sign(sign_flag);
delete[]bits;