From f31d0dcbc5ddcd97e1e2e6f7bc7eb0f5a547fe16 Mon Sep 17 00:00:00 2001 From: Martin Whitaker Date: Sun, 28 Jan 2024 11:51:42 +0000 Subject: [PATCH] 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. --- lexor.lex | 20 ++++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/lexor.lex b/lexor.lex index 22851ee29..f94c68f5f 100644 --- a/lexor.lex +++ b/lexor.lex @@ -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;