[dragonegg] r182095 - Support for writing to bitfields of arbitrary scalar type. Tweak the code for

Duncan Sands baldrick at free.fr
Fri May 17 06:35:15 PDT 2013


Author: baldrick
Date: Fri May 17 08:35:15 2013
New Revision: 182095

URL: http://llvm.org/viewvc/llvm-project?rev=182095&view=rev
Log:
Support for writing to bitfields of arbitrary scalar type.  Tweak the code for
reading such bitfields while there.

Added:
    dragonegg/trunk/test/validator/ada/bitfield.adb
    dragonegg/trunk/test/validator/ada/bitfield.ads
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=182095&r1=182094&r2=182095&view=diff
==============================================================================
--- dragonegg/trunk/src/Convert.cpp (original)
+++ dragonegg/trunk/src/Convert.cpp Fri May 17 08:35:15 2013
@@ -2809,13 +2809,13 @@ Value *TreeToLLVM::EmitLoadOfLValue(tree
   // TODO: Arrange for Volatile to already be set in the LValue.
   unsigned Alignment = LV.getAlignment();
 
+  tree type = TREE_TYPE(exp);
   if (!LV.isBitfield())
     // Scalar value: emit a load.
-    return LoadRegisterFromMemory(LV, TREE_TYPE(exp), describeAliasSet(exp),
-                                  Builder);
+    return LoadRegisterFromMemory(LV, type, describeAliasSet(exp), Builder);
 
   // This is a bitfield reference.
-  Type *Ty = getRegType(TREE_TYPE(exp));
+  Type *Ty = getRegType(type);
   if (!LV.BitSize)
     return Constant::getNullValue(Ty);
 
@@ -2844,34 +2844,30 @@ Value *TreeToLLVM::EmitLoadOfLValue(tree
   // Shift the first bit of the bitfield to be bit zero.  This zaps any extra
   // bits that occurred before the start of the bitfield.  In the signed case
   // this also duplicates the sign bit, giving a sign extended value.
-  bool isSigned = !TYPE_UNSIGNED(TREE_TYPE(exp));
+  bool isSigned = !TYPE_UNSIGNED(type);
   Value *ShAmt = ConstantInt::get(LoadType, LoadSizeInBits - LV.BitSize);
   Val = isSigned ? Builder.CreateAShr(Val, ShAmt)
                  : Builder.CreateLShr(Val, ShAmt);
 
-  // If the result is an integer then cast to the right size and return.  This
-  // is an optimization: the code below would give the same result.
-  if (Ty->isIntegerTy())
-    return Builder.CreateIntCast(Val, Ty, isSigned);
-
-  // Otherwise the result type is a non-integer scalar, possibly a vector.
-  // Get the bits as an integer with the same alloc size as the result.
+  // Get the bits as an integer with the same in-memory size as the result.
   // Extending the integer with defined bits (rather than storing it as is to
   // the temporary, which in effect extends with undefined bits) is required
-  // to get the right result for C-like languages.
-  Type *ResIntTy = IntegerType::get(Context, DL.getTypeAllocSizeInBits(Ty));
+  // in order to get the right result for C-like languages.
+  unsigned MemSize = GET_MODE_BITSIZE(TYPE_MODE(type));
+  Type *ResIntTy = IntegerType::get(Context, MemSize);
   Value *ResInt = Builder.CreateIntCast(Val, ResIntTy, isSigned);
 
-  // Create a temporary with the final type and store the bits to it.
-  Alignment = std::max(DL.getPrefTypeAlignment(Ty),
-                                DL.getPrefTypeAlignment(ResIntTy));
-  MemRef Tmp(CreateTemporary(Ty, Alignment), Alignment, false);
-  Builder.CreateStore(ResInt,
-                      Builder.CreateBitCast(Tmp.Ptr, ResIntTy->getPointerTo()));
+  // Create the temporary, an integer.  Ensure it is sufficiently aligned for
+  // both the integer and the real type.  Store the bits to it.
+  Alignment = std::max(TYPE_ALIGN(type) / 8,
+                       DL.getPrefTypeAlignment(ResIntTy));
+  MemRef Tmp(CreateTemporary(ResIntTy, Alignment), Alignment, false);
+  Builder.CreateStore(ResInt, Tmp.Ptr);
+
   // At this point we have in essence just displaced the original set of bits to
   // a new memory location that is byte aligned, from which we now trivially load
   // the desired value.
-  return LoadRegisterFromMemory(Tmp, TREE_TYPE(exp), 0, Builder);
+  return LoadRegisterFromMemory(Tmp, type, 0, Builder);
 }
 
 Value *TreeToLLVM::EmitADDR_EXPR(tree exp) {
@@ -9199,78 +9195,108 @@ bool TreeToLLVM::EmitBuiltinCall(gimple
                     : 0;
     }
 
-    /// WriteScalarToLHS - Store RHS, a non-aggregate value, into the given LHS.
-    void TreeToLLVM::WriteScalarToLHS(tree lhs, Value * RHS) {
-      // May need a useless type conversion (useless_type_conversion_p).
-      RHS = TriviallyTypeConvert(RHS, getRegType(TREE_TYPE(lhs)));
-
-      // If this is the definition of an ssa name, record it in the SSANames map.
-      if (isa<SSA_NAME>(lhs)) {
-        if (flag_verbose_asm)
-          NameValue(RHS, lhs);
-        DefineSSAName(lhs, RHS);
-        return;
-      }
+/// WriteScalarToLHS - Store RHS, a non-aggregate value, into the given LHS.
+void TreeToLLVM::WriteScalarToLHS(tree lhs, Value * RHS) {
+  tree type = TREE_TYPE(lhs);
+
+  // May need a useless type conversion (useless_type_conversion_p).
+  RHS = TriviallyTypeConvert(RHS, getRegType(type));
+
+  // If this is the definition of an ssa name, record it in the SSANames map.
+  if (isa<SSA_NAME>(lhs)) {
+    if (flag_verbose_asm)
+      NameValue(RHS, lhs);
+    DefineSSAName(lhs, RHS);
+    return;
+  }
 
-      if (canEmitRegisterVariable(lhs)) {
-        // If this is a store to a register variable, EmitLV can't handle the dest
-        // (there is no l-value of a register variable).  Emit an inline asm node
-        // that copies the value into the specified register.
-        EmitModifyOfRegisterVariable(lhs, RHS);
-        return;
-      }
+  if (canEmitRegisterVariable(lhs)) {
+    // If this is a store to a register variable, EmitLV can't handle the dest
+    // (there is no l-value of a register variable).  Emit an inline asm node
+    // that copies the value into the specified register.
+    EmitModifyOfRegisterVariable(lhs, RHS);
+    return;
+  }
 
-      LValue LV = EmitLV(lhs);
-      LV.Volatile = TREE_THIS_VOLATILE(lhs);
-      // TODO: Arrange for Volatile to already be set in the LValue.
-      if (!LV.isBitfield()) {
-        // Non-bitfield, scalar value.  Just emit a store.
-        StoreRegisterToMemory(RHS, LV, TREE_TYPE(lhs), describeAliasSet(lhs),
-                              Builder);
-        return;
-      }
+  LValue LV = EmitLV(lhs);
+  LV.Volatile = TREE_THIS_VOLATILE(lhs);
+  // TODO: Arrange for Volatile to already be set in the LValue.
+  if (!LV.isBitfield()) {
+    // Non-bitfield, scalar value.  Just emit a store.
+    StoreRegisterToMemory(RHS, LV, type, describeAliasSet(lhs), Builder);
+    return;
+  }
 
-      // Last case, this is a store to a bitfield, so we have to emit a
-      // read/modify/write sequence.
-      if (!LV.BitSize)
-        return;
+  // Last case, this is a store to a bitfield, so we have to emit a
+  // read/modify/write sequence.
+  if (!LV.BitSize)
+    return;
 
-      // Load and store the minimum number of bytes that covers the field.
-      unsigned LoadSizeInBits = LV.BitStart + LV.BitSize;
-      LoadSizeInBits =
-          (unsigned) RoundUpToAlignment(LoadSizeInBits, BITS_PER_UNIT);
-      Type *LoadType = IntegerType::get(Context, LoadSizeInBits);
-
-      // Load the bits.
-      Value *Ptr = Builder.CreateBitCast(LV.Ptr, LoadType->getPointerTo());
-      Value *Val =
-          Builder.CreateAlignedLoad(Ptr, LV.getAlignment(), LV.Volatile);
-
-      // Get the right-hand side as a value of the same type.
-      // FIXME: This assumes the right-hand side is an integer.
-      bool isSigned = !TYPE_UNSIGNED(TREE_TYPE(lhs));
-      RHS = CastToAnyType(RHS, isSigned, LoadType, isSigned);
-
-      // Shift the right-hand side so that its bits are in the right position.
-      unsigned FirstBitInVal =
-          BYTES_BIG_ENDIAN ? LoadSizeInBits - LV.BitStart - LV.BitSize
-                           : LV.BitStart;
-      if (FirstBitInVal) {
-        Value *ShAmt = ConstantInt::get(LoadType, FirstBitInVal);
-        RHS = Builder.CreateShl(RHS, ShAmt);
-      }
-      // Mask out any bits in the right-hand side that shouldn't be in the result.
-      // The lower bits are zero already, so this only changes bits off the end.
-      APInt Mask = APInt::getBitsSet(LoadSizeInBits, FirstBitInVal,
-                                     FirstBitInVal + LV.BitSize);
-      if (FirstBitInVal + LV.BitSize != LoadSizeInBits)
-        RHS = Builder.CreateAnd(RHS, ConstantInt::get(Context, Mask));
-
-      // Mask out those bits in the original value that are being replaced by the
-      // right-hand side.
-      Val = Builder.CreateAnd(Val, ConstantInt::get(Context, ~Mask));
-
-      // Finally, merge the two together and store it.
-      Val = Builder.CreateOr(Val, RHS);
-      Builder.CreateAlignedStore(Val, Ptr, LV.getAlignment(), LV.Volatile);
-    }
+  // Load and store the minimum number of bytes that covers the field.
+  unsigned LoadSizeInBits = LV.BitStart + LV.BitSize;
+  LoadSizeInBits =
+      (unsigned) RoundUpToAlignment(LoadSizeInBits, BITS_PER_UNIT);
+  Type *LoadType = IntegerType::get(Context, LoadSizeInBits);
+
+  // Load the existing bits.
+  Value *Ptr = Builder.CreateBitCast(LV.Ptr, LoadType->getPointerTo());
+  Value *Val =
+      Builder.CreateAlignedLoad(Ptr, LV.getAlignment(), LV.Volatile);
+
+  // Turn RHS into a bunch of bits by storing it to a temporary then loading it
+  // out again as an integer.  The temporary needs to be big enough to hold the
+  // in-memory representation of RHS.  If the bitfield is wider than this (which
+  // only happens for non C-like languages) then any extra bits are undefined.
+  // We tell the optimizers that they are undefined by widening the temporary to
+  // at least the bitfield size but not storing anything to the extra bits.
+  unsigned MemSize = GET_MODE_BITSIZE(TYPE_MODE(type));
+  unsigned TmpSize = std::max(LoadSizeInBits, MemSize);
+  Type *TmpType = IntegerType::get(Context, TmpSize);
+
+  // Create the temporary, an integer.  Ensure it is aligned enough for both RHS
+  // and the integer version of RHS.
+  unsigned Alignment = std::max(TYPE_ALIGN(type) / 8,
+                                DL.getPrefTypeAlignment(TmpType));
+  Value *Tmp = CreateTemporary(TmpType, Alignment);
+
+  // Store the right-hand side to it.  Ensure that any extra bits turn up in the
+  // high bits of the integer loaded out below.
+  MemRef TmpLoc(Tmp, Alignment, false);
+  if (BYTES_BIG_ENDIAN && MemSize < LoadSizeInBits) {
+    unsigned BitOffset = LoadSizeInBits - MemSize;
+    assert(BitOffset % BITS_PER_UNIT == 0 && "Mode size not round?");
+    TmpLoc = DisplaceLocationByUnits(TmpLoc, BitOffset/BITS_PER_UNIT, Builder);
+  }
+  StoreRegisterToMemory(RHS, TmpLoc, type, 0, Builder);
+
+  // Load it out again as an integer.  Only the first LV.BitSize bits of this
+  // integer will be used (see the masking below).  For C-like languages, the
+  // original RHS is always an integer that is at least as wide as LV.BitSize,
+  // so the used bits are just the original integer truncated to be LV.BitSize
+  // bits wide.
+  RHS = Builder.CreateIntCast(Builder.CreateLoad(Tmp), LoadType,
+                              !TYPE_UNSIGNED(type));
+
+  // Shift the right-hand side so that its bits are in the right position.
+  unsigned FirstBitInVal =
+      BYTES_BIG_ENDIAN ? LoadSizeInBits - LV.BitStart - LV.BitSize
+                       : LV.BitStart;
+  if (FirstBitInVal) {
+    Value *ShAmt = ConstantInt::get(LoadType, FirstBitInVal);
+    RHS = Builder.CreateShl(RHS, ShAmt);
+  }
+  // Mask out any bits in the right-hand side that shouldn't be in the result.
+  // The lower bits are zero already, so this only changes bits off the end.
+  APInt Mask = APInt::getBitsSet(LoadSizeInBits, FirstBitInVal,
+                                 FirstBitInVal + LV.BitSize);
+  if (FirstBitInVal + LV.BitSize != LoadSizeInBits)
+    RHS = Builder.CreateAnd(RHS, ConstantInt::get(Context, Mask));
+
+  // Mask out those bits in the original value that are being replaced by the
+  // right-hand side.
+  Val = Builder.CreateAnd(Val, ConstantInt::get(Context, ~Mask));
+
+  // Finally, merge the two together and store it.
+  Val = Builder.CreateOr(Val, RHS);
+  Builder.CreateAlignedStore(Val, Ptr, LV.getAlignment(), LV.Volatile);
+}

Added: dragonegg/trunk/test/validator/ada/bitfield.adb
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/test/validator/ada/bitfield.adb?rev=182095&view=auto
==============================================================================
--- dragonegg/trunk/test/validator/ada/bitfield.adb (added)
+++ dragonegg/trunk/test/validator/ada/bitfield.adb Fri May 17 08:35:15 2013
@@ -0,0 +1,19 @@
+-- RUN: %dragonegg -S %s
+package body Bitfield is
+   function R (X : T) return Boolean is
+   begin
+      return X.B;
+   end;
+   function R (X : T) return Float is
+   begin
+      return X.F;
+   end;
+   procedure W (X : in out T; B : Boolean) is
+   begin
+      X.B := B;
+   end;
+   procedure W (X : in out T; F : Float) is
+   begin
+      X.F := F;
+   end;
+end;

Added: dragonegg/trunk/test/validator/ada/bitfield.ads
URL: http://llvm.org/viewvc/llvm-project/dragonegg/trunk/test/validator/ada/bitfield.ads?rev=182095&view=auto
==============================================================================
--- dragonegg/trunk/test/validator/ada/bitfield.ads (added)
+++ dragonegg/trunk/test/validator/ada/bitfield.ads Fri May 17 08:35:15 2013
@@ -0,0 +1,16 @@
+-- RUN: true
+package Bitfield is
+   -- Read and write of a non-integer scalar bitfield.
+   type T is record
+      B : Boolean;
+      F : Float;
+   end record;
+   for T use record
+     B at 0 range 1 .. 1;
+     F at 0 range 2 .. 33;
+   end record;
+   function R (X : T) return Boolean;
+   function R (X : T) return Float;
+   procedure W (X : in out T; B : Boolean);
+   procedure W (X : in out T; F : Float);
+end;





More information about the llvm-commits mailing list