8- and 16-bit operations convert to 32 bit and back?

I was flipping through a C++ slideshow on efficiency when I came across one which stated,

Prefer 32-bit ints to all other sizes, because (for one reason), 8 and 16-bit computations use conversion to 32-bits and back.
( source: http://image.slidesharecdn.com/main-slides-121220010501-phpapp01/95/slide-21-638.jpg?1355987208 )

I figured this just meant that int8 and in16 types are copied into a CPU register (assuming 32-bit arch) for operations, and then stuffed back into memory.

I got curious, and hacked around with some assembly and confirmed that this was the case, even for 32-bit types, they always get copied into a register, and copied back to memory later.

So I got even more curious, and wondered... "is this even necessary?"

I wrote an 'optimized' version of this code in assembly, and it seems to do exactly what it did before, just with fewer operations.

Even with various g++ optimization levels with the -O# option, it still used the register as an intermediary.

Why?


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

int main ( void  ) {
/**/ // Original C++ Code
	volatile unsigned int ui=2147483647; // max value
	ui++; // overflow by one
	printf("%d\n",ui);
	return 0;
/**/ // Copy-Pasta assmebly from `g++ -S try.cpp`
	volatile unsigned int ui;
	asm("movl	$2147483647, 28(%esp)");
	asm("movl	28(%esp), %eax");
	asm("addl	$1, %eax");
	asm("movl	%eax, 28(%esp)");
	printf("%d\n",ui);
	return 0;
/**/ // Optimized assembly, does not copy ui to/from register for ui++
	volatile unsigned int ui;
	asm("movl	$2147483647, 28(%esp)");
	asm("addl	$1, 28(%esp)");
	printf("%d\n",ui);
	return 0;
}
Last edited on
So I got even more curious, and wondered... "is this even necessary?"

Of course it's not "necessary". Are you aware what the volatile keyword is for?
yes, I wanted to make sure that during my fussing with the address of that unsigned integer variable, that it would not be 'optimized away' by the compiler.

if it's not necessary, why doen't g++ optimize better than that? it seems like a pretty obvious optimization...

edit: I know very little about assembly in general, this demonstrates just about the extent of my skill. I can write assmebly loops and some math operations, but that's about it.
Last edited on
The keyword volatile is a binding requirement for the compiler to generate one memory load and one memory store when compiling ui++. Regardless of optimizations that may be applied.

Make it a simple non-volatile global variable, and remove printf() (so that the result of ui++ isn't needed in a register) and gcc will happily generate that command.
Last edited on
I got curious, and hacked around with some assembly and confirmed that this was the case, even for 32-bit types, they always get copied into a register, and copied back to memory later.

So I got even more curious, and wondered... "is this even necessary?"
No register-based processor is capable of operating on data that's not loaded on a register.

I wrote an 'optimized' version of this code in assembly, and it seems to do exactly what it did before, just with fewer operations.
Just because something is coded in fewer instructions doesn't mean it's actually faster. Instructions with memory as both the source and destination translate to microcode that loads the memory to a register, performs the operation, then stores the result back to memory, so theoretically it's no faster than the MOV-x-MOV sequence a compiler would generate. It may be faster or slower depending on the relative cost of translating to microcode one complex instruction vs. several simpler ones, although I'm willing to bet the latter is faster.
Topic archived. No new replies allowed.