[LLVMdev] RFC: Store alignment should be LValue alignment, not source alignment

Evan Cheng evan.cheng at apple.com
Fri Jan 9 13:50:17 PST 2009


On Jan 9, 2009, at 12:33 PM, Duncan Sands wrote:

> Hi Evan,
>
>>   LValue LV = EmitLV(lhs);
>>   bool isVolatile = TREE_THIS_VOLATILE(lhs);
>>   unsigned Alignment = expr_align(exp) / 8
>>
>> It's using the alignment of the expression, rather than the memory
>> object of LValue.
>
> can't you just use expr_align(lhs) instead?

No. My earlier comment is wrong. Under EmitMODIFY_EXPR, it was using  
expr_align(lhs). But it's still wrong. See this example:

extern int bar(unsigned long long key_token2)
{
...
__attribute__ ((unused)) Key iospec = (Key) key_token2;

In the EmitMODIFY_EXPR case, lhs is a component_ref for this:

Here is that it looks like:

(gdb) call debug_tree(lhs)
  <component_ref 0x42cd1750
     type <integer_type 0x42c0c540 long long unsigned int sizes- 
gimplified public unsigned DI
         size <integer_cst 0x42c04930 constant invariant 64>
         unit size <integer_cst 0x42c04960 constant invariant 8>
         align 64 symtab 2 alias set -1 precision 64 min <integer_cst  
0x42c04a50 0> max <integer_cst 0x42c04a20 18446744073709551615>
	LLVM:  i64>

     arg 0 <var_decl 0x42cd6850 iospec
         type <union_type 0x42cd65b0 Key sizes-gimplified type_0 DI  
size <integer_cst 0x42c04930 64> unit size <integer_cst 0x42c04960 8>
             align 32 symtab 0 alias set -1 fields <field_decl  
0x42cd6310 key_io>>
         used asm-frame-size 0 DI file t.c line 87 size <integer_cst  
0x42c04930 64> unit size <integer_cst 0x42c04960 8>
         align 32 context <function_decl 0x42cbb600 bar> attributes  
<tree_list 0x42cc9c80>
         LLVM: %struct.Key* %iospec>
     arg 1 <field_decl 0x42cd6540 lkey type <integer_type 0x42c0c540  
long long unsigned int>
	unsigned asm-frame-size 0 DI file t.c line 61 size <integer_cst  
0x42c04930 64> unit size <integer_cst 0x42c04960 8>
	align 32 offset_align 128
	offset <integer_cst 0x42c04210 constant invariant 0>
	bit offset <integer_cst 0x42c04de0 constant invariant 0> context  
<union_type 0x42cbdc40 _Key>>>

Note type of component_ref is i64 with 8-byte alignment.   
expr_align(lhs) would return 64 here. However, the address of the  
store is iospec, which is 32-bit aligned.

>
>
>> The patch saves the alignment of the memory object in LValue returned
>> by EmitLV(). Please review it carefully as I am not entirely
>> comfortable hacking on llvm-gcc. :-)
>
> In the long run, LValue and MemRef should be merged, but that can
> wait until later I suppose.
>
>> +  case LABEL_DECL: {
>> +    Value *Ptr = TreeConstantToLLVM::EmitLV_LABEL_DECL(exp);
>> +    return LValue(Ptr, DECL_ALIGN(exp) / 8);
>> +  }
>> +  case COMPLEX_CST: {
>> +    Value *Ptr = TreeConstantToLLVM::EmitLV_COMPLEX_CST(exp);
>> +    return LValue(Ptr, TYPE_ALIGN(TREE_TYPE(exp)) / 8);
>> +  }
>> +  case STRING_CST: {
>> +    Value *Ptr = TreeConstantToLLVM::EmitLV_STRING_CST(exp);
>> +    return LValue(Ptr, TYPE_ALIGN(TREE_TYPE(exp)) / 8);
>> +  }
>
> These are all equivalent to using expr_align, right?

Yes.

