r263192 - Add a coerce-and-expand ABIArgInfo as a generalization of some

John McCall via cfe-commits cfe-commits at lists.llvm.org
Thu Mar 10 20:30:44 PST 2016


Author: rjmccall
Date: Thu Mar 10 22:30:43 2016
New Revision: 263192

URL: http://llvm.org/viewvc/llvm-project?rev=263192&view=rev
Log:
Add a coerce-and-expand ABIArgInfo as a generalization of some
of the things we do with Expand / Direct.

NFC for now, but this will be used by swiftcall expansion.

Modified:
    cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
    cfe/trunk/lib/CodeGen/CGBuilder.h
    cfe/trunk/lib/CodeGen/CGCall.cpp
    cfe/trunk/lib/CodeGen/TargetInfo.cpp

Modified: cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h?rev=263192&r1=263191&r2=263192&view=diff
==============================================================================
--- cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h (original)
+++ cfe/trunk/include/clang/CodeGen/CGFunctionInfo.h Thu Mar 10 22:30:43 2016
@@ -19,15 +19,11 @@
 #include "clang/AST/CanonicalType.h"
 #include "clang/AST/CharUnits.h"
 #include "clang/AST/Type.h"
+#include "llvm/IR/DerivedTypes.h"
 #include "llvm/ADT/FoldingSet.h"
 #include "llvm/Support/TrailingObjects.h"
 #include <cassert>
 
-namespace llvm {
-  class Type;
-  class StructType;
-}
-
 namespace clang {
 class Decl;
 
@@ -64,6 +60,12 @@ public:
     /// are all scalar types or are themselves expandable types.
     Expand,
 
+    /// CoerceAndExpand - Only valid for aggregate argument types. The
+    /// structure should be expanded into consecutive arguments corresponding
+    /// to the non-array elements of the type stored in CoerceToType.
+    /// Array elements in the type are assumed to be padding and skipped.
+    CoerceAndExpand,
+
     /// InAlloca - Pass the argument directly using the LLVM inalloca attribute.
     /// This is similar to indirect with byval, except it only applies to
     /// arguments stored in memory and forbids any implicit copies.  When
@@ -75,8 +77,11 @@ public:
   };
 
 private:
-  llvm::Type *TypeData; // isDirect() || isExtend()
-  llvm::Type *PaddingType;
+  llvm::Type *TypeData; // canHaveCoerceToType()
+  union {
+    llvm::Type *PaddingType; // canHavePaddingType()
+    llvm::Type *UnpaddedCoerceAndExpandType; // isCoerceAndExpand()
+  };
   union {
     unsigned DirectOffset;     // isDirect() || isExtend()
     unsigned IndirectAlign;    // isIndirect()
@@ -91,8 +96,22 @@ private:
   bool InReg : 1;           // isDirect() || isExtend() || isIndirect()
   bool CanBeFlattened: 1;   // isDirect()
 
+  bool canHavePaddingType() const {
+    return isDirect() || isExtend() || isIndirect() || isExpand();
+  }
+  void setPaddingType(llvm::Type *T) {
+    assert(canHavePaddingType());
+    PaddingType = T;
+  }
+
+  void setUnpaddedCoerceToType(llvm::Type *T) {
+    assert(isCoerceAndExpand());
+    UnpaddedCoerceAndExpandType = T;
+  }
+
   ABIArgInfo(Kind K)
-      : PaddingType(nullptr), TheKind(K), PaddingInReg(false), InReg(false) {}
+      : TheKind(K), PaddingInReg(false), InReg(false) {
+  }
 
 public:
   ABIArgInfo()
@@ -104,8 +123,8 @@ public:
                               bool CanBeFlattened = true) {
     auto AI = ABIArgInfo(Direct);
     AI.setCoerceToType(T);
-    AI.setDirectOffset(Offset);
     AI.setPaddingType(Padding);
+    AI.setDirectOffset(Offset);
     AI.setCanBeFlattened(CanBeFlattened);
     return AI;
   }
@@ -117,6 +136,7 @@ public:
   static ABIArgInfo getExtend(llvm::Type *T = nullptr) {
     auto AI = ABIArgInfo(Extend);
     AI.setCoerceToType(T);
+    AI.setPaddingType(nullptr);
     AI.setDirectOffset(0);
     return AI;
   }
