[LLVMdev] Any extend

Greg Chadwick gac43 at cam.ac.uk
Tue Jan 26 07:06:44 PST 2010


Hi Duncan,

>>>> 1) What causes the Initial selection DAG code to choose an 
>>>> any_extend over a sign_extend (or zero_extend)?
>>>
>>> because it is more efficient: the backend gets more choice in how to do
>>> it, and at the same time it tells the optimizers that the extra bits
>>> contain rubbish, which gives them more freedom to reason.
>> Makes sense, though I was wondering why it would choose to sign_extend 
>> an 8-bit or 16-bit value, but any_extend a 32-bit value (These are all 
>> signed values).
> 
> I'm not sure what you mean by "these are all signed values" - in LLVM there
> is no such thing as a "signed i16" or an "unsigned i16", there is only i16
> with signed and unsigned operations.  As to why you get a sign-extend in
> some cases and any-extend in others... well, it depends on details of what
> you are compiling, so without a testcase it is hard to say anything useful.
> 

Yes, I could have worded that better.  The particular test case I'm 
using is the following bit of c, which is then compiled to LLVM using 
Clang without any optimisation:

int func(void)
{
	return 0;
}

I then compile the same thing with func returning char or short (which 
are all signed types, which I realise isn't reflected in the LLVM types).

Clang generates the following LLVM:

; ModuleID = 'test.c'
target datalayout = 
"e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128"
target triple = "x86_64-unknown-linux-gnu"

define i32 @func() nounwind {
entry:
   %retval = alloca i32                            ; <i32*> [#uses=2]
   store i32 0, i32* %retval
   %0 = load i32* %retval                          ; <i32> [#uses=1]
   ret i32 %0
}

When I use char or short it generates the same code, only using i16 or 
i8, plus (I now realise having looked at it more closely) one more 
crucial difference, it adds signext to the function definition in the i8 
and i16 cases like so:

define signext i16 @func() nounwind {

Which is where the sign_extend/any_extend difference comes from :)  So 
it's Clang that makes the decision.

Out of interest the Mips backend does deal with any_extend, it just does 
it using Pat to map them directly to unsigned loads, rather than 
defining them as a Mips instruction.  Which is why I missed them when 
extending it for 64-bit.

Cheers,

Greg



More information about the llvm-dev mailing list