Hi, Given this LLVM assembly: @a = global i8* getelementptr (i8* null, i64 mul (i64 ptrtoint (i32* getelementptr (i32* null, i32 1) to i64), i64 2)) llc fails an assertion: llc: /home/jdenny/llvm-svn/include/llvm/Support/Casting.h:202: typename llvm::cast_retty<To, From>::ret_type llvm::cast(const Y&) [with X = llvm::ConstantInt, Y = llvm::Value*]: Assertion `isa<X>(Val) && "cast<Ty>() argument of incompatible type!"' failed. This has been reported previously as a bug and was resolved as invalid: http://llvm.org/bugs/show_bug.cgi?id=2672 The explanation was: "I don't think we should try to fold arbitrary expressions in the code generator. Instead, we should accept that targets have limitations on these. We can't ever support things like "void *X = &G / &H;" for example." Are the limitations on what can be placed in a static initializer documented somewhere? When those limitations aren't obeyed, would it be possible for llc to print a more intelligible error message for the user? Thanks.
Joel E. Denny wrote:> Hi, > > Given this LLVM assembly: > > @a = global i8* getelementptr (i8* null, i64 mul (i64 ptrtoint (i32* getelementptr (i32* null, i32 1) to i64), i64 2)) > > llc fails an assertion: > > llc: /home/jdenny/llvm-svn/include/llvm/Support/Casting.h:202: typename llvm::cast_retty<To, From>::ret_type llvm::cast(const Y&) [with X = llvm::ConstantInt, Y = llvm::Value*]: Assertion `isa<X>(Val)&& "cast<Ty>() argument of incompatible type!"' failed. > > This has been reported previously as a bug and was resolved as invalid: > > http://llvm.org/bugs/show_bug.cgi?id=2672 > > The explanation was: > > "I don't think we should try to fold arbitrary expressions in the code > generator. Instead, we should accept that targets have limitations on > these. We can't ever support things like "void *X =&G /&H;" for > example." > > Are the limitations on what can be placed in a static initializer > documented somewhere?No. When those limitations aren't obeyed, would it be> possible for llc to print a more intelligible error message for the user?The limitations are a product of the ABI and on-disk .o file format. For example, given "int X = (int)&G / (int)&H;", llc will happily generate "X: .long G/H" which is invalid assembly, but llc doesn't know that. Maybe with the MC infrastructure we could start to figure out what is and isn't representable. That would be nice since the frontend may need to change its behaviour, for example, GCC lowers the example code into a C++ static initializer function to calculate the value for X at load time before main() starts. As of today, llvm-gcc and clang both get this wrong. Nick
Hi Nick, On Tue, 26 Oct 2010, Nick Lewycky wrote:> Joel E. Denny wrote:> > Given this LLVM assembly: > > > > @a = global i8* getelementptr (i8* null, i64 mul (i64 ptrtoint (i32* > > getelementptr (i32* null, i32 1) to i64), i64 2)) > > > > llc fails an assertion: > > > > llc: /home/jdenny/llvm-svn/include/llvm/Support/Casting.h:202: typename > > llvm::cast_retty<To, From>::ret_type llvm::cast(const Y&) [with X > > llvm::ConstantInt, Y = llvm::Value*]: Assertion `isa<X>(Val)&& "cast<Ty>() > > argument of incompatible type!"' failed.> The limitations are a product of the ABI and on-disk .o file format. For > example, given "int X = (int)&G / (int)&H;", llc will happily generate "X: > .long G/H" which is invalid assembly, but llc doesn't know that. > > Maybe with the MC infrastructure we could start to figure out what is and > isn't representable.llc is already able to determine that something has gone wrong. It fails an assertion. Could that be turned into a user-friendly error message? However, I'm not sure that the target assembly's exact limitations are really the issue in the cases I've been encountering. I think the issue is how far LLVM is able to go to fold constant expressions, in general. For example, for my platform, llc folds the add but not the getelementptr in: @a = global i8* getelementptr (i8* null, i64 add (i64 3, i64 2)) so we get: .quad 0+5 However, it folds neither of those in: @b = global i64 add (i64 ptrtoint (i8* getelementptr (i8* null, i64 3) to i64), i64 2) so we get: .quad ((0+1)*3)+2 In other words, it seems llc knows when it must fold an add, but it doesn't do it if it doesn't have to. Why can't it use the same logic for getelementptr? For example, if a getelementptr invocation has the following form: <result> = getelementptr (<pty>* null{, <ty> <idx>}*) where every idx is a constant, is there any reason this getelementptr cannot be folded? This would allow more flexibility in building expressions that use getelementptr to compute sizeof or offsetof. In case it isn't clear, my goal is more about understanding constant folding in LLVM than in seeing this particular functionality implemented. Thanks.