@@ -151,7 +171,9 @@ public:
     return AI;
   }
   static ABIArgInfo getExpand() {
-    return ABIArgInfo(Expand);
+    auto AI = ABIArgInfo(Expand);
+    AI.setPaddingType(nullptr);
+    return AI;
   }
   static ABIArgInfo getExpandWithPadding(bool PaddingInReg,
                                          llvm::Type *Padding) {
@@ -161,6 +183,54 @@ public:
     return AI;
   }
 
+  /// \param unpaddedCoerceToType The coerce-to type with padding elements
+  ///   removed, canonicalized to a single element if it would otherwise
+  ///   have exactly one element.
+  static ABIArgInfo getCoerceAndExpand(llvm::StructType *coerceToType,
+                                       llvm::Type *unpaddedCoerceToType) {
+#ifndef NDEBUG
+    // Sanity checks on unpaddedCoerceToType.
+
+    // Assert that we only have a struct type if there are multiple elements.
+    auto unpaddedStruct = dyn_cast<llvm::StructType>(unpaddedCoerceToType);
+    assert(!unpaddedStruct || unpaddedStruct->getNumElements() != 1);
+
+    // Assert that all the non-padding elements have a corresponding element
+    // in the unpadded type.
+    unsigned unpaddedIndex = 0;
+    for (auto eltType : coerceToType->elements()) {
+      if (isPaddingForCoerceAndExpand(eltType)) continue;
+      if (unpaddedStruct) {
+        assert(unpaddedStruct->getElementType(unpaddedIndex) == eltType);
+      } else {
+        assert(unpaddedIndex == 0 && unpaddedCoerceToType == eltType);
+      }
+      unpaddedIndex++;
+    }
+
+    // Assert that there aren't extra elements in the unpadded type.
+    if (unpaddedStruct) {
+      assert(unpaddedStruct->getNumElements() == unpaddedIndex);
+    } else {
+      assert(unpaddedIndex == 1);
+    }
+#endif
+
+    auto AI = ABIArgInfo(CoerceAndExpand);
+    AI.setCoerceToType(coerceToType);
+    AI.setUnpaddedCoerceToType(unpaddedCoerceToType);
+    return AI;
+  }
+
+  static bool isPaddingForCoerceAndExpand(llvm::Type *eltType) {
+    if (eltType->isArrayTy()) {
+      assert(eltType->getArrayElementType()->isIntegerTy(8));
+      return true;
+    } else {
+      return false;
+    }
+  }
+
   Kind getKind() const { return TheKind; }
   bool isDirect() const { return TheKind == Direct; }
   bool isInAlloca() const { return TheKind == InAlloca; }
@@ -168,8 +238,11 @@ public:
   bool isIgnore() const { return TheKind == Ignore; }
   bool isIndirect() const { return TheKind == Indirect; }
   bool isExpand() const { return TheKind == Expand; }
+  bool isCoerceAndExpand() const { return TheKind == CoerceAndExpand; }
 
-  bool canHaveCoerceToType() const { return isDirect() || isExtend(); }
+  bool canHaveCoerceToType() const {
+    return isDirect() || isExtend() || isCoerceAndExpand();
+  }
 
   // Direct/Extend accessors
   unsigned getDirectOffset() const {
@@ -181,9 +254,9 @@ public:
     DirectOffset = Offset;
   }
 
-  llvm::Type *getPaddingType() const { return PaddingType; }
-
-  void setPaddingType(llvm::Type *T) { PaddingType = T; }
+  llvm::Type *getPaddingType() const {
+    return (canHavePaddingType() ? PaddingType : nullptr);
+  }
 
   bool getPaddingInReg() const {
     return PaddingInReg;
@@ -202,6 +275,26 @@ public:
     TypeData = T;
   }
 