>
>
>> @@ -2290,7 +2301,7 @@ Value *TreeToLLVM::EmitLoadOfLValue(tree
>>    LValue LV = EmitLV(exp);
>>    bool isVolatile = TREE_THIS_VOLATILE(exp);
>>    const Type *Ty = ConvertType(TREE_TYPE(exp));
>> -  unsigned Alignment = expr_align(exp) / 8;
>> +  unsigned Alignment = LV.getAlignment();
>
> Here expr_align(exp) is correct I think.

Not true. The result of the load might be have a generic type. For  
example, it can be i64 with alignment 64. However, the address can be  
64-bit wide but with a different alignment. LLVM load / store  
instruction alignments are equal to alignment of the memory location,  
not the value being loaded or stored.

>
>
>> @@ -2963,7 +2974,7 @@ Value *TreeToLLVM::EmitMODIFY_EXPR(tree
>>
>>    LValue LV = EmitLV(lhs);
>>    bool isVolatile = TREE_THIS_VOLATILE(lhs);
>> -  unsigned Alignment = expr_align(lhs) / 8;
>> +  unsigned Alignment = LV.getAlignment();
>
> Here I think expr_align(lhs) was correct.

No. See before.

>
>
>>        LValue LV = EmitLV(Op);
>>        assert(!LV.isBitfield() && "Expected an aggregate operand!");
>>        bool isVolatile = TREE_THIS_VOLATILE(Op);
>> -      unsigned Alignment = expr_align(Op) / 8;
>> +      unsigned Alignment = LV.getAlignment();
>
> This also looks like it was already ok.
>
>>      if (errorcount || sorrycount) {
>> -      const PointerType *Ty =
>> -        PointerType::getUnqual(ConvertType(TREE_TYPE(exp)));
>> -      return ConstantPointerNull::get(Ty);
>> +      const Type *Ty = ConvertType(TREE_TYPE(exp));
>> +      const PointerType *PTy = PointerType::getUnqual(Ty);
>> +      LValue LV(ConstantPointerNull::get(PTy),
>> TD.getABITypeAlignment(Ty));
>> +      return LV;
>
> If the type is opaque or abstract, won't this assert getting the
> alignment?  You might as well use 1 here, since compilation is
> going to fail anyway.

Makes sense.

>
>
>> @@ -5924,7 +5936,13 @@ LValue TreeToLLVM::EmitLV_DECL(tree exp)
>>    // type void.
>>    if (Ty == Type::VoidTy) Ty = StructType::get(NULL, NULL);
>>    const PointerType *PTy = PointerType::getUnqual(Ty);
>> -  return BitCastToType(Decl, PTy);
>> +  unsigned Alignment = Ty->isSized() ?  
>> TD.getABITypeAlignment(Ty) : 1;
>
> Can't you just use expr_align here?  That said, I'm not sure what
> this case is doing.

I am not entirely sure. One thing I noticed is a gcc assigns alignment  
64 to a i64 parameter. But TD.getABITypeAlignment will return 32 here  
(which is correct).

>
>
>> +  if (DECL_ALIGN_UNIT(exp)) {
>> +    if (DECL_USER_ALIGN(exp) || Alignment <
>> (unsigned)DECL_ALIGN_UNIT(exp))
>> +      Alignment = DECL_ALIGN_UNIT(exp);
>> +  }
>> +
>> +  return LValue(BitCastToType(Decl, PTy), Alignment);
>
> Since I don't know what this case handles, I can't comment on this.
>
>>      LValue ArrayAddrLV = EmitLV(Array);
>>      assert(!ArrayAddrLV.isBitfield() && "Arrays cannot be
>> bitfields!");
>>      ArrayAddr = ArrayAddrLV.Ptr;
>> +    ArrayAlign = ArrayAddrLV.Alignment;
>
> Couldn't this be expr_align(Array)?
>
>> +    const Type *ATy = cast<PointerType>(ArrayAddr->getType())-
>>> getElementType();
>> +    const Type *ElementTy = cast<ArrayType>(ATy)->getElementType();
>> +    unsigned Alignment = MinAlign(ArrayAlign,
>> TD.getABITypeSize(ElementTy));
>
> Why these manipulations?  These happens several more times below.

According to Chris, alignment of a vector element is MinAlign(alignof  
vector, sizeof vector element).

>
>
>> @@ -6028,8 +6063,9 @@ static unsigned getComponentRefOffsetInB
>>
>>  LValue TreeToLLVM::EmitLV_COMPONENT_REF(tree exp) {
>>    LValue StructAddrLV = EmitLV(TREE_OPERAND(exp, 0));
>> -  tree FieldDecl = TREE_OPERAND(exp, 1);
>> -
>> +  tree FieldDecl = TREE_OPERAND(exp, 1);
>> +  unsigned LVAlign = DECL_PACKED(FieldDecl) ? 1 :
>> StructAddrLV.Alignment;
>
> Can't this be expr_align(exp)?

No. It will just return alignment of the expression type.

>
>
> I'll stop here, because I still don't understand the need
> for incorporating the alignment into LValue.

Hopefully my earlier explanation makes sense on why this is necessary.

Evan

>
>
> Ciao,
>
> Duncan.




More information about the llvm-dev mailing list