[llvm-commits] [dragonegg] r152542 - /dragonegg/trunk/src/Convert.cpp

Duncan Sands baldrick at free.fr
Sun Mar 11 09:16:17 PDT 2012


Author: baldrick
Date: Sun Mar 11 11:16:17 2012
New Revision: 152542

URL: http://llvm.org/viewvc/llvm-project?rev=152542&view=rev
Log:
Work towards eliminating Mem2Reg and Reg2Mem (and the built in assumptions about
memory layout) in favour of LoadRegisterFromMemory and StoreRegisterToMemory by
rewriting these last to not use Mem2Reg/Reg2Mem and to not assume anything about
in-memory types.  I tried to make these future proof by correctly handling things
like complex types with a boolean element type and vectors of boolean even though
GCC does't currently produce them.

Modified:
    dragonegg/trunk/src/Convert.cpp

Modified: dragonegg/trunk/src/Convert.cpp
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/src/Convert.cpp?rev=152542&r1=152541&r2=152542&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Sun Mar 11 11:16:17 2012
@@ -137,6 +137,40 @@
   return StringRef();
 }
 
+/// DisplaceLocationByUnits - Move a memory location by a fixed number of units.
+/// This uses an "inbounds" getelementptr, so the displacement should remain
+/// inside the original object.
+MemRef DisplaceLocationByUnits(MemRef Loc, int32_t Offset,
+                               LLVMBuilder &Builder) {
+  // Convert to a byte pointer and displace by the offset.
+  unsigned AddrSpace = cast<PointerType>(Loc.Ptr->getType())->getAddressSpace();
+  Type *UnitPtrTy = GetUnitPointerType(Context, AddrSpace);
+  Value *Ptr = Builder.CreateBitCast(Loc.Ptr, UnitPtrTy);
+  Ptr = Builder.CreateConstInBoundsGEP1_32(Ptr, Offset);
+  Ptr = Builder.CreateBitCast(Ptr, Loc.Ptr->getType());
+  uint32_t Align = MinAlign(Loc.getAlignment(), Offset);
+  return MemRef(Ptr, Align, Loc.Volatile);
+}
+
+/// LoadFromLocation - Load a value of the given type from a memory location.
+static LoadInst *LoadFromLocation(MemRef Loc, Type *Ty, LLVMBuilder &Builder) {
+  unsigned AddrSpace = cast<PointerType>(Loc.Ptr->getType())->getAddressSpace();
+  Value *Ptr = Builder.CreateBitCast(Loc.Ptr, Ty->getPointerTo(AddrSpace));
+  LoadInst *LI = Builder.CreateLoad(Ptr, Loc.Volatile);
+  LI->setAlignment(Loc.getAlignment());
+  return LI;
+}
+
+/// StoreToLocation - Store a value to the given memory location.
+static StoreInst *StoreToLocation(Value *V, MemRef Loc, LLVMBuilder &Builder) {
+  Type *Ty = V->getType();
+  unsigned AddrSpace = cast<PointerType>(Loc.Ptr->getType())->getAddressSpace();
+  Value *Ptr = Builder.CreateBitCast(Loc.Ptr, Ty->getPointerTo(AddrSpace));
+  StoreInst *SI = Builder.CreateStore(V, Ptr, Loc.Volatile);
+  SI->setAlignment(Loc.getAlignment());
+  return SI;
+}
+
 /// Mem2Reg - Convert a value of in-memory type (that given by ConvertType)
 /// to in-register type (that given by getRegType).  TODO: Eliminate these
 /// methods: "memory" values should never be held in registers.  Currently
@@ -245,6 +279,59 @@
   llvm_unreachable("Don't know how to turn this into memory!");
 }
 
