I'd like to be able to make use of a structure type and its fields before it is completely defined. To be specific, let me ask detailed questions at various stages in the construction of a recursive type. I copy from http://llvm.org/docs/ProgrammersManual.html#TypeResolve // Create the initial outer struct PATypeHolder StructTy = OpaqueType::get(); Is it possible to declare variables of type StructTy at this point? Is it possible to define other structured types that have fields of type StructTy at this point? I'm guessing the answers to these questions are "Yes". std::vector<const Type*> Elts; Elts.push_back(PointerType::get(StructTy)); Is it possible to build an expression that uses the newly generated Elt as field-selector at this point? I'm hoping yes, but I suspect No, because the elments of Elts* are clearly Type* instead of being a field. In particular, if I use the same type twice to make two fields, the corresponding elements of Elts will be indistinguishable. Elts.push_back(Type::Int32Ty); StructType *NewSTy = StructType::get(Elts); Presumably at this point is is definitely possible to declare variables of type NewsTy and use field-selectors from NewSTy. But it's a little too late for my purposes. The types I'm dealing with are not recursive, but of course I'll have to perform the rest of the steps so that the variables I declared long ago finally get well-defined types. // At this point, NewSTy = "{ opaque*, i32 }". Tell VMCore that // the struct and the opaque type are actually the same. cast<OpaqueType>(StructTy.get())->refineAbstractTypeTo(NewSTy); // NewSTy is potentially invalidated, but StructTy (a PATypeHolder) is // kept up-to-date NewSTy = cast<StructType>(StructTy.get()); // Add a name for the type to the module symbol table (optional) MyModule->addTypeName("mylist", NewSTy); If the answers to my questions are "yes", I can generate code easily for all the variations on the source language I'm compiling. If any are "no" I'll be significantly constrained in what I'll be able to do easily (i.e., without extra code generation passes and intermediate data structures). -- hendrik
On Fri, Sep 12, 2008 at 9:35 AM, Hendrik Boom <hendrik at topoi.pooq.com> wrote:> I'd like to be able to make use of a structure type and its fields before > it is completely defined. To be specific, let me ask detailed questions > at various stages in the construction of a recursive type. I copy from > > http://llvm.org/docs/ProgrammersManual.html#TypeResolve > > // Create the initial outer struct > PATypeHolder StructTy = OpaqueType::get(); > > Is it possible to declare variables of type StructTy at this point?I think you can, although you have to be careful; if you don't make sure the variable eventually has a computable size, the module won't be valid. Declaring variables of type pointer to StructTy is completely safe.> std::vector<const Type*> Elts; > Elts.push_back(PointerType::get(StructTy)); > > Is it possible to build an expression that uses the newly generated Elt > as field-selector at this point? I'm hoping yes, but I suspect No, > because the elments of Elts* are clearly Type* instead of being a field. > In particular, if I use the same type twice to make two fields, the > corresponding elements of Elts will be indistinguishable.I'm not following; are you trying to access the first member of NewSTy here? You can't use a type that hasn't been created yet. You might be able to pull some tricks with incomplete types or casts, though. http://llvm.org/docs/LangRef.html#i_getelementptr and http://llvm.org/docs/GetElementPtr.html might be useful here.> Elts.push_back(Type::Int32Ty); > StructType *NewSTy = StructType::get(Elts); > > Presumably at this point is is definitely possible to declare variables > of type NewsTy and use field-selectors from NewSTy. But it's a little > too late for my purposes.Basically, the rule for opaque types is that in a valid module, you can do anything you could do with a declaration like "struct S;" in C. And in a module under construction, I'm pretty sure you can pull some more tricks, like declaring variables with types of unknown size, or accessing structs with members of unknown size. -Eli
On Fri, 12 Sep 2008 11:06:30 -0700, Eli Friedman wrote:> On Fri, Sep 12, 2008 at 9:35 AM, Hendrik Boom <hendrik at topoi.pooq.com> > wrote: >> I'd like to be able to make use of a structure type and its fields >> before it is completely defined. To be specific, let me ask detailed >> questions at various stages in the construction of a recursive type. I >> copy from >> >> http://llvm.org/docs/ProgrammersManual.html#TypeResolve >> >> // Create the initial outer struct >> PATypeHolder StructTy = OpaqueType::get(); >> >> Is it possible to declare variables of type StructTy at this point? > > I think you can, although you have to be careful; if you don't make sure > the variable eventually has a computable size, the module won't be > valid.Of course, eventually they type will ba fully defined.> > Declaring variables of type pointer to StructTy is completely safe. > >> std::vector<const Type*> Elts; >> Elts.push_back(PointerType::get(StructTy)); >> >> Is it possible to build an expression that uses the newly generated Elt >> as field-selector at this point? I'm hoping yes, but I suspect No, >> because the elments of Elts* are clearly Type* instead of being a >> field. In particular, if I use the same type twice to make two fields, >> the corresponding elements of Elts will be indistinguishable. > > I'm not following; are you trying to access the first member of NewSTy > here? You can't use a type that hasn't been created yet. You might be > able to pull some tricks with incomplete types or casts, though.What I want is to be able to use the fields that have already been defined, even though the type isn't complete yet. The vector<const Type*> is all I have at that moment, and it isn't a type. But by the time I have a type it's frozen and I can't add new fields to it. Do I gather that I keep making new types, each slightly larger than the previous ones, cast each pointer to my growing type to the type-of-the- moment, and field-select from it; then finally complete the type when all is known? That might just work, if field-allocation is independent of later fields, but it is ugly. The trouble is that llvm won't believe in fields until the structure is complete, and then it believes in all of them. While that's fine for semantics of the completed module, it makes less sense while the module is under construction. I view type-declaration syntax as being syntax, and I'd like it to be as flexible and modifiable as syntax anywhere else in the parse tree. The time to interpret type declarations as actually defining specific types with known semantics is after the syntax has been constructed, not before. If it's possible to do some of it statically during parse tree construction, that's fine, but it shouldn't be *required*. But it's evidently not the way llvm thinks.> > http://llvm.org/docs/LangRef.html#i_getelementptr and > http://llvm.org/docs/GetElementPtr.html might be useful here.These operations also require a completed tyle.> >> Elts.push_back(Type::Int32Ty); >> StructType *NewSTy = StructType::get(Elts); >> >> Presumably at this point is is definitely possible to declare variables >> of type NewsTy and use field-selectors from NewSTy. But it's a little >> too late for my purposes. > > Basically, the rule for opaque types is that in a valid module, you can > do anything you could do with a declaration like "struct S;" in C.Which is, basically, nothing but point to it and statically know that it's the same or different from (possibly) other types.> And in a module under construction, I'm pretty sure you can pull some > more tricks, like declaring variables with types of unknown size, or > accessing structs with members of unknown size.But not their fields, because llvm doesn't believe in fields of a structure until it has them all. If the elements of Elts were fields of a yet-to-be-identified structure, I'd be able to use them; it would make sense then to use field explicitly in the getelementptr istruction instead of the integers which have to be indexed into a type to obtain them.> > -Eli