gcc 4.5.2 or DragonEgg for GDC?

Jason E. Aten j.e.aten at gmail.com
Thu Mar 24 15:56:03 PDT 2011


On Thu, 24 Mar 2011 21:48:27 +0000, Iain Buclaw wrote:

> == Quote from Jason E. Aten (j.e.aten at gmail.com)'s article
>> On Thu, 24 Mar 2011 19:25:24 +0100, Andrej Mitrovic wrote:
>> > So far 4.5.2 works for me on XP. I've never tried it with DragonEgg
>> > though (first time I've heard about it too).
>> I compiled both gdc and dragonegg together cleanly, which is nice that
>> the patches they both required to gcc-4.5.2 don't conflict.  Not
>> surprisingly, the resulting gdc doesn't work right away when using the
>> dragonegg plugin. But that doesn't mean that this isn't a viable
>> approach. jaten at afarm:~/dj$ gdc
>> -fplugin=/opt/gdc-dragonegg/lib64/dragonegg.so vmacro.d
>> cc1d: /home/jaten/pkg/dragonegg28/dragonegg-2.8/llvm-types.cpp:2066:
>> const llvm::Type* TypeConverter::ConvertRECORD(tree_node*): Assertion
>> `\ 0 && "Unable to decode struct fields."' failed.
> 
> Out of curiousity, what does the struct look like?

Hmm... I'm not sure on that one. Since I don't have any D structs in my 
v2.d code (below), the struct must be either one of the structs in 
std.stdio, or an implicitly created one. Either way, it's not the only 
issue, as the smallest program still yield a compiler crash.  It's the 
packed record that is having issues--I'll attach the section of the llvm-
types.cpp code where the assert is firing.

jaten at afarm:~/dj$ cat simple.d
import std.stdio; int main() {return 0;}

$ gdc -fplugin=/opt/gdc-dragonegg/lib64/dragonegg.so simple.d
cc1d: /home/jaten/pkg/dragonegg28/dragonegg-2.8/llvm-backend.cpp:1013: 
void emit_global(tree_node*): Assertion `(((((decl)->decl_common.initi\
al))->base.constant_flag) || ((enum tree_code) (((decl)-
>decl_common.initial))->base.code) == STRING_CST) && "Global initializer 
should be constant!"' failed.


jaten at afarm:~/dj$ cat v2.d
import std.stdio;
void main() {
     void v(string s)() { writefln("view: %s => %s:%s\n", s, typeid(mixin
(s)), mixin(s)); } // use: v!"varname"
     auto x1=1.;
     v!"x1";
}
jaten at afarm:~/dj$ gdc -fplugin=/opt/gdc-dragonegg/lib64/dragonegg.so v2.d
cc1d: /home/jaten/pkg/dragonegg28/dragonegg-2.8/llvm-types.cpp:2066: 
const llvm::Type* TypeConverter::ConvertRECORD(tree_node*): Assertion `0\
 && "Unable to decode struct fields."' failed.


jaten at afarm:~/dj$ cat s1.d
void main() {}
jaten at afarm:~/dj$ gdc -fplugin=/opt/gdc-dragonegg/lib64/dragonegg.so s1.d
cc1d: /home/jaten/pkg/dragonegg28/dragonegg-2.8/llvm-backend.cpp:1013: 
void emit_global(tree_node*): Assertion `(((((decl)-
>decl_common.initial))->base.constant_flag) || ((enum tree_code) (((decl)-
>decl_common.initial))->base.code) == STRING_CST) && "Global initializer 
should be constant!"' failed.


where the assert is firing: (scroll to the <<<<<< at the bottom)

# This listing starts at line 1984 of dragonegg-2.8/llvm-types.cpp
/// ConvertRECORD - Convert a RECORD_TYPE, UNION_TYPE or QUAL_UNION_TYPE 
to
/// an LLVM type.
// A note on C++ virtual base class layout.  Consider the following 
example:
// class A { public: int i0; };
// class B : public virtual A { public: int i1; };
// class C : public virtual A { public: int i2; };
// class D : public virtual B, public virtual C { public: int i3; };
//
// The TYPE nodes gcc builds for classes represent that class as it looks
// standing alone.  Thus B is size 12 and looks like { vptr; i2; baseclass 
A; }
// However, this is not the layout used when that class is a base class 
for
// some other class, yet the same TYPE node is still used.  D in the 
above has
// both a BINFO list entry and a FIELD that reference type B, but the 
virtual
// base class A within B is not allocated in that case; B-within-D is only
// size 8.  The correct size is in the FIELD node (does not match the size
// in its child TYPE node.)  The fields to be omitted from the child TYPE,
// as far as I can tell, are always the last ones; but also, there is a
// TYPE_DECL node sitting in the middle of the FIELD list separating 
virtual
// base classes from everything else.
//
// Similarly, a nonvirtual base class which has virtual base classes might
// not contain those virtual base classes when used as a nonvirtual base 
class.
// There is seemingly no way to detect this except for the size 
differential.
//
// For LLVM purposes, we build a new type for B-within-D that
// has the correct size and layout for that usage.

