8

I'm floored that VisualStudio 2015 insists on promoting a WORD (unsigned short) to an unsigned int when only WORD values are involved in only bit manipulations. (i.e. promotes 16 bit to 32 bit when doing 16bit | 16bit).

e.g.

// where WORD is a 'unsigned short'
const WORD kFlag = 1;
WORD old = 2;
auto value = old | kFlag;  // why the blazes is value an unsigned int (32 bits)

Moreover, is there a way to get 0x86 intrinsics for WORD|WORD? I surely do not want to pay for (16->32|16->)->16. Nor does this code need to consume more than a couple of 16 bit registers, not a few 32 bit regs.

But the registry use is really just an aside. The optimizer is welcome to do as it pleases, so long as the results are indistinguishable for me. (i.e. it should not change the size in a visible way).

The main problem for me is that using flags|kFlagValue results in a wider entity, and then pumping that into a template gives me a type mismatch error (template is rather much longer than I want to get into here, but the point is it takes two arguments, and they should match in type, or be trivially convertible, but aren't, due to this automatic size-promotion rule).

If I had access to a "conservative bit processing function set" then I could use:

      flag non-promoting-bit-operator kFlagValue

To achieve my ends.

I guess I have to go write that, or use casts all over the place, because of this unfortunate rule.

C++ should not promote in this instance. It was a poor language choice.

Mordachai
  • 9,412
  • 6
  • 60
  • 112
  • If the output of this function is so important to the overall execution of your program, then by all means drop some assembler in there and help the compiler do it correctly. Otherwise, why worry about what's in the sausage if it still tastes good? – Michael Dorgan Nov 29 '16 at 18:35
  • Because it violates the types. C++ is widening something that NEVER should be wider. A 16bit value that is being or ORed and ANDed with other 16bit values will NEVER overflow, and the results are 100% safe 16bit value that can be stored in an ABI. I don't want the language to arbitrarily promote things for speed in ways that generates visible side-effects where none are needed (if it wants to do so as an optimization that is invisible to me, that's fine, but this has visible consequences that force my code to have to change) :( – Mordachai Nov 29 '16 at 18:41
  • 1
    Logical operations, a subset of arithmetic ops, convert operands that are smaller than `int` to an `int` – doug Nov 29 '16 at 18:42
  • 1
    if you declare value as WORD then compiler will possibly optimize it. This is not the case if you use auto because the standard requires promotion to happen. – user3528438 Nov 29 '16 at 18:42
  • yes, but it breaks templates - they generate stupid code because the operands are of different types. (yes, this example is a subset of a more general situation involving templates). – Mordachai Nov 29 '16 at 18:45
  • Yep, another place, besides proxy classes, that `auto` doesn't do what one would want. – doug Nov 29 '16 at 20:19

1 Answers1

2

Why is value promoted to a larger type? Because the language spec says it is (a 16-bit unsigned short will be converted to a 32-bit int). 16-bit ops on x86 actually incur a penalty over the corresponding 32 bit ones (due to a prefix opcode), so the 32 bit version just may run faster.

1201ProgramAlarm
  • 32,384
  • 7
  • 42
  • 56
  • Beat me to it - smaller operations on larger CPUs tend to be more expensive. – Michael Dorgan Nov 29 '16 at 18:37
  • It should be `int`, not `unsigned` if the spec is to be followed (in OP's environment). "A prvalue of an integer type other than bool, char16_t, char32_t, or wchar_t whose integer conversion rank (4.13) is less than the rank of int can be converted to a prvalue of type int if int can represent all the values of the source type; otherwise, the source prvalue can be converted to a prvalue of type unsigned int." – krzaq Nov 29 '16 at 18:41
  • I don't care about the sign of the promotion - but the promotion itself. I can see having +/- promote, but bit operators is just annoying and forces me to sprinkle my code with pointless casting operators. – Mordachai Nov 29 '16 at 18:43
  • 4
    Ahh - this should be part of your question as I completely missed why this was annoying you. I thought you were performance bound, not fighting a template processor. – Michael Dorgan Nov 29 '16 at 18:53
  • 1
    This answer seems wrong. `unsigned short` should be promoted to `int`, not `unsigned int`. Unless of course `int` can't hold all values of `unsigned short`, but that doesn't seem likely – Arvid Sep 16 '17 at 15:41
  • 1
    @Arvid I originally answered based on what is in the question, but have rephrased my answer based on what really happens. – 1201ProgramAlarm Sep 16 '17 at 19:19