473,395 Members | 1,652 Online
Bytes | Software Development & Data Engineering Community
Post Job

Home Posts Topics Members FAQ

Join Bytes to post your question to a community of 473,395 software developers and data experts.

Integer demotion requirements in ANSI-C

Hi, I just signed in to this excellent network.
I hope I could get some answers to many questions
I have in writing C compilers.

My first question is:

Is "integer demotion" required in ANSI-C?

Assumption:
- CPU: 32-bit RISC (int = long = 4 bytes, short = 2 bytes, char = 1 byte)
- All integral operations done on 4 bytes (signed or unsigned int)
- Each 32-bit register holds one integral type data that is
"already" integer promoted, so that arithmetic conversion is
unnecessary when used as operands in integral operations.
- Integer demotion on mem-store and integer promotion on mem-load is
handled by the memory interface hardware. So if you save a short integer to
memory, and then read it back, it will have correct "already integer promoted"
bit pattern in the register.

The question here is: do I need to perform integer demotion where the destination is another register?

Example 1:
char i;
for(i = 0; i < n; i = i + 1){...}

Here, "char i" would most likely be allocated to internal register.
Then integer demotion for (i = i + 1) would require the below code sequence:
(tmp: signed int register)
tmp = i + 1;
tmp = tmp << 24;
tmp = tmp >> 24;
i = tmp;

Such integer demotion seems redundant since:
- if(n < 128): i never overflows
- if(n >= 128): (i < n) will always be true (infinite loop: must be a bug??)

Unless the latter case is the actual intention of the programmer,
I don't want to produce such integer demotion code here.

Example 2:
char c = val;
if(c < val)

Here, the intention can be:
- simply checking the sign of val (programmer assumes -128 <= val < 128)
- checking the bit-7 of val

If the former case is guaranteed, then integer promotion is unnecessary.

Example 3:
unsigned char c = val;
<c used in other integral operations>

Here, the intention COULD be the mask operation: c = val & 0xff; in which case
the programmer expects the integer demotion code here.

In Microsoft's C reference, it says:
"When the value with integral type is demoted to a signed integer with
smaller size, or an unsigned integer is converted to its corresponding
signed integer, the value is unchanged if it can be represented in the
new type. ... If it cannot be represented, the result is implementation-defined."

This seems to suggest that for my assumed RISC (where register holds integer
promoted values), integer demotion is unnecessary. But I have checked that
Microsoft's Visual-C does actually perform integer demotion in my first
for-loop example. My guess is that this is true for most other compilers.