+/// isDirectMemoryAccessSafe - Whether directly storing/loading a value of the
+/// given register type generates the correct in-memory representation for the
+/// type.  Eg, if a 32 bit wide integer type has only one bit of precision then
+/// the register type is i1 and the in-memory type i32.  Storing an i1 directly
+/// to memory would not properly set up all 32 in-memory bits, thus this method
+/// would return false.
+static bool isDirectMemoryAccessSafe(Type *RegTy, tree type) {
+  assert(RegTy == getRegType(type) && "Wrong register type!");
+
+  switch (TREE_CODE(type)) {
+  default:
+    debug_tree(type);
+    llvm_unreachable("Unknown register type!");
+
+  case BOOLEAN_TYPE:
+  case ENUMERAL_TYPE:
+  case INTEGER_TYPE:
+    assert(RegTy->isIntegerTy() && "Expected an integer type!");
+    return RegTy->getIntegerBitWidth() == GET_MODE_BITSIZE(TYPE_MODE(type));
+
+  case COMPLEX_TYPE:
+  case VECTOR_TYPE: {
+    assert((TREE_CODE(type) != COMPLEX_TYPE || RegTy->isStructTy()) &&
+           "Expected a struct type!");
+    assert((TREE_CODE(type) != VECTOR_TYPE || RegTy->isVectorTy()) &&
+           "Expected a vector type!");
+    tree elt_type = main_type(type);
+    Type *EltRegTy = getRegType(elt_type);
+    // Check that fields are safe to access directly.
+    if (!isDirectMemoryAccessSafe(EltRegTy, elt_type))
+      return false;
+    // Check that the field positions agree with GCC.
+    unsigned StrideBits = GET_MODE_BITSIZE(TYPE_MODE(elt_type));
+    return getTargetData().getTypeAllocSizeInBits(EltRegTy) == StrideBits;
+  }
+
+  case OFFSET_TYPE:
+    assert(RegTy->isIntegerTy() && "Expected an integer type!");
+    return true;
+
+  case POINTER_TYPE:
+  case REFERENCE_TYPE:
+    assert(RegTy->isPointerTy() && "Expected a pointer type!");
+    return true;
+
+  case REAL_TYPE:
+    assert(RegTy->isFloatingPointTy() && "Expected a floating point type!");
+    // NOTE: This might be wrong for floats with precision less than their alloc
+    // size on big-endian machines.
+    return true;
+  }
+}
+
 /// LoadRegisterFromMemory - Loads a value of the given scalar GCC type from
 /// the memory location pointed to by Loc.  Takes care of adjusting for any
 /// differences between in-memory and in-register types (the returned value