const Type *TypeConverter::ConvertRECORD(tree type) {
  if (const Type *Ty = GET_TYPE_LLVM(type)) {
    // If we already compiled this type, and if it was not a forward
    // definition that is now defined, use the old type.
    if (!Ty->isOpaqueTy() || TYPE_SIZE(type) == 0)
      return Ty;
  }

  if (TYPE_SIZE(type) == 0) {   // Forward declaration?
    const Type *Ty = OpaqueType::get(Context);
    return TypeDB.setType(type, Ty);
  }

  // Note that we are compiling a struct now.
  bool OldConvertingStruct = ConvertingStruct;
  ConvertingStruct = true;

  // Record those fields which will be converted to LLVM fields.
  SmallVector<std::pair<tree, uint64_t>, 32> Fields;
  for (tree Field = TYPE_FIELDS(type); Field; Field = TREE_CHAIN(Field))
    if (TREE_CODE(Field) == FIELD_DECL && OffsetIsLLVMCompatible(Field))
      Fields.push_back(std::make_pair(Field, getFieldOffsetInBits
(Field)));

  // The fields are almost always sorted, but occasionally not.  Sort 
them by
  // field offset.
  for (unsigned i = 1, e = Fields.size(); i < e; i++)
    for (unsigned j = i; j && Fields[j].second < Fields[j-1].second; j--)
      std::swap(Fields[j], Fields[j-1]);

  StructTypeConversionInfo *Info =
    new StructTypeConversionInfo(*TheTarget, TYPE_ALIGN(type) / 8,
                                 TYPE_PACKED(type));

  // Convert over all of the elements of the struct.
  // Workaround to get Fortran EQUIVALENCE working.
  // TODO: Unify record and union logic and handle this optimally.
  bool HasOnlyZeroOffsets = TREE_CODE(type) != RECORD_TYPE &&
    UnionHasOnlyZeroOffsets(type);
  if (HasOnlyZeroOffsets) {
    SelectUnionMember(type, *Info);
  } else {
    // Convert over all of the elements of the struct.
    bool retryAsPackedStruct = false;
    for (unsigned i = 0, e = Fields.size(); i < e; i++)
      if (DecodeStructFields(Fields[i].first, *Info) == false) {
        retryAsPackedStruct = true;
        break;
      }

    if (retryAsPackedStruct) {
      delete Info;
      Info = new StructTypeConversionInfo(*TheTarget, TYPE_ALIGN(type) / 
8,
                                          true);
      for (unsigned i = 0, e = Fields.size(); i < e; i++)
        if (DecodeStructFields(Fields[i].first, *Info) == false) {
          assert(0 && "Unable to decode struct fields."); // <<<<<< this 
assert is firing, at line 2066 of dragonegg-2.8/llvm-types.cpp
        }
    }
  }


More information about the D.gnu mailing list