So, to summarize my question:
- Is "integer demotion" required in ANSI-C?
- If not, as a compiler writer, is it "reasonable" to say to the programmers
"it's your responsiblity to make sure the values assigned to short integers
can fit into that short type, because with my compiler, "integer demotion"
may or may not be performed (depending on the destination (register or memory)"??

I appreciate any inputs on this issue.

Regards, tsuyois
Jan 31 '09 #1
9 5307
Sorry. There was one typo:

Example 2:
char c = val;
if(c < 0) /// if(c < val) <-- typo....
Jan 31 '09 #2
JosAH
11,448 Expert 8TB
The ANSI-C Standard text doesn't even mention "integer demotion" but integer promotion is always necessary, especially when temporary results are held in a 32 bits wide register (e.g. an ARM processor); e.g.

Expand|Select|Wrap|Line Numbers
  1. unsigned char c= 255;
  2. if (++c) ...
  3.  
If the value of c is held in a register the value should be integer promoted when the result of ++c is needed for the comparison against zero. Either store the register value back at the memory location c, resulting in truncation (which is correct) or mask out all but the low byte of the register.

kind regards,

Jos
Jan 31 '09 #3
Thanks for the input, Jos.

But I'm now confused with your example:

-----------
unsigned char c= 255;
if (++c) ...
-----------
(++c) will evaluate to 0 since it's prefix increment. So the if-condition is FALSE.

The above statement is equivalent to:

if(c = c + 1) ...

and the computation sequence would be:

int tmp;
unsigned char c = 255;
tmp = (int) c; /// integer promotion : tmp = 255
tmp = tmp + 1; /// tmp = 256
c = (unsigned char) tmp; /// integer demotion : c = 0
tmp = (int) c;
if(tmp) ....

If c is held in the 32-bit register (say reg_c), then what I could do is:

reg_c = 0xff; /// unsigned char c = 255;
reg_c = reg_c + 1; /// reg_c = 0x100
reg_c = (unsigned char) reg_c; /// reg_c = 0x00
if(reg_c) ...

Above code generation strategy (which I think is common), is to always maintain the 32-bit register so that integer promotion comes for free (you don't need to do (int) reg_c before you do reg_c + 1).

So my point exactly is: whether the last code
reg_c = (unsigned char) reg_c
is required by ANSI-C spec. If you say ANSI-C doesn't even mention integer demotion, can I generate the below code sequence and say "this is ANSI-C compliant"?

reg_c = 0xff;
reg_c = reg_c + 1;
if(reg_c) ...

tsuyois
Jan 31 '09 #4
JosAH
11,448 Expert 8TB
@tsuyois
The test is supposed to fail so you should make reg_c equal to zero one way or another. The Standard also speaks about an "abstract execution" environment that should behave according to the semantics imposed by the Standard itself.

There can be an escape if you define a char to be 32 bits wide and the sizeof() operator returns 1 for all integer types but I guess that is not what your want.

Demotion is just truncation to the byte size of the target int and the semantics should behave as if you had used such a sized int. The test above should always fail so reg_c (or a copy thereof) should always be equal to zero.

kind regards,

Jos
Jan 31 '09 #5
@JosAH
OK. I understand that the generated code should behave according to the semantics imposed by the Standard itself. What I still want to chew on is "what is the semantics imposed by the (ANSI-C) standard itself"?

As I have referred in my original question, Microsoft's C Reference says:
"When the value with integral type is demoted to a signed integer with
smaller size, or an unsigned integer is converted to its corresponding
signed integer, the value is unchanged if it can be represented in the
new type. ... If it cannot be represented, the result is implementation-defined."

Now, I am assuming that the above statement refers to the ANSI-C standard.
Coming back to your example,
unsigned char c = 255;
c = c + 1;
the value c + 1 is 256 before being demoted to unsigned char. And 256 cannot be represented in unsigned char. So doesn't this mean "the result is implementation-defined"?? (that ANSI-C does not define what c = c + 1 should be, if c + 1 overflows?)

The reason I'm stuck in this integer demotion problem is that some legacy codes sometimes do include the use of short integers as loop counters (one of the loop counter in Dhrystone's main function is char Ch_Index) that, at first glance, seem to behave correctly without demoting the loop counters everytime they are incremented. (But you never know, maybe the person who wrote Dhrystone was expecting that the compilers would insert integer demotion codes and just maybe measuring the integer demotion overhead was part of the intention of this benchmark program...)

Generating integer demotion code is straightforward (unsigned char: c &= 0xff, signed char: c = (c << 24) >> 24), and I already have them in place in my compiler. What's not so straightforward is determining whether integer demotion code is necessary or not, especially on a 32-bit machine that has load/store instructions that do these integer promotion and demotion in hardware. Good example is the textbook DLX processor which has
- Load Byte (signed, unsigned), Store Byte
- Load Half-Word (signed, unsigned), Store Half-Word
- Load Word, Store Word

Here, you don't want to insert integer demotion codes if the value is to be stored in memory and never referenced directly from the register later. In these situations, a smart compiler would want to avoid inserting redundant integer demotion codes.

And now, I am trying to decide how much effort I should put to make my compiler make "smart" decisions about integer demotion codes. Then I came accross the above C-reference on integer demotion, and started thinking "can I just simply skip all integer demotions", since most of the time it's not needed, and IF ANSI-C DOES NOT IMPOSE INTEGER DEMOTION, this is still ANSI-C compliant.

Tsuyois
Jan 31 '09 #6
Just to update my latest findings on this issue:

Below is the description from MSDN C Language Reference
---------------------------------------------------------------------------------
Implementation-Defined Behavior
ANSI X3.159-1989, American National Standard for Information Systems – Programming Language – C, contains a section called "Portability Issues." The ANSI section lists areas of the C language that ANSI leaves open to each particular implementation.
---------------------------------------------------------------------------------
Demotion of Integers
ANSI 3.2.1.2 The result of converting an integer to a shorter signed integer, or the result of converting an unsigned integer to a signed integer of equal length, if the value cannot be represented
---------------------------------------------------------------------------------
So my current conclusion is that integer demotion whose value cannot be represented in the new integral type is indeed "implementation defined".

tsuyois
Feb 25 '09 #7
JosAH
11,448 Expert 8TB
True, but a few lines above in that same Standard it reads:

When an integer is demoted to an unsigned integer with smaller
size, the result is the nonnegative remainder on division by the
number one greater than the largest unsigned number that can be
represented in the type with smaller size.
so the following test is supposed to fail:

Expand|Select|Wrap|Line Numbers
  1. int i= 0xff; // assume i is stored in a 32 bit wide register
  2. unsigned char c; // assume chars are 8 bits wide
  3.  
  4. if (c= ++i) /* never reached */
  5.  
kind regards,

Jos
Feb 25 '09 #8
Thanks Jos for all the advice.

So I think my understanding is now clear:
ANSI-C Integer Demotion:
0. If the value can be represented in the new integral type, the value is preserved.
Otherwise: (if the value cannot be represented in the new integral type)
1. If the new type is unsigned, the value is truncated to the new type
2. If the new type is signed, the value is implementation defined

It was my mistake of replying too much on MSDN C Reference which does not quite give the complete description of ANSI-C standard.

Is there a good source of ANSI-C(89) standard description in the WEB? What I found was below linked from Wiki(C Programming):
http://flash-gordon.me.uk/ansi.c.txt
Mar 1 '09 #9
JosAH
11,448 Expert 8TB
You can order the Standard text at ISO. The standard number is 9899 and it doesn't cost much. As far as I know there is no free copy available on the net. There are some draft texts available (as you already know).

kind regards,

Jos
Mar 1 '09 #10

Sign in to post your reply or Sign up for a free account.

Similar topics

1
by: Kevin Goodsell | last post by:
Can someone tell me what is required of the size_type type for standard containers (and other standard classes defining this type)? Specifically: 1) Are the requirements the same for each...
27
by: Daniel Lidström | last post by:
Hello! I want to work with individual bytes of integers. I know that ints are 32-bit and will always be. Sometimes I want to work with the entire 32-bits, and other times I want to modify just...
13
by: sam | last post by:
Hi, Does STL has Integer class? I want to convert an integer to string. Of course I can use sprintfs C API, but I m wondering whether STL has Integer class to be utilsed. Thanks Sam.
21
by: Frederick Gotham | last post by:
I set about trying to find a portable way to set the value of UCHAR_MAX. At first, I thought the following would work: #define UCHAR_MAX ~( (unsigned char)0 ) However, it didn't work for me....
232
by: robert maas, see http://tinyurl.com/uh3t | last post by:
I'm working on examples of programming in several languages, all (except PHP) running under CGI so that I can show both the source files and the actually running of the examples online. The first...
9
by: Fred | last post by:
I'm having terrible trouble trying to work out exactly which of the promotions one reads about in old books are still present in current C - and there seems to be a distinction between promotion...
7
by: Spoon | last post by:
Hello everyone, In my code, I use uint16_t (exactly 16-bit-wide unsigned integer type) and I need to print their value in base 10. ...
30
by: =?ISO-8859-1?Q?Tom=E1s_=D3_h=C9ilidhe?= | last post by:
Let's say we had a simple function for returning the amount of days in a month: unsigned DaysInMonth(unsigned const month) { switch (month) { case 8: case 3: case 5:
20
by: Robbie Hatley | last post by:
I needed a quick program called "random" that gives a random positive integer from n1 to n2. For example, if I type "random 38, 43", I want the program to print a random member of the set {38,...
0
BarryA
by: BarryA | last post by:
What are the essential steps and strategies outlined in the Data Structures and Algorithms (DSA) roadmap for aspiring data scientists? How can individuals effectively utilize this roadmap to progress...
1
by: nemocccc | last post by:
hello, everyone, I want to develop a software for my android phone for daily needs, any suggestions?
1
by: Sonnysonu | last post by:
This is the data of csv file 1 2 3 1 2 3 1 2 3 1 2 3 2 3 2 3 3 the lengths should be different i have to store the data by column-wise with in the specific length. suppose the i have to...
0
by: Hystou | last post by:
There are some requirements for setting up RAID: 1. The motherboard and BIOS support RAID configuration. 2. The motherboard has 2 or more available SATA protocol SSD/HDD slots (including MSATA, M.2...
0
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However,...
0
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can...
0
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers,...
0
jinu1996
by: jinu1996 | last post by:
In today's digital age, having a compelling online presence is paramount for businesses aiming to thrive in a competitive landscape. At the heart of this digital strategy lies an intricately woven...
0
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each...

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.