@@ -252,11 +339,84 @@
 static Value *LoadRegisterFromMemory(MemRef Loc, tree type,
                                      LLVMBuilder &Builder) {
   // NOTE: Needs to be kept in sync with getRegType.
-  Type *MemTy = ConvertType(type);
-  Value *Ptr = Builder.CreateBitCast(Loc.Ptr, MemTy->getPointerTo());
-  LoadInst *LI = Builder.CreateLoad(Ptr, Loc.Volatile);
-  LI->setAlignment(Loc.getAlignment());
-  return Mem2Reg(LI, type, Builder);
+  Type *RegTy = getRegType(type);
+
+  // If loading the register type directly out of memory gives the right result,
+  // then just do that.
+  if (isDirectMemoryAccessSafe(RegTy, type))
+    return LoadFromLocation(Loc, RegTy, Builder);
+
+  // There is a discrepancy between the in-register type and the in-memory type.
+  switch (TREE_CODE(type)) {
+  default:
+    debug_tree(type);
+    llvm_unreachable("Unexpected type mismatch!");
+
+  case BOOLEAN_TYPE:
+  case ENUMERAL_TYPE:
+  case INTEGER_TYPE: {
+    // For integral types, load an integer with size equal to the mode size,
+    // then truncate down to the precision.  For example, when extracting a bool
+    // this probably first loads out an i8 or i32 which is then truncated to i1.
+    // This roundabout approach means we get the right result on both little and
+    // big endian machines.
+    unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(type));
+    Type *MemTy = IntegerType::get(Context, Size);
+    LoadInst *LI = LoadFromLocation(Loc, MemTy, Builder);
+    return Builder.CreateTruncOrBitCast(LI, RegTy);
+  }
+
+  case COMPLEX_TYPE: {
+    // Load the complex number component by component.
+    tree elt_type = main_type(type);
+    unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type));
+    Value *RealPart = LoadRegisterFromMemory(Loc, elt_type, Builder);
+    Loc = DisplaceLocationByUnits(Loc, Stride, Builder);
+    Value *ImagPart = LoadRegisterFromMemory(Loc, elt_type, Builder);
+    Value *Res = UndefValue::get(RegTy);
+    Res = Builder.CreateInsertValue(Res, RealPart, 0);
+    Res = Builder.CreateInsertValue(Res, ImagPart, 1);
+    return Res;
+  }
+
+  case VECTOR_TYPE: {
+    tree elt_type = main_type(type);
+    Type *EltRegTy = getRegType(elt_type);
+    unsigned NumElts = TYPE_VECTOR_SUBPARTS(type);
+    unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(elt_type));
+    // If, say, the register type is a vector of i1 but memory is laid out as a
+    // vector of i32 then load an i32 vector out and truncate to a vector of i1.
+    if (EltRegTy->isIntegerTy() && EltRegTy->getIntegerBitWidth() != Size) {
+      // See if changing the element type to an integer with size equal to the
+      // mode size gives a vector type that corresponds to the in-memory layout.
+      Type *MemTy = IntegerType::get(Context, Size);
+      if (getTargetData().getTypeAllocSizeInBits(MemTy) == Size) {
+        // It does!  Load out the memory as a vector of that type then truncate
+        // to the register size.
+        Type *MemVecTy = VectorType::get(MemTy, NumElts);
+        LoadInst *LI = LoadFromLocation(Loc, MemVecTy, Builder);
+        return Builder.CreateTruncOrBitCast(LI, RegTy);
+      }
+    }
+    // Otherwise, load the vector component by component.
+    Value *Res = UndefValue::get(RegTy);
+    bool isVectorOfPointers = isa<PointerType>(EltRegTy);
+    unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type));
+    IntegerType *IntPtrTy = getTargetData().getIntPtrType(Context);
+    for (unsigned i = 0; i != NumElts; ++i) {
+      Value *Idx = Builder.getInt32(i);
+      Value *Elt = LoadRegisterFromMemory(Loc, elt_type, Builder);
+      // LLVM does not support vectors of pointers, so turn any pointers into
+      // integers.
+      if (isVectorOfPointers)
+        Elt = Builder.CreatePtrToInt(Elt, IntPtrTy);
+      Res = Builder.CreateInsertElement(Res, Elt, Idx);
+      if (i + 1 != NumElts)
+        Loc = DisplaceLocationByUnits(Loc, Stride, Builder);
+    }
+    return Res;
+  }
+  }
 }
 
 /// StoreRegisterToMemory - Stores the given value to the memory pointed to by