+  llvm::StructType *getCoerceAndExpandType() const {
+    assert(isCoerceAndExpand());
+    return cast<llvm::StructType>(TypeData);
+  }
+
+  llvm::Type *getUnpaddedCoerceAndExpandType() const {
+    assert(isCoerceAndExpand());
+    return UnpaddedCoerceAndExpandType;
+  }
+
+  ArrayRef<llvm::Type *>getCoerceAndExpandTypeSequence() const {
+    assert(isCoerceAndExpand());
+    if (auto structTy =
+          dyn_cast<llvm::StructType>(UnpaddedCoerceAndExpandType)) {
+      return structTy->elements();
+    } else {
+      return llvm::makeArrayRef(&UnpaddedCoerceAndExpandType, 1);
+    }
+  }
+
   bool getInReg() const {
     assert((isDirect() || isExtend() || isIndirect()) && "Invalid kind!");
     return InReg;

Modified: cfe/trunk/lib/CodeGen/CGBuilder.h
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGBuilder.h?rev=263192&r1=263191&r2=263192&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGBuilder.h (original)
+++ cfe/trunk/lib/CodeGen/CGBuilder.h Thu Mar 10 22:30:43 2016
@@ -10,6 +10,7 @@
 #ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
 #define LLVM_CLANG_LIB_CODEGEN_CGBUILDER_H
 
+#include "llvm/IR/DataLayout.h"
 #include "llvm/IR/IRBuilder.h"
 #include "Address.h"
 #include "CodeGenTypeCache.h"
@@ -194,6 +195,12 @@ public:
                                    Addr.getPointer(), Index, Name),
                    Addr.getAlignment().alignmentAtOffset(Offset));
   }
+  Address CreateStructGEP(Address Addr, unsigned Index,
+                          const llvm::StructLayout *Layout,
+                          const llvm::Twine &Name = "") {
+    auto Offset = CharUnits::fromQuantity(Layout->getElementOffset(Index));
+    return CreateStructGEP(Addr, Index, Offset, Name);
+  }
 
   /// Given
   ///   %addr = [n x T]* ...

Modified: cfe/trunk/lib/CodeGen/CGCall.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGCall.cpp?rev=263192&r1=263191&r2=263192&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/CGCall.cpp (original)
+++ cfe/trunk/lib/CodeGen/CGCall.cpp Thu Mar 10 22:30:43 2016
@@ -1357,11 +1357,13 @@ void ClangToLLVMArgMapping::construct(co
       // ignore and inalloca doesn't have matching LLVM parameters.
       IRArgs.NumberOfArgs = 0;
       break;
-    case ABIArgInfo::Expand: {
+    case ABIArgInfo::CoerceAndExpand:
+      IRArgs.NumberOfArgs = AI.getCoerceAndExpandTypeSequence().size();
+      break;
+    case ABIArgInfo::Expand:
       IRArgs.NumberOfArgs = getExpansionSize(ArgType, Context);
       break;
     }
-    }
 
     if (IRArgs.NumberOfArgs > 0) {
       IRArgs.FirstArgIndex = IRArgNo;
@@ -1460,6 +1462,10 @@ CodeGenTypes::GetFunctionType(const CGFu
   case ABIArgInfo::Ignore:
     resultType = llvm::Type::getVoidTy(getLLVMContext());
     break;
+
+  case ABIArgInfo::CoerceAndExpand:
+    resultType = retAI.getUnpaddedCoerceAndExpandType();
+    break;
   }
 
   ClangToLLVMArgMapping IRFunctionArgs(getContext(), FI, true);
@@ -1527,6 +1533,15 @@ CodeGenTypes::GetFunctionType(const CGFu
       break;
     }
 
+    case ABIArgInfo::CoerceAndExpand: {
+      auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
+      for (auto EltTy : ArgInfo.getCoerceAndExpandTypeSequence()) {
+        *ArgTypesIter++ = EltTy;
+      }
+      assert(ArgTypesIter == ArgTypes.begin() + FirstIRArg + NumIRArgs);
+      break;
+    }
+
     case ABIArgInfo::Expand:
       auto ArgTypesIter = ArgTypes.begin() + FirstIRArg;
       getExpandedTypes(it->type, ArgTypesIter);
@@ -1768,6 +1783,9 @@ void CodeGenModule::ConstructAttributeLi
     break;
   }
 
+  case ABIArgInfo::CoerceAndExpand:
+    break;
+
   case ABIArgInfo::Expand:
     llvm_unreachable("Invalid ABI kind for return argument");
   }
@@ -1875,7 +1893,8 @@ void CodeGenModule::ConstructAttributeLi
     }
     case ABIArgInfo::Ignore:
     case ABIArgInfo::Expand:
