From fdfeb6976f07ad10d809b922ed7376ba2a3539be Mon Sep 17 00:00:00 2001 From: Chris Lattner Date: Fri, 12 Feb 2010 20:49:41 +0000 Subject: [PATCH] Add support for a union type in LLVM IR. Patch by Talin! git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@96011 91177308-0d34-0410-b5e6-96231b3b80d8 --- docs/LangRef.html | 141 +++++++++++++++++++------ include/llvm-c/Core.h | 10 +- include/llvm/Bitcode/LLVMBitCodes.h | 3 +- include/llvm/Constants.h | 45 ++++++++ include/llvm/DerivedTypes.h | 61 ++++++++++- include/llvm/Type.h | 14 +-- include/llvm/Value.h | 1 + lib/AsmParser/LLLexer.cpp | 1 + lib/AsmParser/LLParser.cpp | 80 ++++++++++++-- lib/AsmParser/LLParser.h | 4 + lib/AsmParser/LLToken.h | 1 + lib/Bitcode/Reader/BitcodeReader.cpp | 7 ++ lib/Bitcode/Writer/BitcodeWriter.cpp | 21 +++- lib/Target/X86/X86InstrInfo.td | 2 +- lib/VMCore/AsmWriter.cpp | 13 +++ lib/VMCore/ConstantFold.cpp | 6 ++ lib/VMCore/Constants.cpp | 33 ++++++ lib/VMCore/ConstantsContext.h | 15 +++ lib/VMCore/Core.cpp | 31 ++++++ lib/VMCore/LLVMContextImpl.h | 5 + lib/VMCore/Type.cpp | 136 ++++++++++++++++++++++-- lib/VMCore/TypesContext.h | 26 +++++ test/Assembler/2010-01-06-UnionType.ll | 3 + test/Feature/unions.ll | 12 +++ 24 files changed, 612 insertions(+), 59 deletions(-) create mode 100644 test/Assembler/2010-01-06-UnionType.ll create mode 100644 test/Feature/unions.ll diff --git a/docs/LangRef.html b/docs/LangRef.html index 9590609a872..b337b6a8571 100644 --- a/docs/LangRef.html +++ b/docs/LangRef.html @@ -66,12 +66,17 @@
  • Derived Types
      -
    1. Array Type
    2. +
    3. Aggregate Types +
        +
      1. Array Type
      2. +
      3. Structure Type
      4. +
      5. Packed Structure Type
      6. +
      7. Union Type
      8. +
      9. Vector Type
      10. +
      +
    4. Function Type
    5. Pointer Type
    6. -
    7. Structure Type
    8. -
    9. Packed Structure Type
    10. -
    11. Vector Type
    12. Opaque Type
  • @@ -1404,6 +1409,7 @@ Classifications pointer, vector, structure, + union, array, label, metadata. @@ -1418,12 +1424,12 @@ Classifications derived - integer, - array, + array, function, pointer, structure, packed structure, + union, vector, opaque. @@ -1561,6 +1567,21 @@ Classifications possible to have a two dimensional array, using an array as the element type of another array.

    + + + + +
    Aggregate Types
    + +
    + +

    Aggregate Types are a subset of derived types that can contain multiple + member types. Arrays, + structs, vectors and + unions are aggregate types.

    + +
    + @@ -1629,9 +1650,9 @@ Classifications
    Overview:

    The function type can be thought of as a function signature. It consists of a return type and a list of formal parameter types. The return type of a - function type is a scalar type, a void type, or a struct type. If the return - type is a struct type then all struct elements must be of first class types, - and the struct must have at least one element.

    + function type is a scalar type, a void type, a struct type, or a union + type. If the return type is a struct type then all struct elements must be + of first class types, and the struct must have at least one element.

    Syntax:
    @@ -1753,6 +1774,53 @@ Classifications 
     
     
     
    +
    +
    +
    +
    + +
    Overview:
    +

    A union type describes an object with size and alignment suitable for + an object of any one of a given set of types (also known as an "untagged" + union). It is similar in concept and usage to a + struct, except that all members of the union + have an offset of zero. The elements of a union may be any type that has a + size. Unions must have at least one member - empty unions are not allowed. +

    + +

    The size of the union as a whole will be the size of its largest member, + and the alignment requirements of the union as a whole will be the largest + alignment requirement of any member.

    + +

    Unions members are accessed using 'load and + 'store' by getting a pointer to a field with + the 'getelementptr' instruction. + Since all members are at offset zero, the getelementptr instruction does + not affect the address, only the type of the resulting pointer.

    + +
    Syntax:
    +
    +  union { <type list> }
    +
    + +
    Examples:
    + + + + + + + + +
    union { i32, i32*, float }A union of three types: an i32, a pointer to + an i32, and a float.
    + union { float, i32 (i32) * }A union, where the first element is a float and the + second element is a pointer to a + function that takes an i32, returning + an i32.
    + +
    + @@ -1991,6 +2059,14 @@ Classifications the number and types of elements must match those specified by the type. +
    Union constants
    +
    Union constants are represented with notation similar to a structure with + a single element - that is, a single typed element surrounded + by braces ({})). For example: "{ i32 4 }". The + union type can be initialized with a single-element + struct as long as the type of the struct element matches the type of + one of the union members.
    +
    Array constants
    Array constants are represented with notation similar to array type definitions (a comma separated list of elements, surrounded by square @@ -2009,7 +2085,8 @@ Classifications
    Zero initialization
    The string 'zeroinitializer' can be used to zero initialize a - value to zero of any type, including scalar and aggregate types. + value to zero of any type, including scalar and + aggregate types. This is often used to avoid having to print large zero initializers (e.g. for large arrays) and is always exactly equivalent to using explicit zero initializers.
    @@ -3845,7 +3922,8 @@ Instruction
    -

    LLVM supports several instructions for working with aggregate values.

    +

    LLVM supports several instructions for working with + aggregate values.

    @@ -3862,14 +3940,14 @@ Instruction
    Overview:
    -

    The 'extractvalue' instruction extracts the value of a struct field - or array element from an aggregate value.

    +

    The 'extractvalue' instruction extracts the value of a member field + from an aggregate value.

    Arguments:

    The first operand of an 'extractvalue' instruction is a value - of struct or array type. The - operands are constant indices to specify which value to extract in a similar - manner as indices in a + of struct, union or + array type. The operands are constant indices to + specify which value to extract in a similar manner as indices in a 'getelementptr' instruction.

    Semantics:
    @@ -3896,16 +3974,15 @@ Instruction
    Overview:
    -

    The 'insertvalue' instruction inserts a value into a struct field or - array element in an aggregate.

    - +

    The 'insertvalue' instruction inserts a value into a member field + in an aggregate value.

    Arguments:

    The first operand of an 'insertvalue' instruction is a value - of struct or array type. The - second operand is a first-class value to insert. The following operands are - constant indices indicating the position at which to insert the value in a - similar manner as indices in a + of struct, union or + array type. The second operand is a first-class + value to insert. The following operands are constant indices indicating + the position at which to insert the value in a similar manner as indices in a 'getelementptr' instruction. The value to insert must have the same type as the value identified by the indices.

    @@ -4107,8 +4184,8 @@ Instruction
    Overview:

    The 'getelementptr' instruction is used to get the address of a - subelement of an aggregate data structure. It performs address calculation - only and does not access memory.

    + subelement of an aggregate data structure. + It performs address calculation only and does not access memory.

    Arguments:

    The first argument is always a pointer, and forms the basis of the @@ -4118,15 +4195,15 @@ Instruction indexes the pointer value given as the first argument, the second index indexes a value of the type pointed to (not necessarily the value directly pointed to, since the first index can be non-zero), etc. The first type - indexed into must be a pointer value, subsequent types can be arrays, vectors - and structs. Note that subsequent types being indexed into can never be - pointers, since that would require loading the pointer before continuing - calculation.

    + indexed into must be a pointer value, subsequent types can be arrays, + vectors, structs and unions. Note that subsequent types being indexed into + can never be pointers, since that would require loading the pointer before + continuing calculation.

    The type of each index argument depends on the type it is indexing into. - When indexing into a (optionally packed) structure, only i32 integer - constants are allowed. When indexing into an array, pointer or - vector, integers of any width are allowed, and they are not required to be + When indexing into a (optionally packed) structure or union, only i32 + integer constants are allowed. When indexing into an array, pointer + or vector, integers of any width are allowed, and they are not required to be constant.

    For example, let's consider a C code fragment and how it gets compiled to diff --git a/include/llvm-c/Core.h b/include/llvm-c/Core.h index 98358fe3807..4500fccb65a 100644 --- a/include/llvm-c/Core.h +++ b/include/llvm-c/Core.h @@ -193,7 +193,8 @@ typedef enum { LLVMPointerTypeKind, /**< Pointers */ LLVMOpaqueTypeKind, /**< Opaque: type with unknown structure */ LLVMVectorTypeKind, /**< SIMD 'packed' format, or other vector type */ - LLVMMetadataTypeKind /**< Metadata */ + LLVMMetadataTypeKind, /**< Metadata */ + LLVMUnionTypeKind /**< Unions */ } LLVMTypeKind; typedef enum { @@ -372,6 +373,13 @@ unsigned LLVMCountStructElementTypes(LLVMTypeRef StructTy); void LLVMGetStructElementTypes(LLVMTypeRef StructTy, LLVMTypeRef *Dest); LLVMBool LLVMIsPackedStruct(LLVMTypeRef StructTy); +/* Operations on union types */ +LLVMTypeRef LLVMUnionTypeInContext(LLVMContextRef C, LLVMTypeRef *ElementTypes, + unsigned ElementCount); +LLVMTypeRef LLVMUnionType(LLVMTypeRef *ElementTypes, unsigned ElementCount); +unsigned LLVMCountUnionElementTypes(LLVMTypeRef UnionTy); +void LLVMGetUnionElementTypes(LLVMTypeRef UnionTy, LLVMTypeRef *Dest); + /* Operations on array, pointer, and vector types (sequence types) */ LLVMTypeRef LLVMArrayType(LLVMTypeRef ElementType, unsigned ElementCount); LLVMTypeRef LLVMPointerType(LLVMTypeRef ElementType, unsigned AddressSpace); diff --git a/include/llvm/Bitcode/LLVMBitCodes.h b/include/llvm/Bitcode/LLVMBitCodes.h index 9bb50d4b3bd..a980df81104 100644 --- a/include/llvm/Bitcode/LLVMBitCodes.h +++ b/include/llvm/Bitcode/LLVMBitCodes.h @@ -94,7 +94,8 @@ namespace bitc { TYPE_CODE_FP128 = 14, // LONG DOUBLE (112 bit mantissa) TYPE_CODE_PPC_FP128= 15, // PPC LONG DOUBLE (2 doubles) - TYPE_CODE_METADATA = 16 // METADATA + TYPE_CODE_METADATA = 16, // METADATA + TYPE_CODE_UNION = 17 // UNION: [eltty x N] }; // The type symbol table only has one code (TST_ENTRY_CODE). diff --git a/include/llvm/Constants.h b/include/llvm/Constants.h index ff1be051bc9..bd14303d670 100644 --- a/include/llvm/Constants.h +++ b/include/llvm/Constants.h @@ -33,6 +33,7 @@ namespace llvm { class ArrayType; class IntegerType; class StructType; +class UnionType; class PointerType; class VectorType; @@ -452,6 +453,50 @@ struct OperandTraits : public VariadicOperandTraits<> { DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantStruct, Constant) +//===----------------------------------------------------------------------===// +// ConstantUnion - Constant Union Declarations +// +class ConstantUnion : public Constant { + friend struct ConstantCreator; + ConstantUnion(const ConstantUnion &); // DO NOT IMPLEMENT +protected: + ConstantUnion(const UnionType *T, Constant* Val); +public: + // ConstantUnion accessors + static Constant *get(const UnionType *T, Constant* V); + + /// Transparently provide more efficient getOperand methods. + DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Constant); + + /// getType() specialization - Reduce amount of casting... + /// + inline const UnionType *getType() const { + return reinterpret_cast(Value::getType()); + } + + /// isNullValue - Return true if this is the value that would be returned by + /// getNullValue. This always returns false because zero structs are always + /// created as ConstantAggregateZero objects. + virtual bool isNullValue() const { + return false; + } + + virtual void destroyConstant(); + virtual void replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U); + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const ConstantUnion *) { return true; } + static bool classof(const Value *V) { + return V->getValueID() == ConstantUnionVal; + } +}; + +template <> +struct OperandTraits : public FixedNumOperandTraits<1> { +}; + +DEFINE_TRANSPARENT_CASTED_OPERAND_ACCESSORS(ConstantUnion, Constant) + //===----------------------------------------------------------------------===// /// ConstantVector - Constant Vector Declarations /// diff --git a/include/llvm/DerivedTypes.h b/include/llvm/DerivedTypes.h index 881fbc81e50..912bb6d882b 100644 --- a/include/llvm/DerivedTypes.h +++ b/include/llvm/DerivedTypes.h @@ -27,6 +27,7 @@ template class TypeMap; class FunctionValType; class ArrayValType; class StructValType; +class UnionValType; class PointerValType; class VectorValType; class IntegerValType; @@ -229,7 +230,8 @@ public: return T->getTypeID() == ArrayTyID || T->getTypeID() == StructTyID || T->getTypeID() == PointerTyID || - T->getTypeID() == VectorTyID; + T->getTypeID() == VectorTyID || + T->getTypeID() == UnionTyID; } }; @@ -301,6 +303,63 @@ public: }; +/// UnionType - Class to represent union types. A union type is similar to +/// a structure, except that all member fields begin at offset 0. +/// +class UnionType : public CompositeType { + friend class TypeMap; + UnionType(const UnionType &); // Do not implement + const UnionType &operator=(const UnionType &); // Do not implement + UnionType(LLVMContext &C, const Type* const* Types, unsigned NumTypes); +public: + /// UnionType::get - This static method is the primary way to create a + /// UnionType. + static UnionType *get(const Type* const* Types, unsigned NumTypes); + + /// UnionType::get - This static method is a convenience method for + /// creating union types by specifying the elements as arguments. + static UnionType *get(const Type *type, ...) END_WITH_NULL; + + /// isValidElementType - Return true if the specified type is valid as a + /// element type. + static bool isValidElementType(const Type *ElemTy); + + /// Given an element type, return the member index of that type, or -1 + /// if there is no such member type. + int getElementTypeIndex(const Type *ElemTy) const; + + // Iterator access to the elements + typedef Type::subtype_iterator element_iterator; + element_iterator element_begin() const { return ContainedTys; } + element_iterator element_end() const { return &ContainedTys[NumContainedTys];} + + // Random access to the elements + unsigned getNumElements() const { return NumContainedTys; } + const Type *getElementType(unsigned N) const { + assert(N < NumContainedTys && "Element number out of range!"); + return ContainedTys[N]; + } + + /// getTypeAtIndex - Given an index value into the type, return the type of + /// the element. For a union type, this must be a constant value... + /// + virtual const Type *getTypeAtIndex(const Value *V) const; + virtual const Type *getTypeAtIndex(unsigned Idx) const; + virtual bool indexValid(const Value *V) const; + virtual bool indexValid(unsigned Idx) const; + + // Implement the AbstractTypeUser interface. + virtual void refineAbstractType(const DerivedType *OldTy, const Type *NewTy); + virtual void typeBecameConcrete(const DerivedType *AbsTy); + + // Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const UnionType *) { return true; } + static inline bool classof(const Type *T) { + return T->getTypeID() == UnionTyID; + } +}; + + /// SequentialType - This is the superclass of the array, pointer and vector /// type classes. All of these represent "arrays" in memory. The array type /// represents a specifically sized array, pointer types are unsized/unknown diff --git a/include/llvm/Type.h b/include/llvm/Type.h index bc319c6537a..52b2c845d8e 100644 --- a/include/llvm/Type.h +++ b/include/llvm/Type.h @@ -82,10 +82,11 @@ public: IntegerTyID, ///< 8: Arbitrary bit width integers FunctionTyID, ///< 9: Functions StructTyID, ///< 10: Structures - ArrayTyID, ///< 11: Arrays - PointerTyID, ///< 12: Pointers - OpaqueTyID, ///< 13: Opaque: type with unknown structure - VectorTyID, ///< 14: SIMD 'packed' format, or other vector type + UnionTyID, ///< 11: Unions + ArrayTyID, ///< 12: Arrays + PointerTyID, ///< 13: Pointers + OpaqueTyID, ///< 14: Opaque: type with unknown structure + VectorTyID, ///< 15: SIMD 'packed' format, or other vector type NumTypeIDs, // Must remain as last defined ID LastPrimitiveTyID = LabelTyID, @@ -297,7 +298,7 @@ public: /// does not include vector types. /// inline bool isAggregateType() const { - return ID == StructTyID || ID == ArrayTyID; + return ID == StructTyID || ID == ArrayTyID || ID == UnionTyID; } /// isSized - Return true if it makes sense to take the size of this type. To @@ -310,7 +311,8 @@ public: return true; // If it is not something that can have a size (e.g. a function or label), // it doesn't have a size. - if (ID != StructTyID && ID != ArrayTyID && ID != VectorTyID) + if (ID != StructTyID && ID != ArrayTyID && ID != VectorTyID && + ID != UnionTyID) return false; // If it is something that can have a size and it's concrete, it definitely // has a size, otherwise we have to try harder to decide. diff --git a/include/llvm/Value.h b/include/llvm/Value.h index 9045906e7be..d06cbc05c6a 100644 --- a/include/llvm/Value.h +++ b/include/llvm/Value.h @@ -215,6 +215,7 @@ public: ConstantFPVal, // This is an instance of ConstantFP ConstantArrayVal, // This is an instance of ConstantArray ConstantStructVal, // This is an instance of ConstantStruct + ConstantUnionVal, // This is an instance of ConstantUnion ConstantVectorVal, // This is an instance of ConstantVector ConstantPointerNullVal, // This is an instance of ConstantPointerNull MDNodeVal, // This is an instance of MDNode diff --git a/lib/AsmParser/LLLexer.cpp b/lib/AsmParser/LLLexer.cpp index 8ad658d858d..46f3cbcfa37 100644 --- a/lib/AsmParser/LLLexer.cpp +++ b/lib/AsmParser/LLLexer.cpp @@ -570,6 +570,7 @@ lltok::Kind LLLexer::LexIdentifier() { KEYWORD(type); KEYWORD(opaque); + KEYWORD(union); KEYWORD(eq); KEYWORD(ne); KEYWORD(slt); KEYWORD(sgt); KEYWORD(sle); KEYWORD(sge); KEYWORD(ult); KEYWORD(ugt); KEYWORD(ule); KEYWORD(uge); diff --git a/lib/AsmParser/LLParser.cpp b/lib/AsmParser/LLParser.cpp index 4dab11826bc..5cff310c7e3 100644 --- a/lib/AsmParser/LLParser.cpp +++ b/lib/AsmParser/LLParser.cpp @@ -1295,6 +1295,11 @@ bool LLParser::ParseTypeRec(PATypeHolder &Result) { if (ParseStructType(Result, false)) return true; break; + case lltok::kw_union: + // TypeRec ::= 'union' '{' ... '}' + if (ParseUnionType(Result)) + return true; + break; case lltok::lsquare: // TypeRec ::= '[' ... ']' Lex.Lex(); // eat the lsquare. @@ -1604,6 +1609,38 @@ bool LLParser::ParseStructType(PATypeHolder &Result, bool Packed) { return false; } +/// ParseUnionType +/// TypeRec +/// ::= 'union' '{' TypeRec (',' TypeRec)* '}' +bool LLParser::ParseUnionType(PATypeHolder &Result) { + assert(Lex.getKind() == lltok::kw_union); + Lex.Lex(); // Consume the 'union' + + if (ParseToken(lltok::lbrace, "'{' expected after 'union'")) return true; + + SmallVector ParamsList; + do { + LocTy EltTyLoc = Lex.getLoc(); + if (ParseTypeRec(Result)) return true; + ParamsList.push_back(Result); + + if (Result->isVoidTy()) + return Error(EltTyLoc, "union element can not have void type"); + if (!UnionType::isValidElementType(Result)) + return Error(EltTyLoc, "invalid element type for union"); + + } while (EatIfPresent(lltok::comma)) ; + + if (ParseToken(lltok::rbrace, "expected '}' at end of union")) + return true; + + SmallVector ParamsListTy; + for (unsigned i = 0, e = ParamsList.size(); i != e; ++i) + ParamsListTy.push_back(ParamsList[i].get()); + Result = HandleUpRefs(UnionType::get(&ParamsListTy[0], ParamsListTy.size())); + return false; +} + /// ParseArrayVectorType - Parse an array or vector type, assuming the first /// token has already been consumed. /// TypeRec @@ -2163,8 +2200,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { ParseToken(lltok::rparen, "expected ')' in extractvalue constantexpr")) return true; - if (!isa(Val->getType()) && !isa(Val->getType())) - return Error(ID.Loc, "extractvalue operand must be array or struct"); + if (!Val->getType()->isAggregateType()) + return Error(ID.Loc, "extractvalue operand must be aggregate type"); if (!ExtractValueInst::getIndexedType(Val->getType(), Indices.begin(), Indices.end())) return Error(ID.Loc, "invalid indices for extractvalue"); @@ -2184,8 +2221,8 @@ bool LLParser::ParseValID(ValID &ID, PerFunctionState *PFS) { ParseIndexList(Indices) || ParseToken(lltok::rparen, "expected ')' in insertvalue constantexpr")) return true; - if (!isa(Val0->getType()) && !isa(Val0->getType())) - return Error(ID.Loc, "extractvalue operand must be array or struct"); + if (!Val0->getType()->isAggregateType()) + return Error(ID.Loc, "insertvalue operand must be aggregate type"); if (!ExtractValueInst::getIndexedType(Val0->getType(), Indices.begin(), Indices.end())) return Error(ID.Loc, "invalid indices for insertvalue"); @@ -2521,8 +2558,17 @@ bool LLParser::ConvertValIDToValue(const Type *Ty, ValID &ID, Value *&V, V = Constant::getNullValue(Ty); return false; case ValID::t_Constant: - if (ID.ConstantVal->getType() != Ty) + if (ID.ConstantVal->getType() != Ty) { + // Allow a constant struct with a single member to be converted + // to a union, if the union has a member which is the same type + // as the struct member. + if (const UnionType* utype = dyn_cast(Ty)) { + return ParseUnionValue(utype, ID, V); + } + return Error(ID.Loc, "constant expression type mismatch"); + } + V = ID.ConstantVal; return false; } @@ -2552,6 +2598,22 @@ bool LLParser::ParseTypeAndBasicBlock(BasicBlock *&BB, LocTy &Loc, return false; } +bool LLParser::ParseUnionValue(const UnionType* utype, ValID &ID, Value *&V) { + if (const StructType* stype = dyn_cast(ID.ConstantVal->getType())) { + if (stype->getNumContainedTypes() != 1) + return Error(ID.Loc, "constant expression type mismatch"); + int index = utype->getElementTypeIndex(stype->getContainedType(0)); + if (index < 0) + return Error(ID.Loc, "initializer type is not a member of the union"); + + V = ConstantUnion::get( + utype, cast(ID.ConstantVal->getOperand(0))); + return false; + } + + return Error(ID.Loc, "constant expression type mismatch"); +} + /// FunctionHeader /// ::= OptionalLinkage OptionalVisibility OptionalCallingConv OptRetAttrs @@ -3811,8 +3873,8 @@ int LLParser::ParseExtractValue(Instruction *&Inst, PerFunctionState &PFS) { ParseIndexList(Indices, AteExtraComma)) return true; - if (!isa(Val->getType()) && !isa(Val->getType())) - return Error(Loc, "extractvalue operand must be array or struct"); + if (!Val->getType()->isAggregateType()) + return Error(Loc, "extractvalue operand must be aggregate type"); if (!ExtractValueInst::getIndexedType(Val->getType(), Indices.begin(), Indices.end())) @@ -3833,8 +3895,8 @@ int LLParser::ParseInsertValue(Instruction *&Inst, PerFunctionState &PFS) { ParseIndexList(Indices, AteExtraComma)) return true; - if (!isa(Val0->getType()) && !isa(Val0->getType())) - return Error(Loc0, "extractvalue operand must be array or struct"); + if (!Val0->getType()->isAggregateType()) + return Error(Loc0, "insertvalue operand must be aggregate type"); if (!ExtractValueInst::getIndexedType(Val0->getType(), Indices.begin(), Indices.end())) diff --git a/lib/AsmParser/LLParser.h b/lib/AsmParser/LLParser.h index ed7a1d71176..9abe4042736 100644 --- a/lib/AsmParser/LLParser.h +++ b/lib/AsmParser/LLParser.h @@ -31,6 +31,7 @@ namespace llvm { class GlobalValue; class MDString; class MDNode; + class UnionType; /// ValID - Represents a reference of a definition of some sort with no type. /// There are several cases where we have to parse the value but where the @@ -212,6 +213,7 @@ namespace llvm { } bool ParseTypeRec(PATypeHolder &H); bool ParseStructType(PATypeHolder &H, bool Packed); + bool ParseUnionType(PATypeHolder &H); bool ParseArrayVectorType(PATypeHolder &H, bool isVector); bool ParseFunctionType(PATypeHolder &Result); PATypeHolder HandleUpRefs(const Type *Ty); @@ -280,6 +282,8 @@ namespace llvm { return ParseTypeAndBasicBlock(BB, Loc, PFS); } + bool ParseUnionValue(const UnionType* utype, ValID &ID, Value *&V); + struct ParamInfo { LocTy Loc; Value *V; diff --git a/lib/AsmParser/LLToken.h b/lib/AsmParser/LLToken.h index 7f1807c7d0d..3ac91690067 100644 --- a/lib/AsmParser/LLToken.h +++ b/lib/AsmParser/LLToken.h @@ -97,6 +97,7 @@ namespace lltok { kw_type, kw_opaque, + kw_union, kw_eq, kw_ne, kw_slt, kw_sgt, kw_sle, kw_sge, kw_ult, kw_ugt, kw_ule, kw_uge, kw_oeq, kw_one, kw_olt, kw_ogt, kw_ole, kw_oge, kw_ord, kw_uno, diff --git a/lib/Bitcode/Reader/BitcodeReader.cpp b/lib/Bitcode/Reader/BitcodeReader.cpp index 4dfc6cef5ad..a0402caa905 100644 --- a/lib/Bitcode/Reader/BitcodeReader.cpp +++ b/lib/Bitcode/Reader/BitcodeReader.cpp @@ -585,6 +585,13 @@ bool BitcodeReader::ParseTypeTable() { ResultTy = StructType::get(Context, EltTys, Record[0]); break; } + case bitc::TYPE_CODE_UNION: { // UNION: [eltty x N] + SmallVector EltTys; + for (unsigned i = 0, e = Record.size(); i != e; ++i) + EltTys.push_back(getTypeByID(Record[i], true)); + ResultTy = UnionType::get(&EltTys[0], EltTys.size()); + break; + } case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty] if (Record.size() < 2) return Error("Invalid ARRAY type record"); diff --git a/lib/Bitcode/Writer/BitcodeWriter.cpp b/lib/Bitcode/Writer/BitcodeWriter.cpp index ec081d5515c..82e73b5cff2 100644 --- a/lib/Bitcode/Writer/BitcodeWriter.cpp +++ b/lib/Bitcode/Writer/BitcodeWriter.cpp @@ -181,6 +181,14 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { Log2_32_Ceil(VE.getTypes().size()+1))); unsigned StructAbbrev = Stream.EmitAbbrev(Abbv); + // Abbrev for TYPE_CODE_UNION. + Abbv = new BitCodeAbbrev(); + Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_UNION)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Array)); + Abbv->Add(BitCodeAbbrevOp(BitCodeAbbrevOp::Fixed, + Log2_32_Ceil(VE.getTypes().size()+1))); + unsigned UnionAbbrev = Stream.EmitAbbrev(Abbv); + // Abbrev for TYPE_CODE_ARRAY. Abbv = new BitCodeAbbrev(); Abbv->Add(BitCodeAbbrevOp(bitc::TYPE_CODE_ARRAY)); @@ -250,6 +258,17 @@ static void WriteTypeTable(const ValueEnumerator &VE, BitstreamWriter &Stream) { AbbrevToUse = StructAbbrev; break; } + case Type::UnionTyID: { + const UnionType *UT = cast(T); + // UNION: [eltty x N] + Code = bitc::TYPE_CODE_UNION; + // Output all of the element types. + for (UnionType::element_iterator I = UT->element_begin(), + E = UT->element_end(); I != E; ++I) + TypeVals.push_back(VE.getTypeID(*I)); + AbbrevToUse = UnionAbbrev; + break; + } case Type::ArrayTyID: { const ArrayType *AT = cast(T); // ARRAY: [numelts, eltty] @@ -789,7 +808,7 @@ static void WriteConstants(unsigned FirstVal, unsigned LastVal, else if (isCStr7) AbbrevToUse = CString7Abbrev; } else if (isa(C) || isa(V) || - isa(V)) { + isa(C) || isa(V)) { Code = bitc::CST_CODE_AGGREGATE; for (unsigned i = 0, e = C->getNumOperands(); i != e; ++i) Record.push_back(VE.getValueID(C->getOperand(i))); diff --git a/lib/Target/X86/X86InstrInfo.td b/lib/Target/X86/X86InstrInfo.td index d0be4f792c2..de085f522b8 100644 --- a/lib/Target/X86/X86InstrInfo.td +++ b/lib/Target/X86/X86InstrInfo.td @@ -4242,7 +4242,7 @@ def INVEPT : I<0x38, RawFrm, (outs), (ins), "invept", []>, OpSize, TB; // 66 0F 38 81 def INVVPID : I<0x38, RawFrm, (outs), (ins), "invvpid", []>, OpSize, TB; // 0F 01 C1 -def VMCALL : I<0x01, RawFrm, (outs), (ins), "vmcall", []>, TB; +def VMCALL : I<0x01, MRM_C1, (outs), (ins), "vmcall", []>, TB; def VMCLEARm : I<0xC7, MRM6m, (outs), (ins i64mem:$vmcs), "vmclear\t$vmcs", []>, OpSize, TB; // 0F 01 C2 diff --git a/lib/VMCore/AsmWriter.cpp b/lib/VMCore/AsmWriter.cpp index 7d6e0a7d0bc..4fe1eeeb4ab 100644 --- a/lib/VMCore/AsmWriter.cpp +++ b/lib/VMCore/AsmWriter.cpp @@ -239,6 +239,19 @@ void TypePrinting::CalcTypeName(const Type *Ty, OS << '>'; break; } + case Type::UnionTyID: { + const UnionType *UTy = cast(Ty); + OS << "union { "; + for (StructType::element_iterator I = UTy->element_begin(), + E = UTy->element_end(); I != E; ++I) { + CalcTypeName(*I, TypeStack, OS); + if (next(I) != UTy->element_end()) + OS << ','; + OS << ' '; + } + OS << '}'; + break; + } case Type::PointerTyID: { const PointerType *PTy = cast(Ty); CalcTypeName(PTy->getElementType(), TypeStack, OS); diff --git a/lib/VMCore/ConstantFold.cpp b/lib/VMCore/ConstantFold.cpp index 5c117d8a181..4a245d22c3e 100644 --- a/lib/VMCore/ConstantFold.cpp +++ b/lib/VMCore/ConstantFold.cpp @@ -885,6 +885,8 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg, unsigned numOps; if (const ArrayType *AR = dyn_cast(AggTy)) numOps = AR->getNumElements(); + else if (isa(AggTy)) + numOps = 1; else numOps = cast(AggTy)->getNumElements(); @@ -901,6 +903,10 @@ Constant *llvm::ConstantFoldInsertValueInstruction(Constant *Agg, if (const StructType* ST = dyn_cast(AggTy)) return ConstantStruct::get(ST->getContext(), Ops, ST->isPacked()); + if (const UnionType* UT = dyn_cast(AggTy)) { + assert(Ops.size() == 1 && "Union can only contain a single value!"); + return ConstantUnion::get(UT, Ops[0]); + } return ConstantArray::get(cast(AggTy), Ops); } diff --git a/lib/VMCore/Constants.cpp b/lib/VMCore/Constants.cpp index 2250626051b..8cc6e94a4e8 100644 --- a/lib/VMCore/Constants.cpp +++ b/lib/VMCore/Constants.cpp @@ -585,6 +585,27 @@ Constant* ConstantStruct::get(LLVMContext &Context, return get(Context, std::vector(Vals, Vals+NumVals), Packed); } +ConstantUnion::ConstantUnion(const UnionType *T, Constant* V) + : Constant(T, ConstantUnionVal, + OperandTraits::op_end(this) - 1, 1) { + Use *OL = OperandList; + assert(T->getElementTypeIndex(V->getType()) >= 0 && + "Initializer for union element isn't a member of union type!"); + *OL = V; +} + +// ConstantUnion accessors. +Constant* ConstantUnion::get(const UnionType* T, Constant* V) { + LLVMContextImpl* pImpl = T->getContext().pImpl; + + // Create a ConstantAggregateZero value if all elements are zeros... + if (!V->isNullValue()) + return pImpl->UnionConstants.getOrCreate(T, V); + + return ConstantAggregateZero::get(T); +} + + ConstantVector::ConstantVector(const VectorType *T, const std::vector &V) : Constant(T, ConstantVectorVal, @@ -1008,6 +1029,13 @@ void ConstantStruct::destroyConstant() { destroyConstantImpl(); } +// destroyConstant - Remove the constant from the constant table... +// +void ConstantUnion::destroyConstant() { + getType()->getContext().pImpl->UnionConstants.remove(this); + destroyConstantImpl(); +} + // destroyConstant - Remove the constant from the constant table... // void ConstantVector::destroyConstant() { @@ -2083,6 +2111,11 @@ void ConstantStruct::replaceUsesOfWithOnConstant(Value *From, Value *To, destroyConstant(); } +void ConstantUnion::replaceUsesOfWithOnConstant(Value *From, Value *To, + Use *U) { + assert(false && "Implement replaceUsesOfWithOnConstant for unions"); +} + void ConstantVector::replaceUsesOfWithOnConstant(Value *From, Value *To, Use *U) { assert(isa(To) && "Cannot make Constant refer to non-constant!"); diff --git a/lib/VMCore/ConstantsContext.h b/lib/VMCore/ConstantsContext.h index 08224e4488b..c798ba2664c 100644 --- a/lib/VMCore/ConstantsContext.h +++ b/lib/VMCore/ConstantsContext.h @@ -341,6 +341,13 @@ struct ConstantTraits< std::vector > { } }; +template<> +struct ConstantTraits { + static unsigned uses(Constant * const & v) { + return 1; + } +}; + template struct ConstantCreator { static ConstantClass *create(const TypeClass *Ty, const ValType &V) { @@ -470,6 +477,14 @@ struct ConstantKeyData { } }; +template<> +struct ConstantKeyData { + typedef Constant* ValType; + static ValType getValType(ConstantUnion *CU) { + return cast(CU->getOperand(0)); + } +}; + // ConstantPointerNull does not take extra "value" argument... template struct ConstantCreator { diff --git a/lib/VMCore/Core.cpp b/lib/VMCore/Core.cpp index 1755cd213e2..a044fc5b1a0 100644 --- a/lib/VMCore/Core.cpp +++ b/lib/VMCore/Core.cpp @@ -141,6 +141,8 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) { return LLVMFunctionTypeKind; case Type::StructTyID: return LLVMStructTypeKind; + case Type::UnionTyID: + return LLVMUnionTypeKind; case Type::ArrayTyID: return LLVMArrayTypeKind; case Type::PointerTyID: @@ -299,6 +301,35 @@ LLVMBool LLVMIsPackedStruct(LLVMTypeRef StructTy) { return unwrap(StructTy)->isPacked(); } +/*--.. Operations on union types ..........................................--*/ + +LLVMTypeRef LLVMUnionTypeInContext(LLVMContextRef C, LLVMTypeRef *ElementTypes, + unsigned ElementCount) { + SmallVector Tys; + for (LLVMTypeRef *I = ElementTypes, + *E = ElementTypes + ElementCount; I != E; ++I) + Tys.push_back(unwrap(*I)); + + return wrap(UnionType::get(&Tys[0], Tys.size())); +} + +LLVMTypeRef LLVMUnionType(LLVMTypeRef *ElementTypes, + unsigned ElementCount, int Packed) { + return LLVMUnionTypeInContext(LLVMGetGlobalContext(), ElementTypes, + ElementCount); +} + +unsigned LLVMCountUnionElementTypes(LLVMTypeRef UnionTy) { + return unwrap(UnionTy)->getNumElements(); +} + +void LLVMGetUnionElementTypes(LLVMTypeRef UnionTy, LLVMTypeRef *Dest) { + UnionType *Ty = unwrap(UnionTy); + for (FunctionType::param_iterator I = Ty->element_begin(), + E = Ty->element_end(); I != E; ++I) + *Dest++ = wrap(*I); +} + /*--.. Operations on array, pointer, and vector types (sequence types) .....--*/ LLVMTypeRef LLVMArrayType(LLVMTypeRef ElementType, unsigned ElementCount) { diff --git a/lib/VMCore/LLVMContextImpl.h b/lib/VMCore/LLVMContextImpl.h index f7f4860614a..62491d838fb 100644 --- a/lib/VMCore/LLVMContextImpl.h +++ b/lib/VMCore/LLVMContextImpl.h @@ -116,6 +116,10 @@ public: ConstantStruct, true /*largekey*/> StructConstantsTy; StructConstantsTy StructConstants; + typedef ConstantUniqueMap + UnionConstantsTy; + UnionConstantsTy UnionConstants; + typedef ConstantUniqueMap, VectorType, ConstantVector> VectorConstantsTy; VectorConstantsTy VectorConstants; @@ -159,6 +163,7 @@ public: TypeMap PointerTypes; TypeMap FunctionTypes; TypeMap StructTypes; + TypeMap UnionTypes; TypeMap IntegerTypes; // Opaque types are not structurally uniqued, so don't use TypeMap. diff --git a/lib/VMCore/Type.cpp b/lib/VMCore/Type.cpp index cf851987df8..b1cdad577c8 100644 --- a/lib/VMCore/Type.cpp +++ b/lib/VMCore/Type.cpp @@ -50,8 +50,8 @@ void AbstractTypeUser::setType(Value *V, const Type *NewTy) { /// Because of the way Type subclasses are allocated, this function is necessary /// to use the correct kind of "delete" operator to deallocate the Type object. -/// Some type objects (FunctionTy, StructTy) allocate additional space after -/// the space for their derived type to hold the contained types array of +/// Some type objects (FunctionTy, StructTy, UnionTy) allocate additional space +/// after the space for their derived type to hold the contained types array of /// PATypeHandles. Using this allocation scheme means all the PATypeHandles are /// allocated with the type object, decreasing allocations and eliminating the /// need for a std::vector to be used in the Type class itself. @@ -61,7 +61,8 @@ void Type::destroy() const { // Structures and Functions allocate their contained types past the end of // the type object itself. These need to be destroyed differently than the // other types. - if (isa(this) || isa(this)) { + if (isa(this) || isa(this) || + isa(this)) { // First, make sure we destruct any PATypeHandles allocated by these // subclasses. They must be manually destructed. for (unsigned i = 0; i < NumContainedTys; ++i) @@ -71,8 +72,10 @@ void Type::destroy() const { // to delete this as an array of char. if (isa(this)) static_cast(this)->FunctionType::~FunctionType(); - else + else if (isa(this)) static_cast(this)->StructType::~StructType(); + else + static_cast(this)->UnionType::~UnionType(); // Finally, remove the memory as an array deallocation of the chars it was // constructed from. @@ -226,7 +229,7 @@ bool Type::isSizedDerivedType() const { if (const VectorType *PTy = dyn_cast(this)) return PTy->getElementType()->isSized(); - if (!isa(this)) + if (!isa(this) && !isa(this)) return false; // Okay, our struct is sized if all of the elements are... @@ -308,6 +311,32 @@ const Type *StructType::getTypeAtIndex(unsigned Idx) const { return ContainedTys[Idx]; } + +bool UnionType::indexValid(const Value *V) const { + // Union indexes require 32-bit integer constants. + if (V->getType()->isInteger(32)) + if (const ConstantInt *CU = dyn_cast(V)) + return indexValid(CU->getZExtValue()); + return false; +} + +bool UnionType::indexValid(unsigned V) const { + return V < NumContainedTys; +} + +// getTypeAtIndex - Given an index value into the type, return the type of the +// element. For a structure type, this must be a constant value... +// +const Type *UnionType::getTypeAtIndex(const Value *V) const { + unsigned Idx = (unsigned)cast(V)->getZExtValue(); + return getTypeAtIndex(Idx); +} + +const Type *UnionType::getTypeAtIndex(unsigned Idx) const { + assert(indexValid(Idx) && "Invalid structure index!"); + return ContainedTys[Idx]; +} + //===----------------------------------------------------------------------===// // Primitive 'Type' data //===----------------------------------------------------------------------===// @@ -463,6 +492,23 @@ StructType::StructType(LLVMContext &C, setAbstract(isAbstract); } +UnionType::UnionType(LLVMContext &C,const Type* const* Types, unsigned NumTypes) + : CompositeType(C, UnionTyID) { + ContainedTys = reinterpret_cast(this + 1); + NumContainedTys = NumTypes; + bool isAbstract = false; + for (unsigned i = 0; i < NumTypes; ++i) { + assert(Types[i] && " type for union field!"); + assert(isValidElementType(Types[i]) && + "Invalid type for union element!"); + new (&ContainedTys[i]) PATypeHandle(Types[i], this); + isAbstract |= Types[i]->isAbstract(); + } + + // Calculate whether or not this type is abstract + setAbstract(isAbstract); +} + ArrayType::ArrayType(const Type *ElType, uint64_t NumEl) : SequentialType(ArrayTyID, ElType) { NumElements = NumEl; @@ -644,6 +690,13 @@ static bool TypesEqual(const Type *Ty, const Type *Ty2, if (!TypesEqual(STy->getElementType(i), STy2->getElementType(i), EqTypes)) return false; return true; + } else if (const UnionType *UTy = dyn_cast(Ty)) { + const UnionType *UTy2 = cast(Ty2); + if (UTy->getNumElements() != UTy2->getNumElements()) return false; + for (unsigned i = 0, e = UTy2->getNumElements(); i != e; ++i) + if (!TypesEqual(UTy->getElementType(i), UTy2->getElementType(i), EqTypes)) + return false; + return true; } else if (const ArrayType *ATy = dyn_cast(Ty)) { const ArrayType *ATy2 = cast(Ty2); return ATy->getNumElements() == ATy2->getNumElements() && @@ -901,11 +954,65 @@ StructType *StructType::get(LLVMContext &Context, const Type *type, ...) { } bool StructType::isValidElementType(const Type *ElemTy) { - return ElemTy->getTypeID() != VoidTyID && ElemTy->getTypeID() != LabelTyID && - ElemTy->getTypeID() != MetadataTyID && !isa(ElemTy); + return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && + !ElemTy->isMetadataTy() && !isa(ElemTy); } +//===----------------------------------------------------------------------===// +// Union Type Factory... +// + +UnionType *UnionType::get(const Type* const* Types, unsigned NumTypes) { + assert(NumTypes > 0 && "union must have at least one member type!"); + UnionValType UTV(Types, NumTypes); + UnionType *UT = 0; + + LLVMContextImpl *pImpl = Types[0]->getContext().pImpl; + + UT = pImpl->UnionTypes.get(UTV); + + if (!UT) { + // Value not found. Derive a new type! + UT = (UnionType*) operator new(sizeof(UnionType) + + sizeof(PATypeHandle) * NumTypes); + new (UT) UnionType(Types[0]->getContext(), Types, NumTypes); + pImpl->UnionTypes.add(UTV, UT); + } +#ifdef DEBUG_MERGE_TYPES + DEBUG(dbgs() << "Derived new type: " << *UT << "\n"); +#endif + return UT; +} + +UnionType *UnionType::get(const Type *type, ...) { + va_list ap; + SmallVector UnionFields; + va_start(ap, type); + while (type) { + UnionFields.push_back(type); + type = va_arg(ap, llvm::Type*); + } + unsigned NumTypes = UnionFields.size(); + assert(NumTypes > 0 && "union must have at least one member type!"); + return llvm::UnionType::get(&UnionFields[0], NumTypes); +} + +bool UnionType::isValidElementType(const Type *ElemTy) { + return !ElemTy->isVoidTy() && !ElemTy->isLabelTy() && + !ElemTy->isMetadataTy() && !ElemTy->isFunction(); +} + +int UnionType::getElementTypeIndex(const Type *ElemTy) const { + int index = 0; + for (UnionType::element_iterator I = element_begin(), E = element_end(); + I != E; ++I, ++index) { + if (ElemTy == *I) return index; + } + + return -1; +} + //===----------------------------------------------------------------------===// // Pointer Type Factory... // @@ -1165,6 +1272,21 @@ void StructType::typeBecameConcrete(const DerivedType *AbsTy) { pImpl->StructTypes.TypeBecameConcrete(this, AbsTy); } +// refineAbstractType - Called when a contained type is found to be more +// concrete - this could potentially change us from an abstract type to a +// concrete type. +// +void UnionType::refineAbstractType(const DerivedType *OldType, + const Type *NewType) { + LLVMContextImpl *pImpl = OldType->getContext().pImpl; + pImpl->UnionTypes.RefineAbstractType(this, OldType, NewType); +} + +void UnionType::typeBecameConcrete(const DerivedType *AbsTy) { + LLVMContextImpl *pImpl = AbsTy->getContext().pImpl; + pImpl->UnionTypes.TypeBecameConcrete(this, AbsTy); +} + // refineAbstractType - Called when a contained type is found to be more // concrete - this could potentially change us from an abstract type to a // concrete type. diff --git a/lib/VMCore/TypesContext.h b/lib/VMCore/TypesContext.h index 484284551fa..02ab1135b32 100644 --- a/lib/VMCore/TypesContext.h +++ b/lib/VMCore/TypesContext.h @@ -180,6 +180,32 @@ public: } }; +// UnionValType - Define a class to hold the key that goes into the TypeMap +// +class UnionValType { + std::vector ElTypes; +public: + UnionValType(const Type* const* Types, unsigned NumTypes) + : ElTypes(&Types[0], &Types[NumTypes]) {} + + static UnionValType get(const UnionType *UT) { + std::vector ElTypes; + ElTypes.reserve(UT->getNumElements()); + for (unsigned i = 0, e = UT->getNumElements(); i != e; ++i) + ElTypes.push_back(UT->getElementType(i)); + + return UnionValType(&ElTypes[0], ElTypes.size()); + } + + static unsigned hashTypeStructure(const UnionType *UT) { + return UT->getNumElements(); + } + + inline bool operator<(const UnionValType &UTV) const { + return (ElTypes < UTV.ElTypes); + } +}; + // FunctionValType - Define a class to hold the key that goes into the TypeMap // class FunctionValType { diff --git a/test/Assembler/2010-01-06-UnionType.ll b/test/Assembler/2010-01-06-UnionType.ll new file mode 100644 index 00000000000..37130d66088 --- /dev/null +++ b/test/Assembler/2010-01-06-UnionType.ll @@ -0,0 +1,3 @@ +; RUN: llvm-as %s -o /dev/null + +%X = type union { i32, i32* } diff --git a/test/Feature/unions.ll b/test/Feature/unions.ll new file mode 100644 index 00000000000..9d6c36bb3c5 --- /dev/null +++ b/test/Feature/unions.ll @@ -0,0 +1,12 @@ +; RUN: llvm-as < %s | llvm-dis > %t1.ll +; RUN: llvm-as %t1.ll -o - | llvm-dis > %t2.ll +; RUN: diff %t1.ll %t2.ll + +%union.anon = type union { i8, i32, float } + +@union1 = constant union { i32, i8 } { i32 4 } +@union2 = constant union { i32, i8 } insertvalue(union { i32, i8 } undef, i32 4, 0) + +define void @"Unions" () { + ret void +}