@@ -265,11 +425,80 @@
 static void StoreRegisterToMemory(Value *V, MemRef Loc, tree type,
                                   LLVMBuilder &Builder) {
   // NOTE: Needs to be kept in sync with getRegType.
-  Type *MemTy = ConvertType(type);
-  Value *Ptr = Builder.CreateBitCast(Loc.Ptr, MemTy->getPointerTo());
-  StoreInst *SI = Builder.CreateStore(Reg2Mem(V, type, Builder), Ptr,
-                                      Loc.Volatile);
-  SI->setAlignment(Loc.getAlignment());
+  assert(V->getType() == getRegType(type) && "Not of register type!");
+
+  // If storing the register directly to memory gives the right result, then
+  // just do that.
+  if (isDirectMemoryAccessSafe(V->getType(), type)) {
+    StoreToLocation(V, Loc, Builder);
+    return;
+  }
+
+  // There is a discrepancy between the in-register type and the in-memory type.
+  switch (TREE_CODE(type)) {
+  default:
+    debug_tree(type);
+    llvm_unreachable("Unexpected type mismatch!");
+
+  case BOOLEAN_TYPE:
+  case ENUMERAL_TYPE:
+  case INTEGER_TYPE: {
+    // For integral types extend to an integer with size equal to the mode size.
+    // For example, when inserting a bool this probably extends it to an i8 or
+    // to an i32.  This approach means we get the right result on both little
+    // and big endian machines.
+    unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(type));
+    Type *MemTy = IntegerType::get(Context, Size);
+    V = Builder.CreateIntCast(V, MemTy, /*isSigned*/!TYPE_UNSIGNED(type));
+    StoreToLocation(V, Loc, Builder);
+    break;
+  }
+
+  case COMPLEX_TYPE: {
+    // Store the complex number component by component.
+    tree elt_type = main_type(type);
+    unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type));
+    Value *RealPart = Builder.CreateExtractValue(V, 0);
+    Value *ImagPart = Builder.CreateExtractValue(V, 1);
+    StoreRegisterToMemory(RealPart, Loc, elt_type, Builder);
+    Loc = DisplaceLocationByUnits(Loc, Stride, Builder);
+    StoreRegisterToMemory(ImagPart, Loc, elt_type, Builder);
+    break;
+  }
+
+  case VECTOR_TYPE: {
+    tree elt_type = main_type(type);
+    Type *EltRegTy = getRegType(elt_type);
+    unsigned NumElts = TYPE_VECTOR_SUBPARTS(type);
+    unsigned Size = GET_MODE_BITSIZE(TYPE_MODE(elt_type));
+    // If, say, the register type is a vector of i1 but memory is laid out as a
+    // vector of i32 then extend the i1 vector to an i32 vector and store that.
+    if (EltRegTy->isIntegerTy() && EltRegTy->getIntegerBitWidth() != Size) {
+      // See if changing the element type to an integer with size equal to the
+      // mode size gives a vector type that corresponds to the in-memory layout.
+      Type *MemTy = IntegerType::get(Context, Size);
+      if (getTargetData().getTypeAllocSizeInBits(MemTy) == Size) {
+        // It does!  Extend the register value to a vector of that type then
+        // store it to memory.
+        Type *MemVecTy = VectorType::get(MemTy, NumElts);
+        V = Builder.CreateIntCast(V, MemVecTy,
+                                  /*isSigned*/!TYPE_UNSIGNED(elt_type));
+        StoreToLocation(V, Loc, Builder);
+        break;
+      }
+    }
+    // Otherwise, store the vector component by component.
+    unsigned Stride = GET_MODE_SIZE(TYPE_MODE(elt_type));
+    for (unsigned i = 0; i != NumElts; ++i) {
+      Value *Idx = Builder.getInt32(i);
+      Value *Elt = Builder.CreateExtractElement(V, Idx);
+      StoreRegisterToMemory(Elt, Loc, elt_type, Builder);
+      if (i + 1 != NumElts)
+        Loc = DisplaceLocationByUnits(Loc, Stride, Builder);
+    }
+    break;
+  }
+  }
 }
 
 
@@ -5609,6 +5838,7 @@
   // type void.
   if (Ty->isVoidTy()) Ty = StructType::get(Context);
   PointerType *PTy = Ty->getPointerTo();
+  // FIXME: If gcc wants less alignment, we should probably use that.
   unsigned Alignment = Ty->isSized() ? TD.getABITypeAlignment(Ty) : 1;
   if (DECL_ALIGN(exp)) {
     if (DECL_USER_ALIGN(exp) || 8 * Alignment < (unsigned)DECL_ALIGN(exp))





More information about the llvm-commits mailing list