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

Reply via email to