-      continue;
+    case ABIArgInfo::CoerceAndExpand:
+      break;
 
     case ABIArgInfo::InAlloca:
       // inalloca disables readnone and readonly.
@@ -2248,6 +2267,29 @@ void CodeGenFunction::EmitFunctionProlog
       break;
     }
 
+    case ABIArgInfo::CoerceAndExpand: {
+      // Reconstruct into a temporary.
+      Address alloca = CreateMemTemp(Ty, getContext().getDeclAlign(Arg));
+      ArgVals.push_back(ParamValue::forIndirect(alloca));
+
+      auto coercionType = ArgI.getCoerceAndExpandType();
+      alloca = Builder.CreateElementBitCast(alloca, coercionType);
+      auto layout = CGM.getDataLayout().getStructLayout(coercionType);
+
+      unsigned argIndex = FirstIRArg;
+      for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
+        llvm::Type *eltType = coercionType->getElementType(i);
+        if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType))
+          continue;
+
+        auto eltAddr = Builder.CreateStructGEP(alloca, i, layout);
+        auto elt = FnArgs[argIndex++];
+        Builder.CreateStore(elt, eltAddr);
+      }
+      assert(argIndex == FirstIRArg + NumIRArgs);
+      break;
+    }
+
     case ABIArgInfo::Expand: {
       // If this structure was expanded into multiple arguments then
       // we need to create a temporary and reconstruct it from the
@@ -2638,6 +2680,40 @@ void CodeGenFunction::EmitFunctionEpilog
   case ABIArgInfo::Ignore:
     break;
 
+  case ABIArgInfo::CoerceAndExpand: {
+    auto coercionType = RetAI.getCoerceAndExpandType();
+    auto layout = CGM.getDataLayout().getStructLayout(coercionType);
+
+    // Load all of the coerced elements out into results.
+    llvm::SmallVector<llvm::Value*, 4> results;
+    Address addr = Builder.CreateElementBitCast(ReturnValue, coercionType);
+    for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
+      auto coercedEltType = coercionType->getElementType(i);
+      if (ABIArgInfo::isPaddingForCoerceAndExpand(coercedEltType))
+        continue;
+
+      auto eltAddr = Builder.CreateStructGEP(addr, i, layout);
+      auto elt = Builder.CreateLoad(eltAddr);
+      results.push_back(elt);
+    }
+
+    // If we have one result, it's the single direct result type.
+    if (results.size() == 1) {
+      RV = results[0];
+
+    // Otherwise, we need to make a first-class aggregate.
+    } else {
+      // Construct a return type that lacks padding elements.
+      llvm::Type *returnType = RetAI.getUnpaddedCoerceAndExpandType();
+
+      RV = llvm::UndefValue::get(returnType);
+      for (unsigned i = 0, e = results.size(); i != e; ++i) {
+        RV = Builder.CreateInsertValue(RV, results[i], i);
+      }
+    }
+    break;
+  }
+
   case ABIArgInfo::Expand:
     llvm_unreachable("Invalid ABI kind for return argument");
   }
