Hi,
Please find enclosed a patch to resolve PR20018. According to the x86-64
ABI, structures with both floating point and integer members are split
between floating-point and general purpose registers, and consecutive
32-bit floats can be packed into a single floating point register. In
variadic functions, clang writes out the state of the GP registers and FP
registers to different regions in memory. A bug in the TargetInfo logic is
causing llvm to try to read floating point arguments from the FP region of
the stack. Specifically:
02593 llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr :
GPAddr;
02594 llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr :
FPAddr;
Are checking if TyLo is a floating point type, however, two consecutive
floating point fields will be represented as an floating point vector.
Consequently, the correct code should be:
02593 llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr :
GPAddr;
02594 llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr :
FPAddr;
The code on line 2623 is already checking for floating point vectors
appropriately. I have also attached a simple test case named gpfpTest.c.
Thanks.
Tom
Index: lib/CodeGen/TargetInfo.cpp
===================================================================
--- lib/CodeGen/TargetInfo.cpp (revision 207039)
+++ lib/CodeGen/TargetInfo.cpp (working copy)
@@ -2626,8 +2626,8 @@
llvm::Type *PTyHi = llvm::PointerType::getUnqual(TyHi);
llvm::Value *GPAddr = CGF.Builder.CreateGEP(RegAddr, gp_offset);
llvm::Value *FPAddr = CGF.Builder.CreateGEP(RegAddr, fp_offset);
- llvm::Value *RegLoAddr = TyLo->isFloatingPointTy() ? FPAddr : GPAddr;
- llvm::Value *RegHiAddr = TyLo->isFloatingPointTy() ? GPAddr : FPAddr;
+ llvm::Value *RegLoAddr = TyLo->isFPOrFPVectorTy() ? FPAddr : GPAddr;
+ llvm::Value *RegHiAddr = TyLo->isFPOrFPVectorTy() ? GPAddr : FPAddr;
llvm::Value *V =
CGF.Builder.CreateLoad(CGF.Builder.CreateBitCast(RegLoAddr, PTyLo));
CGF.Builder.CreateStore(V, CGF.Builder.CreateStructGEP(Tmp, 0));
#include <assert.h>
#include <stdarg.h>
struct Bar {
float f1;
float f2;
unsigned u;
};
struct Bar gBar = { 3.14149, 2.7132, 7 };
void foo(int i, ...) {
va_list ap;
va_start(ap, i);
struct Bar vBar = va_arg(ap, struct Bar);
assert(gBar.f1 == vBar.f1);
assert(gBar.f2 == vBar.f2);
assert(gBar.u == vBar.u);
va_end(ap);
}
int main(int argc, char **argv) {
foo(0, gBar);
return 0;
}
_______________________________________________
cfe-commits mailing list
[email protected]
http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits