pratlucas created this revision.
Herald added subscribers: cfe-commits, kristof.beyls.
Herald added a project: clang.

Half-precision floating point arguments and returns are currently
promoted to either float or int32 in clang's CodeGen. As such promotions
are implemented as coercion through memory in clang, aruments and
returns of those types end up stored on the wrong bits on big-endian
AArch32 - MSBs instead of LSBs.

This patch enforces AAPCS' directions, making sure clang stores those
types on the proper bits during coercion through memory for bit-endian
targets.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D75169

Files:
  clang/include/clang/CodeGen/CGFunctionInfo.h
  clang/lib/CodeGen/CGCall.cpp
  clang/lib/CodeGen/TargetInfo.cpp
  clang/test/CodeGen/arm-fp16-arguments.c

Index: clang/test/CodeGen/arm-fp16-arguments.c
===================================================================
--- clang/test/CodeGen/arm-fp16-arguments.c
+++ clang/test/CodeGen/arm-fp16-arguments.c
@@ -1,6 +1,9 @@
 // RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fallow-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT
 // RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi hard -fallow-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=CHECK --check-prefix=HARD
 // RUN: %clang_cc1 -triple armv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fnative-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=NATIVE
+// RUN: %clang_cc1 -triple armebv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fallow-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=CHECK --check-prefix=SOFT
+// RUN: %clang_cc1 -triple armebv7a--none-eabi -target-abi aapcs -mfloat-abi hard -fallow-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=CHECK --check-prefix=HARD
+// RUN: %clang_cc1 -triple armebv7a--none-eabi -target-abi aapcs -mfloat-abi soft -fnative-half-arguments-and-returns -emit-llvm -o - -O2 %s | FileCheck %s --check-prefix=NATIVE
 
 __fp16 g;
 
Index: clang/lib/CodeGen/TargetInfo.cpp
===================================================================
--- clang/lib/CodeGen/TargetInfo.cpp
+++ clang/lib/CodeGen/TargetInfo.cpp
@@ -5934,7 +5934,8 @@
     llvm::Type *ResType = IsAAPCS_VFP ?
       llvm::Type::getFloatTy(getVMContext()) :
       llvm::Type::getInt32Ty(getVMContext());
-    return ABIArgInfo::getDirect(ResType);
+    return ABIArgInfo::getDirect(ResType, /*Offset=*/0, /*Padding=*/nullptr,
+                                 /*CanBeFlattened=*/true, /*EndianAlign=*/true);
   }
 
   if (!isAggregateTypeForABI(Ty)) {
@@ -6141,7 +6142,8 @@
     llvm::Type *ResType = IsAAPCS_VFP ?
       llvm::Type::getFloatTy(getVMContext()) :
       llvm::Type::getInt32Ty(getVMContext());
-    return ABIArgInfo::getDirect(ResType);
+    return ABIArgInfo::getDirect(ResType, /*Offset=*/0, /*Padding=*/nullptr,
+        /*CanBeFlattened=*/true, /*EndianAlign=*/true);
   }
 
   if (!isAggregateTypeForABI(RetTy)) {
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -1221,6 +1221,7 @@
 /// destination type; in this situation the values of bits which not
 /// present in the src are undefined.
 static llvm::Value *CreateCoercedLoad(Address Src, llvm::Type *Ty,
+                                      bool EndianAlign,
                                       CodeGenFunction &CGF) {
   llvm::Type *SrcTy = Src.getElementType();
 
@@ -1261,6 +1262,11 @@
   // Otherwise do coercion through memory. This is stupid, but simple.
   Address Tmp = CreateTempAllocaForCoercion(CGF, Ty, Src.getAlignment());
   Address Casted = CGF.Builder.CreateElementBitCast(Tmp,CGF.Int8Ty);
+  if (EndianAlign && CGF.CGM.getDataLayout().isBigEndian()) {
+    // Offset address to match LSBs if endian alignment is required
+    auto Offset = CharUnits::fromQuantity(DstSize - SrcSize);
+    Casted = CGF.Builder.CreateConstInBoundsByteGEP(Casted, Offset);
+  }
   Address SrcCasted = CGF.Builder.CreateElementBitCast(Src,CGF.Int8Ty);
   CGF.Builder.CreateMemCpy(Casted, SrcCasted,
       llvm::ConstantInt::get(CGF.IntPtrTy, SrcSize),
@@ -1296,6 +1302,7 @@
 static void CreateCoercedStore(llvm::Value *Src,
                                Address Dst,
                                bool DstIsVolatile,
+                               bool EndianAlign,
                                CodeGenFunction &CGF) {
   llvm::Type *SrcTy = Src->getType();
   llvm::Type *DstTy = Dst.getType()->getElementType();
@@ -1348,6 +1355,11 @@
     Address Tmp = CreateTempAllocaForCoercion(CGF, SrcTy, Dst.getAlignment());
     CGF.Builder.CreateStore(Src, Tmp);
     Address Casted = CGF.Builder.CreateElementBitCast(Tmp,CGF.Int8Ty);
+    if (EndianAlign && CGF.CGM.getDataLayout().isBigEndian()) {
+      // Offset address to match LSBs if endian alignment is required
+      auto Offset = CharUnits::fromQuantity(SrcSize - DstSize);
+      Casted = CGF.Builder.CreateConstInBoundsByteGEP(Casted, Offset);
+    }
     Address DstCasted = CGF.Builder.CreateElementBitCast(Dst,CGF.Int8Ty);
     CGF.Builder.CreateMemCpy(DstCasted, Casted,
         llvm::ConstantInt::get(CGF.IntPtrTy, DstSize),
@@ -2557,7 +2569,8 @@
         assert(NumIRArgs == 1);
         auto AI = FnArgs[FirstIRArg];
         AI->setName(Arg->getName() + ".coerce");
-        CreateCoercedStore(AI, Ptr, /*DstIsVolatile=*/false, *this);
+        CreateCoercedStore(AI, Ptr, /*DstIsVolatile=*/false,
+                           ArgI.getEndianAlign(), *this);
       }
 
       // Match to what EmitParmDecl is expecting for this type.
@@ -2947,7 +2960,8 @@
       // If the value is offset in memory, apply the offset now.
       Address V = emitAddressAtOffset(*this, ReturnValue, RetAI);
 
-      RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), *this);
+      RV = CreateCoercedLoad(V, RetAI.getCoerceToType(), RetAI.getEndianAlign(),
+                             *this);
     }
 
     // In ARC, end functions that return a retainable type with a call
@@ -4307,8 +4321,8 @@
       } else {
         // In the simple case, just pass the coerced loaded value.
         assert(NumIRArgs == 1);
-        IRCallArgs[FirstIRArg] =
-          CreateCoercedLoad(Src, ArgInfo.getCoerceToType(), *this);
+        IRCallArgs[FirstIRArg] = CreateCoercedLoad(
+            Src, ArgInfo.getCoerceToType(), ArgInfo.getEndianAlign(), *this);
       }
 
       break;
@@ -4763,7 +4777,8 @@
 
       // If the value is offset in memory, apply the offset now.
       Address StorePtr = emitAddressAtOffset(*this, DestPtr, RetAI);
-      CreateCoercedStore(CI, StorePtr, DestIsVolatile, *this);
+      CreateCoercedStore(CI, StorePtr, DestIsVolatile, RetAI.getEndianAlign(),
+                         *this);
 
       return convertTempToRValue(DestPtr, RetTy, SourceLocation());
     }
Index: clang/include/clang/CodeGen/CGFunctionInfo.h
===================================================================
--- clang/include/clang/CodeGen/CGFunctionInfo.h
+++ clang/include/clang/CodeGen/CGFunctionInfo.h
@@ -93,6 +93,7 @@
   bool SRetAfterThis : 1;   // isIndirect()
   bool InReg : 1;           // isDirect() || isExtend() || isIndirect()
   bool CanBeFlattened: 1;   // isDirect()
+  bool EndianAlign: 1;      // isDirect()
   bool SignExt : 1;         // isExtend()
 
   bool canHavePaddingType() const {
@@ -110,19 +111,21 @@
 
 public:
   ABIArgInfo(Kind K = Direct)
-      : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0),
-        TheKind(K), PaddingInReg(false), InAllocaSRet(false),
-        IndirectByVal(false), IndirectRealign(false), SRetAfterThis(false),
-        InReg(false), CanBeFlattened(false), SignExt(false) {}
+      : TypeData(nullptr), PaddingType(nullptr), DirectOffset(0), TheKind(K),
+        PaddingInReg(false), InAllocaSRet(false), IndirectByVal(false),
+        IndirectRealign(false), SRetAfterThis(false), InReg(false),
+        CanBeFlattened(false), EndianAlign(false), SignExt(false) {}
 
   static ABIArgInfo getDirect(llvm::Type *T = nullptr, unsigned Offset = 0,
                               llvm::Type *Padding = nullptr,
-                              bool CanBeFlattened = true) {
+                              bool CanBeFlattened = true,
+                              bool EndianAlign = false) {
     auto AI = ABIArgInfo(Direct);
     AI.setCoerceToType(T);
     AI.setPaddingType(Padding);
     AI.setDirectOffset(Offset);
     AI.setCanBeFlattened(CanBeFlattened);
+    AI.setEndianAlign(EndianAlign);
     return AI;
   }
   static ABIArgInfo getDirectInReg(llvm::Type *T = nullptr) {
@@ -402,6 +405,16 @@
     CanBeFlattened = Flatten;
   }
 
+  bool getEndianAlign() const {
+    assert(isDirect() && "Invalid kind!");
+    return EndianAlign;
+  }
+
+  void setEndianAlign(bool Align) {
+    assert(isDirect() && "Invalid kind!");
+    EndianAlign = Align;
+  }
+
   void dump() const;
 };
 
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to