@@ -3377,7 +3453,7 @@ RValue CodeGenFunction::EmitCall(const C
   // alloca to hold the result, unless one is given to us.
   Address SRetPtr = Address::invalid();
   size_t UnusedReturnSize = 0;
-  if (RetAI.isIndirect() || RetAI.isInAlloca()) {
+  if (RetAI.isIndirect() || RetAI.isInAlloca() || RetAI.isCoerceAndExpand()) {
     if (!ReturnValue.isNull()) {
       SRetPtr = ReturnValue.getValue();
     } else {
@@ -3391,7 +3467,7 @@ RValue CodeGenFunction::EmitCall(const C
     }
     if (IRFunctionArgs.hasSRetArg()) {
       IRCallArgs[IRFunctionArgs.getSRetArgNo()] = SRetPtr.getPointer();
-    } else {
+    } else if (RetAI.isInAlloca()) {
       Address Addr = createInAllocaStructGEP(RetAI.getInAllocaFieldIndex());
       Builder.CreateStore(SRetPtr.getPointer(), Addr);
     }
@@ -3571,6 +3647,29 @@ RValue CodeGenFunction::EmitCall(const C
       break;
     }
 
+    case ABIArgInfo::CoerceAndExpand: {
+      assert(RV.isAggregate() &&
+             "CoerceAndExpand does not support non-aggregate types yet");
+
+      auto coercionType = ArgInfo.getCoerceAndExpandType();
+      auto layout = CGM.getDataLayout().getStructLayout(coercionType);
+
+      Address addr = RV.getAggregateAddress();
+      addr = Builder.CreateElementBitCast(addr, coercionType);
+
+      unsigned IRArgPos = FirstIRArg;
+      for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
+        llvm::Type *eltType = coercionType->getElementType(i);
+        if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
+        Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
+        llvm::Value *elt = Builder.CreateLoad(eltAddr);
+        IRCallArgs[IRArgPos++] = elt;
+      }
+      assert(IRArgPos == FirstIRArg + NumIRArgs);
+
+      break;
+    }
+
     case ABIArgInfo::Expand:
       unsigned IRArgPos = FirstIRArg;
       ExpandTypeToArgs(I->Ty, RV, IRFuncTy, IRCallArgs, IRArgPos);
@@ -3770,6 +3869,24 @@ RValue CodeGenFunction::EmitCall(const C
       return ret;
     }
 
+    case ABIArgInfo::CoerceAndExpand: {
+      auto coercionType = RetAI.getCoerceAndExpandType();
+      auto layout = CGM.getDataLayout().getStructLayout(coercionType);
+
+      Address addr = SRetPtr;
+      addr = Builder.CreateElementBitCast(addr, coercionType);
+
+      unsigned unpaddedIndex = 0;
+      for (unsigned i = 0, e = coercionType->getNumElements(); i != e; ++i) {
+        llvm::Type *eltType = coercionType->getElementType(i);
+        if (ABIArgInfo::isPaddingForCoerceAndExpand(eltType)) continue;
+        Address eltAddr = Builder.CreateStructGEP(addr, i, layout);
+        llvm::Value *elt = Builder.CreateExtractValue(CI, unpaddedIndex++);
+        Builder.CreateStore(elt, eltAddr);
+      }
+      break;
+    }
+
     case ABIArgInfo::Ignore:
       // If we are ignoring an argument that had a result, make sure to
       // construct the appropriate return value for our caller.

Modified: cfe/trunk/lib/CodeGen/TargetInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/TargetInfo.cpp?rev=263192&r1=263191&r2=263192&view=diff
==============================================================================
--- cfe/trunk/lib/CodeGen/TargetInfo.cpp (original)
+++ cfe/trunk/lib/CodeGen/TargetInfo.cpp Thu Mar 10 22:30:43 2016
@@ -160,6 +160,10 @@ LLVM_DUMP_METHOD void ABIArgInfo::dump()
   case Expand:
     OS << "Expand";
     break;
+  case CoerceAndExpand:
+    OS << "CoerceAndExpand Type=";
+    getCoerceAndExpandType()->print(OS);
+    break;
   }
   OS << ")\n";
 }
@@ -1570,6 +1574,7 @@ static bool isArgInAlloca(const ABIArgIn
   case ABIArgInfo::Direct:
   case ABIArgInfo::Extend:
   case ABIArgInfo::Expand:
+  case ABIArgInfo::CoerceAndExpand:
     if (Info.getInReg())
       return false;
     return true;
@@ -6829,6 +6834,7 @@ Address SparcV9ABIInfo::EmitVAArg(CodeGe
   CharUnits Stride;
   switch (AI.getKind()) {
   case ABIArgInfo::Expand:
+  case ABIArgInfo::CoerceAndExpand:
   case ABIArgInfo::InAlloca:
     llvm_unreachable("Unsupported ABI kind for va_arg");
 
@@ -7059,6 +7065,7 @@ Address XCoreABIInfo::EmitVAArg(CodeGenF
   CharUnits ArgSize = CharUnits::Zero();
   switch (AI.getKind()) {
   case ABIArgInfo::Expand:
+  case ABIArgInfo::CoerceAndExpand:
   case ABIArgInfo::InAlloca:
     llvm_unreachable("Unsupported ABI kind for va_arg");
   case ABIArgInfo::Ignore:




More information about the cfe-commits mailing list