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>
Possibly Parallel Threads
- [LLVMdev] How to force the creation of arrays with zeroes?
- [LLVMdev] How to force the creation of arrays with zeroes?
- [LLVMdev] How to force the creation of arrays with zeroes?
- [LLVMdev] How to force the creation of arrays with zeroes?
- [LLVMdev] bug of tail call optimization on x86 target