Hi, I have a confusion about types used in load/store, (http://llvm.org/docs/GetElementPtr.html#types) says that [...] Furthermore, loads and stores don't have to use the same types as the type of the underlying object. Types in this context serve only to specify memory size and alignment. Beyond that there are merely a hint to the optimizer indicating how the value will likely be used. [...] I was wondering that in which cases we may have undefined behaviors if types in load/store don't match the objects'. In C, they need to be compatible, which means the size of types should be same, otherwise undefined. Do we follow the same convention in LLVM IR? Does GEP also follow similar rules when types mismatch? The other question is about 'when loading a value of a type like i20 with a size that is not an integral number of bytes, the result is undefined if the value was not originally written using a store of the same type'. At this case, can we make an assumption that typically we only load the 20 bits, but ignore extra bits, like what store does at such a case. Is there any problem that stops such an assumption? Thanks. -- Jianzhou
Hi Jianzhou,> The other question is about 'when loading a value of a type like i20 > with a size that is not an integral number of bytes, the result is > undefined if the value was not originally written using a store of the > same type'. At this case, can we make an assumption that typically we > only load the 20 bits, but ignore extra bits, like what store does at > such a case. Is there any problem that stops such an assumption?the way the code generators currently work is that when you store an i20, three bytes are written: your 20 bits followed by 4 zero bits. When an i20 is loaded, which means loading three bytes, the code generators "know" that the extra 4 bits must be zero, and may perform some simplifications based on this knowledge. If you store three bytes, and bits 20 to 23 are not zero, and you try to load it as an i20, you may therefore get strange results due to such simplifications. Ciao, Duncan. PS: The fact that the extra stored bits are zero shouldn't be relied upon, since it may change in the future.
On Jul 8, 2010 8:50 AM, "Duncan Sands" <baldrick at free.fr> wrote:> PS: The fact that the extra stored bits are zero shouldn't be relied > upon, since it may change in the future.Interesting -- sounds like a place where signed and unsigned types would be helpful, since they could be stored zero- or sign-extended as appropriate. ~ Scott
On Thu, Jul 8, 2010 at 11:09 AM, Jianzhou Zhao <jianzhou at seas.upenn.edu> wrote:> Hi, > > I have a confusion about types used in load/store, > (http://llvm.org/docs/GetElementPtr.html#types) says that [...] > Furthermore, loads and stores don't have to use the same types as the > type of the underlying object. Types in this context serve only to > specify memory size and alignment. Beyond that there are merely a hint > to the optimizer indicating how the value will likely be used. [...] > > I was wondering that in which cases we may have undefined behaviors if > types in load/store don't match the objects'. In C, they need to be > compatible, which means the size of types should be same, otherwise > undefined. Do we follow the same convention in LLVM IR? Does GEP also > follow similar rules when types mismatch?I misunderstood C99 ISO, such behaviors are defined not when types have the same sizes, but when they are same (compatible) types with signed or qualified extension (this is much stronger than being of same sizes), or reading char by char: 7 An object shall have its stored value accessed only by an lvalue expression that has one of the following types: — a type compatible with the effective type of the object, [...] — a type that is the signed or unsigned type corresponding to the effective type of the object, [...] — an aggregate or union type that includes one of the aforementioned types among its members (including, recursively, a member of a subaggregate or contained union), or — a character type. (sec 6.5, items 6 and 7, page 67-68, http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf) If LLVM IR is weaker than these C restrictions, then I have the following questions about when GEP is undefined: 1) Can I load a value partially or overlapped with other stored values? For example, if the stored values are of type [10*i32], and we cast i32* to {i8, i4, float} *, can we successfully load each fields via the addresses from GEPs? Since IR allows to define data layout of targets (size and alignment for types), does whether such GEPs undefined depend on its data layout? 2) C allows characters as the least granularity when loading. Does LLVM have the same assumption?> > The other question is about 'when loading a value of a type like i20 > with a size that is not an integral number of bytes, the result is > undefined if the value was not originally written using a store of the > same type'. At this case, can we make an assumption that typically we > only load the 20 bits, but ignore extra bits, like what store does at > such a case. Is there any problem that stops such an assumption? > > Thanks. > -- > Jianzhou >-- Jianzhou
Hi Jianzhou,> I misunderstood C99 ISO, such behaviors are defined not when types > have the same sizes, but when they are same (compatible) types with > signed or qualified extension (this is much stronger than being of > same sizes), or reading char by char: > > 7 An object shall have its stored value accessed only by an lvalue > expression that has one of > the following types: > — a type compatible with the effective type of the object, > [...] > — a type that is the signed or unsigned type corresponding to the > effective type of the > object, > [...] > — an aggregate or union type that includes one of the aforementioned > types among its > members (including, recursively, a member of a subaggregate or > contained union), or > — a character type. > (sec 6.5, items 6 and 7, page 67-68, > http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf)LLVM does not have any such restrictions.> If LLVM IR is weaker than these C restrictions, then I have the > following questions about when GEP is undefined:In your examples, it is not GEP that would be undefined, but a load or store from the GEP. GEP just offsets the memory address. In C too it is not invalid to offset or cast a pointer; it is loading from or storing to the cast or offset pointer that may be invalid.> 1) Can I load a value partially or overlapped with other stored > values? For example, if the stored values are of type [10*i32], and we > cast i32* to {i8, i4, float} *, can we successfully load each fields > via the addresses from GEPs?Yes, except that as previously mentioned this is invalid for the i4 if the original value was not set by performing an i4 store. Since IR allows to define data layout of> targets (size and alignment for types), does whether such GEPs > undefined depend on its data layout?As I mentioned, there is no problem with GEPs being undefined.> 2) C allows characters as the least granularity when loading. Does > LLVM have the same assumption?LLVM doesn't have a notion of "character". Currently all processors that LLVM targets are capable of addressing an octet (8 bits), but nothing smaller. This means that the smallest granularity is currently i8. Ciao, Duncan.