[pkg-d-commits] [ldc] 109/211: Use the regular LL type for all init symbols and most globals

Matthias Klumpp mak at moszumanska.debian.org
Sun Apr 23 22:36:14 UTC 2017


This is an automated email from the git hooks/post-receive script.

mak pushed a commit to annotated tag v1.1.0
in repository ldc.

commit ab1432ed06ca08f549bf3e3ea31adea8c2ac9e3f
Author: Martin <noone at nowhere.com>
Date:   Sat Oct 22 20:00:15 2016 +0200

    Use the regular LL type for all init symbols and most globals
    
    There's no <Type>_init type for aggregates (structs and classes) anymore,
    effectively eliminating a *lot* of named LLVM types, some bitcasts as well
    as replacements of globals etc.
    
    To get there, it was even required to use the regular type for compatible
    literals too, otherwise structs embedded as fields in other aggregates had
    an anonymous type (well, the LLVM constant for the field initializer had)
    and so the container initializer wasn't compatible with the regular type
    anymore.
    
    What was also necessary was a fix wrt. static arrays of bools (LLVM
    constant of type `[N x i1]` vs. `[N x i8]` for regular type).
    I also had to change the initializer for `char[2][3] x = 0xff` from
    `[6 x i8]` to `[3 x [2 x i8]]`, i.e., NOT flattening multi-dimensional
    inits from a scalar.
    
    So only literals with overlapping (union) fields and an explicit
    initializer initializing dominated non-alias union fields should still
    have a mismatching anonymous type - i.e., very, very few cases.
---
 gen/arrays.cpp                     |  3 ++
 gen/llvmhelpers.cpp                | 74 +++++++++++++++++++++++++-------------
 ir/iraggr.cpp                      | 58 ++++++++++++++++++------------
 ir/iraggr.h                        | 20 +++++------
 tests/codegen/align.d              |  4 +--
 tests/codegen/const_struct.d       |  4 +--
 tests/codegen/in_place_construct.d |  4 +--
 tests/codegen/union.d              | 58 ++++++++++++++++++++++++++++++
 8 files changed, 159 insertions(+), 66 deletions(-)

