Hi, I found a mysterious behavior of LLVM optimizer. I compiled the following code by clang -emit-llvm -S: #include <stddef.h> static const struct t {char t[4]; char s;} p = {{}, 'a'}; char f() { return ((char*)&p)[offsetof(struct t, s)]; } then I obtained the following LLVM IR: %struct.t = type { [4 x i8], i8 } @p = constant %struct.t { [4 x i8] zeroinitializer, i8 97 }, align 1 define signext i8 @f() nounwind ssp uwtable { %1 = load i8* getelementptr inbounds (%struct.t* @p, i32 0, i32 0, i64 4), align 1 ret i8 %1 } By applying the above code to opt -O1 of LLVM 3.4, I obtained: %struct.t = type { [4 x i8], i8 } @p = constant %struct.t { [4 x i8] zeroinitializer, i8 97 }, align 1 define signext i8 @f() nounwind readnone ssp uwtable { ret i8 0 } The function "f" is eventually compiled into a function that always returns 0, while I expect "f" returns 'a' (97). Is this an intended behavior, or a bug? By replacing the getelementptr expression in the clang output getelementptr inbounds (%struct.t* @p, i32 0, i32 0, i64 4) with getelementptr inbounds (i8* bitcast (%struct.t* @p to i8*), i64 4) opt -O1 generates the following code that is what I expected: define signext i8 @f() nounwind readnone ssp uwtable { ret i8 97 } I carefully read LLVM Language Reference Manual but I could not understand the difference of these two getelementptr expressions. Are these two getelementptr equivalent in the semantics of LLVM IR? Thanks, -- UENO, Katsuhiro
On 29 Jan 2014, at 16:42, Katsuhiro Ueno wrote:> I compiled the following code by clang -emit-llvm -S: > > #include <stddef.h> > static const struct t {char t[4]; char s;} p = {{}, 'a'}; > char f() { > return ((char*)&p)[offsetof(struct t, s)]; > } > > then I obtained the following LLVM IR: > > %struct.t = type { [4 x i8], i8 } > @p = constant %struct.t { [4 x i8] zeroinitializer, i8 97 }, align 1 > define signext i8 @f() nounwind ssp uwtable { > %1 = load i8* getelementptr inbounds (%struct.t* @p, i32 0, i32 0, > i64 4), align 1 > ret i8 %1 > }The GEP takes the address of the 5th element (= offset 4) of your "char t[4]". It's not entirely clear to me from the description of "inbounds" whether this means the the GEP results in a poison value or not, but it definitely looks wrong.> By applying the above code to opt -O1 of LLVM 3.4, I obtained: > > %struct.t = type { [4 x i8], i8 } > @p = constant %struct.t { [4 x i8] zeroinitializer, i8 97 }, align 1 > define signext i8 @f() nounwind readnone ssp uwtable { > ret i8 0 > }Given this result, I guess it is in fact a poison value. Jonas
On Thu, Jan 30, 2014 at 9:46 AM, Jonas Maebe <jonas.maebe at elis.ugent.be>wrote:> > The GEP takes the address of the 5th element (= offset 4) of your "char > t[4]". It's not entirely clear to me from the description of "inbounds" > whether this means the the GEP results in a poison value or not, but it > definitely looks wrong.I believe LLVM IR allows you to GEP from inside of one field into the next, but I would defer to experts. The constant folder is what creates this, and it totally ignores the element index when folding a zero initialized array type: Constant *ConstantAggregateZero::getSequentialElement() const { return Constant::getNullValue(getType()->getSequentialElementType()); } Constant *ConstantAggregateZero::getElementValue(unsigned Idx) const { if (isa<SequentialType>(getType())) return getSequentialElement(); // Doesn't pass in Idx or check bounds. return getStructElement(Idx); } Looks like a bug to me. -------------- next part -------------- An HTML attachment was scrubbed... URL: <http://lists.llvm.org/pipermail/llvm-dev/attachments/20140130/1c3a26f9/attachment.html>