diff --git a/gen/arrays.cpp b/gen/arrays.cpp
index 476f79f..d154144 100644
--- a/gen/arrays.cpp
+++ b/gen/arrays.cpp
@@ -544,6 +544,9 @@ llvm::Constant *arrayLiteralToConst(IRState *p, ArrayLiteralExp *ale) {
   vals.reserve(ale->elements->dim);
   for (unsigned i = 0; i < ale->elements->dim; ++i) {
     llvm::Constant *val = toConstElem(indexArrayLiteral(ale, i), p);
+    // extend i1 to i8
+    if (val->getType() == LLType::getInt1Ty(p->context()))
+      val = llvm::ConstantExpr::getZExt(val, LLType::getInt8Ty(p->context()));
     if (!elementType) {
       elementType = val->getType();
     } else {
diff --git a/gen/llvmhelpers.cpp b/gen/llvmhelpers.cpp
index 1e0b0a0..20e7f92 100644
--- a/gen/llvmhelpers.cpp
+++ b/gen/llvmhelpers.cpp
@@ -1099,48 +1099,73 @@ LLConstant *DtoConstExpInit(Loc &loc, Type *targetType, Expression *exp) {
   LOG_SCOPE
 
   LLConstant *val = toConstElem(exp, gIR);
+  Type *baseValType = exp->type->toBasetype();
+  Type *baseTargetType = targetType->toBasetype();
 
   // The situation here is a bit tricky: In an ideal world, we would always
   // have val->getType() == DtoType(targetType). But there are two reasons
   // why this is not true. One is that the LLVM type system cannot represent
   // all the C types, leading to differences in types being necessary e.g. for
   // union initializers. The second is that the frontend actually does not
-  // explicitly lowers things like initializing an array/vector with a scalar
+  // explicitly lower things like initializing an array/vector with a scalar
   // constant, or since 2.061 sometimes does not get implicit conversions for
   // integers right. However, we cannot just rely on the actual Types being
   // equal if there are no rewrites to do because of – as usual – AST
   // inconsistency bugs.
 
-  Type *expBase = stripModifiers(exp->type->toBasetype())->merge();
-  Type *targetBase = stripModifiers(targetType->toBasetype())->merge();
+  LLType *llType = val->getType();
+  LLType *targetLLType = DtoMemType(baseTargetType);
 
-  if (expBase->equals(targetBase) && targetBase->ty != Tbool) {
-    return val;
-  }
+  // shortcut for zeros
+  if (val->isNullValue())
+    return llvm::Constant::getNullValue(targetLLType);
 
-  llvm::Type *llType = val->getType();
-  llvm::Type *targetLLType = DtoMemType(targetBase);
-  if (llType == targetLLType) {
-    Logger::println("Matching LLVM types, ignoring frontend glitch.");
+  if (llType == targetLLType)
     return val;
+
+  // extend i1 to i8
+  if (llType == LLType::getInt1Ty(gIR->context())) {
+    llType = LLType::getInt8Ty(gIR->context());
+    val = llvm::ConstantExpr::getZExt(val, llType);
+
+    if (llType == targetLLType)
+      return val;
   }
 
-  if (targetBase->ty == Tsarray) {
-    Logger::println("Building constant array initializer to single value.");
+  if (baseTargetType->ty == Tsarray) {
+    Logger::println("Building constant array initializer from scalar.");
 
-    assert(expBase->size() > 0);
-    d_uns64 elemCount = targetBase->size() / expBase->size();
-    assert(targetBase->size() % expBase->size() == 0);
+    assert(baseValType->size() > 0);
+    const auto numTotalVals = baseTargetType->size() / baseValType->size();
+    assert(baseTargetType->size() % baseValType->size() == 0);
 
-    std::vector<llvm::Constant *> initVals(elemCount, val);
-    return llvm::ConstantArray::get(llvm::ArrayType::get(llType, elemCount),
-                                    initVals);
+    // may be a multi-dimensional array init, e.g., `char[2][3] x = 0xff`
+    baseValType = stripModifiers(baseValType);
+    LLSmallVector<size_t, 4> dims; // { 3, 2 }
+    for (auto t = baseTargetType; t->ty == Tsarray;) {
+      dims.push_back(static_cast<TypeSArray *>(t)->dim->toUInteger());
+      auto elementType = stripModifiers(t->nextOf()->toBasetype());
+      if (elementType->equals(baseValType))
+        break;
+      t = elementType;
+    }
+
+    size_t product = 1;
+    for (size_t i = dims.size(); i--;) {
+      product *= dims[i];
+      auto at = llvm::ArrayType::get(val->getType(), dims[i]);
+      LLSmallVector<llvm::Constant *, 16> elements(dims[i], val);
+      val = llvm::ConstantArray::get(at, elements);
+    }
+
+    assert(product == numTotalVals);
+    return val;
   }
 
-  if (targetBase->ty == Tvector) {
-    Logger::println("Building vector initializer from scalar.");
+  if (baseTargetType->ty == Tvector) {
+    Logger::println("Building constant vector initializer from scalar.");
 
-    TypeVector *tv = static_cast<TypeVector *>(targetBase);
+    TypeVector *tv = static_cast<TypeVector *>(baseTargetType);
     assert(tv->basetype->ty == Tsarray);
     dinteger_t elemCount =
         static_cast<TypeSArray *>(tv->basetype)->dim->toInteger();
@@ -1154,10 +1179,9 @@ LLConstant *DtoConstExpInit(Loc &loc, Type *targetType, Expression *exp) {
     llvm::IntegerType *source = llvm::cast<llvm::IntegerType>(llType);
     llvm::IntegerType *target = llvm::cast<llvm::IntegerType>(targetLLType);
 
-    assert(
-        target->getBitWidth() > source->getBitWidth() &&
-        "On initializer "
-        "integer type mismatch, the target should be wider than the source.");
+    assert(target->getBitWidth() > source->getBitWidth() &&
+           "On initializer integer type mismatch, the target should be wider "
+           "than the source.");
     return llvm::ConstantExpr::getZExtOrBitCast(val, target);
   }
 
diff --git a/ir/iraggr.cpp b/ir/iraggr.cpp
index 90d194b..f4bd903 100644
--- a/ir/iraggr.cpp
+++ b/ir/iraggr.cpp
@@ -26,11 +26,18 @@
 
 //////////////////////////////////////////////////////////////////////////////
 
-IrAggr::IrAggr(AggregateDeclaration *aggr)
-    : aggrdecl(aggr), type(aggr->type),
-      // above still need to be looked at
-      init_type(LLStructType::create(
-          gIR->context(), std::string(aggr->toPrettyChars()) + "_init")) {}
+llvm::StructType *IrAggr::getLLStructType() {
+  if (llStructType)
+    return llStructType;
+
+  LLType *llType = DtoType(type);
+  if (auto irClassType = type->ctype->isClass())
+    llType = irClassType->getMemoryLLType();
+
+  llStructType = llvm::dyn_cast<LLStructType>(llType);
+
+  return llStructType;
+}
 
 //////////////////////////////////////////////////////////////////////////////
 
@@ -43,7 +50,7 @@ LLGlobalVariable *IrAggr::getInitSymbol() {
   auto initname = getMangledInitSymbolName(aggrdecl);
 
   init =
-      getOrCreateGlobal(aggrdecl->loc, gIR->module, init_type, true,
+      getOrCreateGlobal(aggrdecl->loc, gIR->module, getLLStructType(), true,
                         llvm::GlobalValue::ExternalLinkage, nullptr, initname);
 
   // set alignment
@@ -63,9 +70,8 @@ llvm::Constant *IrAggr::getDefaultInit() {
                          aggrdecl->toPrettyChars());
   LOG_SCOPE;
 
-  DtoType(type);
   VarInitMap noExplicitInitializers;
-  constInit = createInitializerConstant(noExplicitInitializers, init_type);
+  constInit = createInitializerConstant(noExplicitInitializers);
   return constInit;
 }
 
@@ -134,8 +140,7 @@ static llvm::Constant *FillSArrayDims(Type *arrTypeD, llvm::Constant *init) {
 }
 
 llvm::Constant *
-IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers,
-                                  llvm::StructType *initializerType) {
+IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers) {
   IF_LOG Logger::println("Creating initializer constant for %s",
                          aggrdecl->toChars());
   LOG_SCOPE;
@@ -167,23 +172,30 @@ IrAggr::createInitializerConstant(const VarInitMap &explicitInitializers,
   if (offset < structsize)
     add_zeros(constants, offset, structsize);
 
-  // get initializer type
-  if (!initializerType || initializerType->isOpaque()) {
-    llvm::SmallVector<llvm::Type *, 16> types;
-    types.reserve(constants.size());
-    for (auto c : constants) {
-      types.push_back(c->getType());
-    }
-    if (!initializerType) {
-      initializerType = LLStructType::get(gIR->context(), types, isPacked());
-    } else {
-      initializerType->setBody(types, isPacked());
+  assert(!constants.empty());
+
+  // get LL field types
+  llvm::SmallVector<llvm::Type *, 16> types;
+  types.reserve(constants.size());
+  for (auto c : constants)
+    types.push_back(c->getType());
+
+  auto llStructType = getLLStructType();
+  bool isCompatible = (types.size() == llStructType->getNumElements());
+  if (isCompatible) {
+    for (size_t i = 0; i < types.size(); i++) {
+      if (types[i] != llStructType->getElementType(i)) {
+        isCompatible = false;
+        break;
+      }
     }
   }
 
   // build constant
-  assert(!constants.empty());
-  llvm::Constant *c = LLConstantStruct::get(initializerType, constants);
+  LLStructType *llType =
+      isCompatible ? llStructType
+                   : LLStructType::get(gIR->context(), types, isPacked());
+  llvm::Constant *c = LLConstantStruct::get(llType, constants);
   IF_LOG Logger::cout() << "final initializer: " << *c << std::endl;
   return c;
 }
diff --git a/ir/iraggr.h b/ir/iraggr.h
index ea93e35..cc15fd0 100644
--- a/ir/iraggr.h
+++ b/ir/iraggr.h
@@ -33,7 +33,8 @@ class StructType;
 // it is used during codegen to hold all the vital info we need
 struct IrAggr {
   /// Constructor.
-  explicit IrAggr(AggregateDeclaration *agg);
+  explicit IrAggr(AggregateDeclaration *aggr)
+      : aggrdecl(aggr), type(aggr->type) {}
 
   //////////////////////////////////////////////////////////////////////////
   // public fields,
@@ -78,24 +79,16 @@ struct IrAggr {
   /// fields set to the provided constants. The remaining space (not
   /// explicitly specified fields, padding) is default-initialized.
   ///
-  /// The optional initializerType parmeter can be used to specify the exact
-  /// LLVM type to use for the initializer. If non-null and non-opaque, the
-  /// type must exactly match the generated constant. This parameter is used
-  /// mainly for supporting legacy code.
-  ///
   /// Note that in the general case (if e.g. unions are involved), the
   /// returned type is not necessarily the same as getLLType().
   llvm::Constant *
-  createInitializerConstant(const VarInitMap &explicitInitializers,
-                            llvm::StructType *initializerType = nullptr);
+  createInitializerConstant(const VarInitMap &explicitInitializers);
 
 protected:
   /// Static default initializer global.
   llvm::GlobalVariable *init = nullptr;
   /// Static default initializer constant.
   llvm::Constant *constInit = nullptr;
-  /// Static default initialier type.
-  llvm::StructType *init_type = nullptr;
 
   /// Vtbl global.
   llvm::GlobalVariable *vtbl = nullptr;
@@ -107,7 +100,8 @@ protected:
   /// ClassInfo initializer constant.
   llvm::Constant *constClassInfo = nullptr;
 
-  using ClassGlobalMap = std::map<std::pair<ClassDeclaration *, size_t>, llvm::GlobalVariable *>;
+  using ClassGlobalMap =
+      std::map<std::pair<ClassDeclaration *, size_t>, llvm::GlobalVariable *>;
 
   /// Map from pairs of <interface vtbl,index> to global variable, implemented
   /// by this class. The same interface can appear multiple times, so index is
@@ -144,6 +138,10 @@ protected:
   bool isPacked() const;
 
 private:
+  llvm::StructType *llStructType = nullptr;
+
+  llvm::StructType *getLLStructType();
+
   /// Recursively adds all the initializers for the given aggregate and, in
   /// case of a class type, all its base classes.
   void addFieldInitializers(llvm::SmallVectorImpl<llvm::Constant *> &constants,
diff --git a/tests/codegen/align.d b/tests/codegen/align.d
index 6a809a1..c309505 100644
--- a/tests/codegen/align.d
+++ b/tests/codegen/align.d
@@ -9,10 +9,10 @@ struct Inner { align(32) int a; }
 align(1) ubyte globalByte1;
 // CHECK-DAG: align11globalByte1h = {{.*}} align 1
 static Outer globalOuter;
-// CHECK-DAG: constant %align.Outer_init zeroinitializer{{(, comdat)?}}, align 32
+// CHECK-DAG: constant %align.Outer zeroinitializer{{(, comdat)?}}, align 32
 // CHECK-DAG: align11globalOuterS5align5Outer = {{.*}} align 32
 static Inner globalInner;
-// CHECK-DAG: constant %align.Inner_init zeroinitializer{{(, comdat)?}}, align 32
+// CHECK-DAG: constant %align.Inner zeroinitializer{{(, comdat)?}}, align 32
 // CHECK-DAG: align11globalInnerS5align5Inner = {{.*}} align 32
 
 Outer passAndReturnOuterByVal(Outer arg) { return arg; }
diff --git a/tests/codegen/const_struct.d b/tests/codegen/const_struct.d
index cf23628..7d310b4 100644
--- a/tests/codegen/const_struct.d
+++ b/tests/codegen/const_struct.d
@@ -16,9 +16,9 @@ void testNested() {
   assert(x == 3);
 }
 
-// CHECK: @.immutablearray = internal constant [1 x { [3 x { { i32 } }] }] [{ [3 x { { i32 } }] } { [3 x { { i32 } }] [{ { i32 } } { { i32 } { i32 42 } }, { { i32 } } { { i32 } { i32 43 } }, { { i32 } } { { i32 } { i32 44 } }] }] ; [#uses = 1]
+// CHECK: @.immutablearray = internal constant [1 x %const_struct.S2] [%const_struct.S2 { [3 x %const_struct.S1] [%const_struct.S1 { %const_struct.S0 { i32 42 } }, %const_struct.S1 { %const_struct.S0 { i32 43 } }, %const_struct.S1 { %const_struct.S0 { i32 44 } }] }] ;
 void main () {
-    // CHECK: store %const_struct.S2* bitcast ([1 x { [3 x { { i32 } }] }]* @.immutablearray to %const_struct.S2*), %const_struct.S2** %2
+    // CHECK: store %const_struct.S2* getelementptr inbounds ({{.*}}[1 x %const_struct.S2]* @.immutablearray, i32 0, i32 0), %const_struct.S2** %2
     immutable S2[] xyz = [ { [ { { 42 } }, { { 43 } }, { { 44 } } ] } ];
     // CHECK: %.gc_mem = call {{{.*}}} @_d_newarrayU(%object.TypeInfo* bitcast (%"typeid(immutable(C0[]))"* @{{.*}} to %object.TypeInfo*), i{{32|64}} 3)
     immutable C0[] zyx = [ { new int(42) }, { null }, { null } ];
diff --git a/tests/codegen/in_place_construct.d b/tests/codegen/in_place_construct.d
index 23fb944..d2ccb97 100644
--- a/tests/codegen/in_place_construct.d
+++ b/tests/codegen/in_place_construct.d
@@ -108,9 +108,7 @@ struct Container { S s; }
 void hierarchyOfLiterals()
 {
     // CHECK: %sa = alloca [1 x %in_place_construct.Container]
-    // CHECK: %1 = bitcast [1 x %in_place_construct.Container]* %sa to [1 x { { i64, i64, i64, i64 } }]*
-    // CHECK: store [{{.*}}]* %1
-    // CHECK: ret void
+    // CHECK: store [1 x %in_place_construct.Container] [%in_place_construct.Container { %in_place_construct.S { i64 11, i64 12, i64 13, i64 14 } }], [1 x %in_place_construct.Container]* %sa
     Container[1] sa = [ Container(S(11, 12, 13, 14)) ];
 }
 
diff --git a/tests/codegen/union.d b/tests/codegen/union.d
new file mode 100644
index 0000000..484d7b8
--- /dev/null
+++ b/tests/codegen/union.d
@@ -0,0 +1,58 @@
+// Tests LL types and constant initializers of init symbols and globals of
+// structs with and without overlapping (union) fields.
+
+// RUN: %ldc -c -output-ll -of=%t.ll %s && FileCheck %s < %t.ll
+
+struct S
+{
+    char c;              // default initializer: 0xff
+    uint ui;
+    bool[2] bools;       // make sure the 2 bools are extended to 2 bytes
+    char[2][4] multidim; // multidimensional init based on a single 0xff char
+}
+// CHECK-DAG: %union.S                     = type { i8, [3 x i8], i32, [2 x i8], [4 x [2 x i8]], [2 x i8] }
+// CHECK-DAG: @_D5union1S6__initZ          = constant %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }
+
+// CHECK-DAG: @_D5union8defaultSS5union1S  = global   %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }
+__gshared S defaultS;
+
+// CHECK-DAG: @_D5union9explicitSS5union1S = global   %union.S { i8 3, [3 x i8] zeroinitializer, i32 56, [2 x i8] c"\00\01", [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }
+__gshared S explicitS = S(3, 56, [false, true] /* implicit multidim */);
+
+
+struct SWithUnion
+{
+    char c;
+    S nested;
+
+    union
+    {
+        struct { ubyte ub = 6; ushort us = 33; ulong ul_dummy = void; }
+        struct { uint ui1; uint ui2 = 84; ulong ul = 666; }
+        ubyte ub_direct;
+    }
+
+    this(ubyte ub)
+    {
+        this.ub_direct = ub; // ub_direct is an alias for dominant ub
+    }
+
+    this(uint ui1, uint ui2)
+    {
+        this.ui1 = ui1; // dominated by ub and us
+        this.ui2 = ui2;
+    }
+}
+// CHECK-DAG: %union.SWithUnion                                            = type { i8, [3 x i8], %union.S, i8, [1 x i8], i16, i32, i64 }
+// CHECK-DAG: @_D5union10SWithUnion6__initZ                                = constant %union.SWithUnion { i8 -1, [3 x i8] zeroinitializer, %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }, i8 6, [1 x i8] zeroinitializer, i16 33, i32 84, i64 666 }
+
+// CHECK-DAG: @_D5union17defaultSWithUnionS5union10SWithUnion              = global   %union.SWithUnion { i8 -1, [3 x i8] zeroinitializer, %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }, i8 6, [1 x i8] zeroinitializer, i16 33, i32 84, i64 666 }
+__gshared SWithUnion defaultSWithUnion;
+
+// CHECK-DAG: @_D5union28explicitCompatibleSWithUnionS5union10SWithUnion   = global   %union.SWithUnion { i8 -1, [3 x i8] zeroinitializer, %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }, i8 53, [1 x i8] zeroinitializer, i16 33, i32 84, i64 666 }
+__gshared SWithUnion explicitCompatibleSWithUnion = SWithUnion(53);
+
+// When using the 2nd constructor, a dominated union field (ui1) is initialized.
+// The regular LL type can thus not be used, an anonymous one is used instead.
+// CHECK-DAG: @_D5union30explicitIncompatibleSWithUnionS5union10SWithUnion = global   { i8, [3 x i8], %union.S, i32, i32, i64 } { i8 -1, [3 x i8] zeroinitializer, %union.S { i8 -1, [3 x i8] zeroinitializer, i32 0, [2 x i8] zeroinitializer, [4 x [2 x i8]] {{\[}}[2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF", [2 x i8] c"\FF\FF"], [2 x i8] zeroinitializer }, i32 23, i32 256, i64 666 }
+__gshared SWithUnion explicitIncompatibleSWithUnion = SWithUnion(23, 256);

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-d/ldc.git



More information about the pkg-d-commits mailing list