[llvm] e6b0221 - [IR] Add a target extension type to LLVM.
Joshua Cranmer via llvm-commits
llvm-commits at lists.llvm.org
Tue Dec 20 08:03:51 PST 2022
Author: Joshua Cranmer
Date: 2022-12-20T11:02:11-05:00
New Revision: e6b02214c68df2c9f826e02310c9352ac652e456
URL: https://github.com/llvm/llvm-project/commit/e6b02214c68df2c9f826e02310c9352ac652e456
DIFF: https://github.com/llvm/llvm-project/commit/e6b02214c68df2c9f826e02310c9352ac652e456.diff
LOG: [IR] Add a target extension type to LLVM.
Target-extension types represent types that need to be preserved through
optimization, but otherwise are not introspectable by target-independent
optimizations. This patch doesn't add any uses of these types by an existing
backend, it only provides basic infrastructure such that these types would work
correctly.
Reviewed By: nikic, barannikov88
Differential Revision: https://reviews.llvm.org/D135202
Added:
llvm/test/Assembler/invalid-target-type-mixed.ll
llvm/test/Assembler/target-type-mangled.ll
llvm/test/Assembler/target-type-params.ll
llvm/test/Assembler/target-type-properties.ll
llvm/test/Assembler/target-types.ll
llvm/test/Transforms/GVN/target-type.ll
llvm/test/Transforms/SROA/sroa-target.ll
Modified:
llvm/docs/BitCodeFormat.rst
llvm/docs/LangRef.rst
llvm/docs/ReleaseNotes.rst
llvm/include/llvm-c/Core.h
llvm/include/llvm/AsmParser/LLParser.h
llvm/include/llvm/Bitcode/LLVMBitCodes.h
llvm/include/llvm/IR/Constants.h
llvm/include/llvm/IR/DataLayout.h
llvm/include/llvm/IR/DerivedTypes.h
llvm/include/llvm/IR/Type.h
llvm/include/llvm/IR/Value.def
llvm/lib/AsmParser/LLParser.cpp
llvm/lib/Bitcode/Reader/BitcodeReader.cpp
llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
llvm/lib/IR/AsmWriter.cpp
llvm/lib/IR/Constants.cpp
llvm/lib/IR/Core.cpp
llvm/lib/IR/DataLayout.cpp
llvm/lib/IR/Function.cpp
llvm/lib/IR/LLVMContextImpl.cpp
llvm/lib/IR/LLVMContextImpl.h
llvm/lib/IR/Type.cpp
llvm/lib/IR/Verifier.cpp
llvm/lib/Transforms/Scalar/SROA.cpp
llvm/lib/Transforms/Utils/VNCoercion.cpp
llvm/tools/llvm-c-test/echo.cpp
llvm/unittests/IR/TypesTest.cpp
Removed:
################################################################################
diff --git a/llvm/docs/BitCodeFormat.rst b/llvm/docs/BitCodeFormat.rst
index d581e18d6daaa..7bbdc5493f175 100644
--- a/llvm/docs/BitCodeFormat.rst
+++ b/llvm/docs/BitCodeFormat.rst
@@ -1338,6 +1338,21 @@ TYPE_CODE_X86_AMX Record
The ``X86_AMX`` record (code 24) adds an ``x86_amx`` type to the type table.
+TYPE_CODE_TARGET_TYPE Record
+^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+``[TARGET_TYPE, num_tys, ...ty_params..., ...int_params... ]``
+
+The ``TARGET_TYPE`` record (code 26) adds a target extension type to the type
+table, with a name defined by a previously encountered ``STRUCT_NAME`` record.
+The operand fields are
+
+* *num_tys*: The number of parameters that are types (as opposed to integers)
+
+* *ty_params*: Type indices that represent type parameters
+
+* *int_params*: Numbers that correspond to the integer parameters.
+
.. _CONSTANTS_BLOCK:
CONSTANTS_BLOCK Contents
diff --git a/llvm/docs/LangRef.rst b/llvm/docs/LangRef.rst
index 938560b07f62c..e8dd9b4948da1 100644
--- a/llvm/docs/LangRef.rst
+++ b/llvm/docs/LangRef.rst
@@ -3631,6 +3631,53 @@ Prior to LLVM 15, pointer types also specified a pointee type, such as
pointers" are still supported under non-default options. See the
`opaque pointers document <OpaquePointers.html>`__ for more information.
+.. _t_target_type:
+
+Target Extension Type
+"""""""""""""""""""""
+
+:Overview:
+
+Target extension types represent types that must be preserved through
+optimization, but are otherwise generally opaque to the compiler. They may be
+used as function parameters or arguments, and in :ref:`phi <i_phi>` or
+:ref:`select <i_select>` instructions. Some types may be also used in
+:ref:`alloca <i_alloca>` instructions or as global values, and correspondingly
+it is legal to use :ref:`load <i_load>` and :ref:`store <i_store>` instructions
+on them. Full semantics for these types are defined by the target.
+
+The only constants that target extension types may have are ``zeroinitializer``,
+``undef``, and ``poison``. Other possible values for target extension types may
+arise from target-specific intrinsics and functions.
+
+These types cannot be converted to other types. As such, it is not legal to use
+them in :ref:`bitcast <i_bitcast>` instructions (as a source or target type),
+nor is it legal to use them in :ref:`ptrtoint <i_ptrtoint>` or
+:ref:`inttoptr <i_inttoptr>` instructions. Similarly, they are not legal to use
+in an :ref:`icmp <i_icmp>` instruction.
+
+Target extension types have a name and optional type or integer parameters. The
+meanings of name and parameters are defined by the target. When being defined in
+LLVM IR, all of the type parameters must precede all of the integer parameters.
+
+Specific target extension types are registered with LLVM as having specific
+properties. These properties can be used to restrict the type from appearing in
+certain contexts, such as being the type of a global variable or having a
+``zeroinitializer`` constant be valid. A complete list of type properties may be
+found in the documentation for ``llvm::TargetExtType::Property`` (`doxygen
+<https://llvm.org/doxygen/classllvm_1_1TargetExtType.html>`_).
+
+:Syntax:
+
+.. code-block:: llvm
+
+ target("label")
+ target("label", void)
+ target("label", void, i32)
+ target("label", 0, 1, 2)
+ target("label", void, i32, 0, 1, 2)
+
+
.. _t_vector:
Vector Type
diff --git a/llvm/docs/ReleaseNotes.rst b/llvm/docs/ReleaseNotes.rst
index 8d473c40a4167..93e7019364daa 100644
--- a/llvm/docs/ReleaseNotes.rst
+++ b/llvm/docs/ReleaseNotes.rst
@@ -104,6 +104,10 @@ Changes to the LLVM IR
* ``fneg``
+* Target extension types have been added, which allow targets to have
+ types that need to be preserved through the optimizer, but otherwise are not
+ introspectable by target-independent optimizations.
+
Changes to building LLVM
------------------------
diff --git a/llvm/include/llvm-c/Core.h b/llvm/include/llvm-c/Core.h
index 1a02a07c783f6..7ce91bf251930 100644
--- a/llvm/include/llvm-c/Core.h
+++ b/llvm/include/llvm-c/Core.h
@@ -165,7 +165,8 @@ typedef enum {
LLVMTokenTypeKind, /**< Tokens */
LLVMScalableVectorTypeKind, /**< Scalable SIMD vector type */
LLVMBFloatTypeKind, /**< 16 bit brain floating point type */
- LLVMX86_AMXTypeKind /**< X86 AMX */
+ LLVMX86_AMXTypeKind, /**< X86 AMX */
+ LLVMTargetExtTypeKind, /**< Target extension type */
} LLVMTypeKind;
typedef enum {
@@ -284,7 +285,8 @@ typedef enum {
LLVMInlineAsmValueKind,
LLVMInstructionValueKind,
- LLVMPoisonValueValueKind
+ LLVMPoisonValueValueKind,
+ LLVMConstantTargetNoneValueKind,
} LLVMValueKind;
typedef enum {
@@ -1571,6 +1573,15 @@ LLVMTypeRef LLVMLabelType(void);
LLVMTypeRef LLVMX86MMXType(void);
LLVMTypeRef LLVMX86AMXType(void);
+/**
+ * Create a target extension type in LLVM context.
+ */
+LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
+ LLVMTypeRef *TypeParams,
+ unsigned TypeParamCount,
+ unsigned *IntParams,
+ unsigned IntParamCount);
+
/**
* @}
*/
diff --git a/llvm/include/llvm/AsmParser/LLParser.h b/llvm/include/llvm/AsmParser/LLParser.h
index a0b22ab5b8ffa..2f39803816330 100644
--- a/llvm/include/llvm/AsmParser/LLParser.h
+++ b/llvm/include/llvm/AsmParser/LLParser.h
@@ -433,6 +433,7 @@ namespace llvm {
bool parseArrayVectorType(Type *&Result, bool IsVector);
bool parseFunctionType(Type *&Result);
+ bool parseTargetExtType(Type *&Result);
// Function Semantic Analysis.
class PerFunctionState {
diff --git a/llvm/include/llvm/Bitcode/LLVMBitCodes.h b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
index 2b474b67425c8..4e19aa610648c 100644
--- a/llvm/include/llvm/Bitcode/LLVMBitCodes.h
+++ b/llvm/include/llvm/Bitcode/LLVMBitCodes.h
@@ -175,6 +175,8 @@ enum TypeCodes {
TYPE_CODE_X86_AMX = 24, // X86 AMX
TYPE_CODE_OPAQUE_POINTER = 25, // OPAQUE_POINTER: [addrspace]
+
+ TYPE_CODE_TARGET_TYPE = 26, // TARGET_TYPE
};
enum OperandBundleTagCode {
diff --git a/llvm/include/llvm/IR/Constants.h b/llvm/include/llvm/IR/Constants.h
index bb66255f1fc2d..3c4ce0434ea81 100644
--- a/llvm/include/llvm/IR/Constants.h
+++ b/llvm/include/llvm/IR/Constants.h
@@ -843,6 +843,33 @@ class ConstantTokenNone final : public ConstantData {
}
};
+/// A constant target extension type default initializer
+class ConstantTargetNone final : public ConstantData {
+ friend class Constant;
+
+ explicit ConstantTargetNone(TargetExtType *T)
+ : ConstantData(T, Value::ConstantTargetNoneVal) {}
+
+ void destroyConstantImpl();
+
+public:
+ ConstantTargetNone(const ConstantTargetNone &) = delete;
+
+ /// Static factory methods - Return objects of the specified value.
+ static ConstantTargetNone *get(TargetExtType *T);
+
+ /// Specialize the getType() method to always return an TargetExtType,
+ /// which reduces the amount of casting needed in parts of the compiler.
+ inline TargetExtType *getType() const {
+ return cast<TargetExtType>(Value::getType());
+ }
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast.
+ static bool classof(const Value *V) {
+ return V->getValueID() == ConstantTargetNoneVal;
+ }
+};
+
/// The address of a basic block.
///
class BlockAddress final : public Constant {
diff --git a/llvm/include/llvm/IR/DataLayout.h b/llvm/include/llvm/IR/DataLayout.h
index f4174ede22fbd..4784614627e84 100644
--- a/llvm/include/llvm/IR/DataLayout.h
+++ b/llvm/include/llvm/IR/DataLayout.h
@@ -713,6 +713,10 @@ inline TypeSize DataLayout::getTypeSizeInBits(Type *Ty) const {
getTypeSizeInBits(VTy->getElementType()).getFixedSize();
return TypeSize(MinBits, EltCnt.isScalable());
}
+ case Type::TargetExtTyID: {
+ Type *LayoutTy = cast<TargetExtType>(Ty)->getLayoutType();
+ return getTypeSizeInBits(LayoutTy);
+ }
default:
llvm_unreachable("DataLayout::getTypeSizeInBits(): Unsupported type");
}
diff --git a/llvm/include/llvm/IR/DerivedTypes.h b/llvm/include/llvm/IR/DerivedTypes.h
index f505fd3f3e325..e5beca2b499ed 100644
--- a/llvm/include/llvm/IR/DerivedTypes.h
+++ b/llvm/include/llvm/IR/DerivedTypes.h
@@ -730,6 +730,82 @@ unsigned Type::getPointerAddressSpace() const {
return cast<PointerType>(getScalarType())->getAddressSpace();
}
+/// Class to represent target extensions types, which are generally
+/// unintrospectable from target-independent optimizations.
+///
+/// Target extension types have a string name, and optionally have type and/or
+/// integer parameters. The exact meaning of any parameters is dependent on the
+/// target.
+class TargetExtType : public Type {
+ TargetExtType(LLVMContext &C, StringRef Name, ArrayRef<Type *> Types,
+ ArrayRef<unsigned> Ints);
+
+ std::string Name;
+ unsigned *IntParams;
+
+public:
+ TargetExtType(const TargetExtType &) = delete;
+ TargetExtType &operator=(const TargetExtType &) = delete;
+
+ /// Return a target extension type having the specified name and optional
+ /// type and integer parameters.
+ static TargetExtType *get(LLVMContext &Context, StringRef Name,
+ ArrayRef<Type *> Types = std::nullopt,
+ ArrayRef<unsigned> Ints = std::nullopt);
+
+ /// Return the name for this target extension type. Two distinct target
+ /// extension types may have the same name if their type or integer parameters
+ ///
diff er.
+ StringRef getName() const { return Name; }
+
+ /// Return the type parameters for this particular target extension type. If
+ /// there are no parameters, an empty array is returned.
+ ArrayRef<Type *> type_params() const {
+ return makeArrayRef(type_param_begin(), type_param_end());
+ }
+
+ using type_param_iterator = Type::subtype_iterator;
+ type_param_iterator type_param_begin() const { return ContainedTys; }
+ type_param_iterator type_param_end() const {
+ return &ContainedTys[NumContainedTys];
+ }
+
+ Type *getTypeParameter(unsigned i) const { return getContainedType(i); }
+ unsigned getNumTypeParameters() const { return getNumContainedTypes(); }
+
+ /// Return the integer parameters for this particular target extension type.
+ /// If there are no parameters, an empty array is returned.
+ ArrayRef<unsigned> int_params() const {
+ return makeArrayRef(IntParams, getNumIntParameters());
+ }
+
+ unsigned getIntParameter(unsigned i) const { return IntParams[i]; }
+ unsigned getNumIntParameters() const { return getSubclassData(); }
+
+ enum Property {
+ /// zeroinitializer is valid for this target extension type.
+ HasZeroInit = 1U << 0,
+ /// This type may be used as the value type of a global variable.
+ CanBeGlobal = 1U << 1,
+ };
+
+ /// Returns true if the target extension type contains the given property.
+ bool hasProperty(Property Prop) const;
+
+ /// Returns an underlying layout type for the target extension type. This
+ /// type can be used to query size and alignment information, if it is
+ /// appropriate (although note that the layout type may also be void). It is
+ /// not legal to bitcast between this type and the layout type, however.
+ Type *getLayoutType() const;
+
+ /// Methods for support type inquiry through isa, cast, and dyn_cast.
+ static bool classof(const Type *T) { return T->getTypeID() == TargetExtTyID; }
+};
+
+StringRef Type::getTargetExtName() const {
+ return cast<TargetExtType>(this)->getName();
+}
+
} // end namespace llvm
#endif // LLVM_IR_DERIVEDTYPES_H
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index a1848c812c3de..6b291ec0c897c 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -76,6 +76,7 @@ class Type {
FixedVectorTyID, ///< Fixed width SIMD vector type
ScalableVectorTyID, ///< Scalable SIMD vector type
TypedPointerTyID, ///< Typed pointer used by some GPU targets
+ TargetExtTyID, ///< Target extension type
};
private:
@@ -194,6 +195,9 @@ class Type {
/// Return true if this is X86 AMX.
bool isX86_AMXTy() const { return getTypeID() == X86_AMXTyID; }
+ /// Return true if this is a target extension type.
+ bool isTargetExtTy() const { return getTypeID() == TargetExtTyID; }
+
/// Return true if this is a FP type or a vector of FP.
bool isFPOrFPVectorTy() const { return getScalarType()->isFloatingPointTy(); }
@@ -267,7 +271,7 @@ class Type {
/// includes all first-class types except struct and array types.
bool isSingleValueType() const {
return isFloatingPointTy() || isX86_MMXTy() || isIntegerTy() ||
- isPointerTy() || isVectorTy() || isX86_AMXTy();
+ isPointerTy() || isVectorTy() || isX86_AMXTy() || isTargetExtTy();
}
/// Return true if the type is an aggregate type. This means it is valid as
@@ -288,7 +292,8 @@ class Type {
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 (getTypeID() != StructTyID && getTypeID() != ArrayTyID && !isVectorTy())
+ if (getTypeID() != StructTyID && getTypeID() != ArrayTyID &&
+ !isVectorTy() && getTypeID() != TargetExtTyID)
return false;
// Otherwise we have to try harder to decide.
return isSizedDerivedType(Visited);
@@ -386,6 +391,8 @@ class Type {
return ContainedTys[0];
}
+ inline StringRef getTargetExtName() const;
+
/// This method is deprecated without replacement. Pointer element types are
/// not available with opaque pointers.
[[deprecated("Deprecated without replacement, see "
diff --git a/llvm/include/llvm/IR/Value.def b/llvm/include/llvm/IR/Value.def
index 97d15260f36b0..61f7a87666d09 100644
--- a/llvm/include/llvm/IR/Value.def
+++ b/llvm/include/llvm/IR/Value.def
@@ -95,6 +95,7 @@ HANDLE_CONSTANT(ConstantDataArray)
HANDLE_CONSTANT(ConstantDataVector)
HANDLE_CONSTANT(ConstantInt)
HANDLE_CONSTANT(ConstantFP)
+HANDLE_CONSTANT(ConstantTargetNone)
HANDLE_CONSTANT(ConstantPointerNull)
HANDLE_CONSTANT(ConstantTokenNone)
diff --git a/llvm/lib/AsmParser/LLParser.cpp b/llvm/lib/AsmParser/LLParser.cpp
index db45f692561d5..ba41556e30eae 100644
--- a/llvm/lib/AsmParser/LLParser.cpp
+++ b/llvm/lib/AsmParser/LLParser.cpp
@@ -2598,6 +2598,12 @@ bool LLParser::parseType(Type *&Result, const Twine &Msg, bool AllowVoid) {
return false;
}
break;
+ case lltok::kw_target: {
+ // Type ::= TargetExtType
+ if (parseTargetExtType(Result))
+ return true;
+ break;
+ }
case lltok::lbrace:
// Type ::= StructType
if (parseAnonStructType(Result, false))
@@ -3105,6 +3111,60 @@ bool LLParser::parseArrayVectorType(Type *&Result, bool IsVector) {
return false;
}
+/// parseTargetExtType - handle target extension type syntax
+/// TargetExtType
+/// ::= 'target' '(' STRINGCONSTANT TargetExtTypeParams TargetExtIntParams ')'
+///
+/// TargetExtTypeParams
+/// ::= /*empty*/
+/// ::= ',' Type TargetExtTypeParams
+///
+/// TargetExtIntParams
+/// ::= /*empty*/
+/// ::= ',' uint32 TargetExtIntParams
+bool LLParser::parseTargetExtType(Type *&Result) {
+ Lex.Lex(); // Eat the 'target' keyword.
+
+ // Get the mandatory type name.
+ std::string TypeName;
+ if (parseToken(lltok::lparen, "expected '(' in target extension type") ||
+ parseStringConstant(TypeName))
+ return true;
+
+ // Parse all of the integer and type parameters at the same time; the use of
+ // SeenInt will allow us to catch cases where type parameters follow integer
+ // parameters.
+ SmallVector<Type *> TypeParams;
+ SmallVector<unsigned> IntParams;
+ bool SeenInt = false;
+ while (Lex.getKind() == lltok::comma) {
+ Lex.Lex(); // Eat the comma.
+
+ if (Lex.getKind() == lltok::APSInt) {
+ SeenInt = true;
+ unsigned IntVal;
+ if (parseUInt32(IntVal))
+ return true;
+ IntParams.push_back(IntVal);
+ } else if (SeenInt) {
+ // The only other kind of parameter we support is type parameters, which
+ // must precede the integer parameters. This is therefore an error.
+ return tokError("expected uint32 param");
+ } else {
+ Type *TypeParam;
+ if (parseType(TypeParam, /*AllowVoid=*/true))
+ return true;
+ TypeParams.push_back(TypeParam);
+ }
+ }
+
+ if (parseToken(lltok::rparen, "expected ')' in target extension type"))
+ return true;
+
+ Result = TargetExtType::get(Context, TypeName, TypeParams, IntParams);
+ return false;
+}
+
//===----------------------------------------------------------------------===//
// Function Semantic Analysis.
//===----------------------------------------------------------------------===//
@@ -5694,6 +5754,9 @@ bool LLParser::convertValIDToValue(Type *Ty, ValID &ID, Value *&V,
// FIXME: LabelTy should not be a first-class type.
if (!Ty->isFirstClassType() || Ty->isLabelTy())
return error(ID.Loc, "invalid type for null constant");
+ if (auto *TETy = dyn_cast<TargetExtType>(Ty))
+ if (!TETy->hasProperty(TargetExtType::HasZeroInit))
+ return error(ID.Loc, "invalid type for null constant");
V = Constant::getNullValue(Ty);
return false;
case ValID::t_None:
diff --git a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
index a2de984fe0406..d8f6859ca185e 100644
--- a/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
+++ b/llvm/lib/Bitcode/Reader/BitcodeReader.cpp
@@ -2486,6 +2486,35 @@ Error BitcodeReader::parseTypeTableBody() {
ResultTy = Res;
break;
}
+ case bitc::TYPE_CODE_TARGET_TYPE: { // TARGET_TYPE: [NumTy, Tys..., Ints...]
+ if (Record.size() < 1)
+ return error("Invalid target extension type record");
+
+ if (NumRecords >= TypeList.size())
+ return error("Invalid TYPE table");
+
+ if (Record[0] >= Record.size())
+ return error("Too many type parameters");
+
+ unsigned NumTys = Record[0];
+ SmallVector<Type *, 4> TypeParams;
+ SmallVector<unsigned, 8> IntParams;
+ for (unsigned i = 0; i < NumTys; i++) {
+ if (Type *T = getTypeByID(Record[i + 1]))
+ TypeParams.push_back(T);
+ else
+ return error("Invalid type");
+ }
+
+ for (unsigned i = NumTys + 1, e = Record.size(); i < e; i++) {
+ if (Record[i] > UINT_MAX)
+ return error("Integer parameter too large");
+ IntParams.push_back(Record[i]);
+ }
+ ResultTy = TargetExtType::get(Context, TypeName, TypeParams, IntParams);
+ TypeName.clear();
+ break;
+ }
case bitc::TYPE_CODE_ARRAY: // ARRAY: [numelts, eltty]
if (Record.size() < 2)
return error("Invalid array type record");
@@ -2989,6 +3018,9 @@ Error BitcodeReader::parseConstants() {
case bitc::CST_CODE_NULL: // NULL
if (CurTy->isVoidTy() || CurTy->isFunctionTy() || CurTy->isLabelTy())
return error("Invalid type for a constant null value");
+ if (auto *TETy = dyn_cast<TargetExtType>(CurTy))
+ if (!TETy->hasProperty(TargetExtType::HasZeroInit))
+ return error("Invalid type for a constant null value");
V = Constant::getNullValue(CurTy);
break;
case bitc::CST_CODE_INTEGER: // INTEGER: [intval]
diff --git a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
index 339fae04b9837..26994b1d9afd1 100644
--- a/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
+++ b/llvm/lib/Bitcode/Writer/BitcodeWriter.cpp
@@ -1052,6 +1052,18 @@ void ModuleBitcodeWriter::writeTypeTable() {
TypeVals.push_back(true);
break;
}
+ case Type::TargetExtTyID: {
+ TargetExtType *TET = cast<TargetExtType>(T);
+ Code = bitc::TYPE_CODE_TARGET_TYPE;
+ writeStringRecord(Stream, bitc::TYPE_CODE_STRUCT_NAME, TET->getName(),
+ StructNameAbbrev);
+ TypeVals.push_back(TET->getNumTypeParameters());
+ for (Type *InnerTy : TET->type_params())
+ TypeVals.push_back(VE.getTypeID(InnerTy));
+ for (unsigned IntParam : TET->int_params())
+ TypeVals.push_back(IntParam);
+ break;
+ }
case Type::TypedPointerTyID:
llvm_unreachable("Typed pointers cannot be added to IR modules");
}
diff --git a/llvm/lib/IR/AsmWriter.cpp b/llvm/lib/IR/AsmWriter.cpp
index 1b555f056d24d..b1ec4848076e1 100644
--- a/llvm/lib/IR/AsmWriter.cpp
+++ b/llvm/lib/IR/AsmWriter.cpp
@@ -622,6 +622,17 @@ void TypePrinting::print(Type *Ty, raw_ostream &OS) {
<< TPTy->getAddressSpace() << ")";
return;
}
+ case Type::TargetExtTyID:
+ TargetExtType *TETy = cast<TargetExtType>(Ty);
+ OS << "target(\"";
+ printEscapedString(Ty->getTargetExtName(), OS);
+ OS << "\"";
+ for (Type *Inner : TETy->type_params())
+ OS << ", " << *Inner;
+ for (unsigned IntParam : TETy->int_params())
+ OS << ", " << IntParam;
+ OS << ")";
+ return;
}
llvm_unreachable("Invalid TypeID");
}
@@ -1438,7 +1449,7 @@ static void WriteConstantInternal(raw_ostream &Out, const Constant *CV,
return;
}
- if (isa<ConstantAggregateZero>(CV)) {
+ if (isa<ConstantAggregateZero>(CV) || isa<ConstantTargetNone>(CV)) {
Out << "zeroinitializer";
return;
}
diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp
index b7126adb9f4c1..9c8e2995b995b 100644
--- a/llvm/lib/IR/Constants.cpp
+++ b/llvm/lib/IR/Constants.cpp
@@ -87,7 +87,7 @@ bool Constant::isNullValue() const {
// constant zero is zero for aggregates, cpnull is null for pointers, none for
// tokens.
return isa<ConstantAggregateZero>(this) || isa<ConstantPointerNull>(this) ||
- isa<ConstantTokenNone>(this);
+ isa<ConstantTokenNone>(this) || isa<ConstantTargetNone>(this);
}
bool Constant::isAllOnesValue() const {
@@ -369,6 +369,8 @@ Constant *Constant::getNullValue(Type *Ty) {
return ConstantAggregateZero::get(Ty);
case Type::TokenTyID:
return ConstantTokenNone::get(Ty->getContext());
+ case Type::TargetExtTyID:
+ return ConstantTargetNone::get(cast<TargetExtType>(Ty));
default:
// Function, Label, or Opaque type?
llvm_unreachable("Cannot create a null constant of that type!");
@@ -1710,6 +1712,25 @@ void ConstantPointerNull::destroyConstantImpl() {
getContext().pImpl->CPNConstants.erase(getType());
}
+//---- ConstantTargetNone::get() implementation.
+//
+
+ConstantTargetNone *ConstantTargetNone::get(TargetExtType *Ty) {
+ assert(Ty->hasProperty(TargetExtType::HasZeroInit) &&
+ "Target extension type not allowed to have a zeroinitializer");
+ std::unique_ptr<ConstantTargetNone> &Entry =
+ Ty->getContext().pImpl->CTNConstants[Ty];
+ if (!Entry)
+ Entry.reset(new ConstantTargetNone(Ty));
+
+ return Entry.get();
+}
+
+/// Remove the constant from the constant table.
+void ConstantTargetNone::destroyConstantImpl() {
+ getContext().pImpl->CTNConstants.erase(getType());
+}
+
UndefValue *UndefValue::get(Type *Ty) {
std::unique_ptr<UndefValue> &Entry = Ty->getContext().pImpl->UVConstants[Ty];
if (!Entry)
diff --git a/llvm/lib/IR/Core.cpp b/llvm/lib/IR/Core.cpp
index 7a34684db4257..984047949d190 100644
--- a/llvm/lib/IR/Core.cpp
+++ b/llvm/lib/IR/Core.cpp
@@ -540,6 +540,8 @@ LLVMTypeKind LLVMGetTypeKind(LLVMTypeRef Ty) {
return LLVMTokenTypeKind;
case Type::ScalableVectorTyID:
return LLVMScalableVectorTypeKind;
+ case Type::TargetExtTyID:
+ return LLVMTargetExtTypeKind;
case Type::TypedPointerTyID:
llvm_unreachable("Typed pointers are unsupported via the C API");
}
@@ -858,6 +860,17 @@ LLVMTypeRef LLVMLabelType(void) {
return LLVMLabelTypeInContext(LLVMGetGlobalContext());
}
+LLVMTypeRef LLVMTargetExtTypeInContext(LLVMContextRef C, const char *Name,
+ LLVMTypeRef *TypeParams,
+ unsigned TypeParamCount,
+ unsigned *IntParams,
+ unsigned IntParamCount) {
+ ArrayRef<Type *> TypeParamArray(unwrap(TypeParams), TypeParamCount);
+ ArrayRef<unsigned> IntParamArray(IntParams, IntParamCount);
+ return wrap(
+ TargetExtType::get(*unwrap(C), Name, TypeParamArray, IntParamArray));
+}
+
/*===-- Operations on values ----------------------------------------------===*/
/*--.. Operations on all values ............................................--*/
diff --git a/llvm/lib/IR/DataLayout.cpp b/llvm/lib/IR/DataLayout.cpp
index 4bd088714d4bf..fb331eec602d8 100644
--- a/llvm/lib/IR/DataLayout.cpp
+++ b/llvm/lib/IR/DataLayout.cpp
@@ -816,6 +816,10 @@ Align DataLayout::getAlignment(Type *Ty, bool abi_or_pref) const {
}
case Type::X86_AMXTyID:
return Align(64);
+ case Type::TargetExtTyID: {
+ Type *LayoutTy = cast<TargetExtType>(Ty)->getLayoutType();
+ return getAlignment(LayoutTy, abi_or_pref);
+ }
default:
llvm_unreachable("Bad type for getAlignment!!!");
}
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index cd66eeb3ec47e..c39e3ea40c3fb 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -941,6 +941,15 @@ static std::string getMangledTypeStr(Type *Ty, bool &HasUnnamedType) {
Result += "nx";
Result += "v" + utostr(EC.getKnownMinValue()) +
getMangledTypeStr(VTy->getElementType(), HasUnnamedType);
+ } else if (TargetExtType *TETy = dyn_cast<TargetExtType>(Ty)) {
+ Result += "t";
+ Result += TETy->getName();
+ for (Type *ParamTy : TETy->type_params())
+ Result += "_" + getMangledTypeStr(ParamTy, HasUnnamedType);
+ for (unsigned IntParam : TETy->int_params())
+ Result += "_" + utostr(IntParam);
+ // Ensure nested target extension types are distinguishable.
+ Result += "t";
} else if (Ty) {
switch (Ty->getTypeID()) {
default: llvm_unreachable("Unhandled type");
diff --git a/llvm/lib/IR/LLVMContextImpl.cpp b/llvm/lib/IR/LLVMContextImpl.cpp
index e3917f12d2413..cd46a04a684b0 100644
--- a/llvm/lib/IR/LLVMContextImpl.cpp
+++ b/llvm/lib/IR/LLVMContextImpl.cpp
@@ -113,6 +113,7 @@ LLVMContextImpl::~LLVMContextImpl() {
CAZConstants.clear();
CPNConstants.clear();
+ CTNConstants.clear();
UVConstants.clear();
PVConstants.clear();
IntConstants.clear();
diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h
index 5a87a025e3c39..e5d9b39261ed0 100644
--- a/llvm/lib/IR/LLVMContextImpl.h
+++ b/llvm/lib/IR/LLVMContextImpl.h
@@ -190,6 +190,55 @@ struct FunctionTypeKeyInfo {
}
};
+struct TargetExtTypeKeyInfo {
+ struct KeyTy {
+ StringRef Name;
+ ArrayRef<Type *> TypeParams;
+ ArrayRef<unsigned> IntParams;
+
+ KeyTy(StringRef N, const ArrayRef<Type *> &TP, const ArrayRef<unsigned> &IP)
+ : Name(N), TypeParams(TP), IntParams(IP) {}
+ KeyTy(const TargetExtType *TT)
+ : Name(TT->getName()), TypeParams(TT->type_params()),
+ IntParams(TT->int_params()) {}
+
+ bool operator==(const KeyTy &that) const {
+ return Name == that.Name && TypeParams == that.TypeParams &&
+ IntParams == that.IntParams;
+ }
+ bool operator!=(const KeyTy &that) const { return !this->operator==(that); }
+ };
+
+ static inline TargetExtType *getEmptyKey() {
+ return DenseMapInfo<TargetExtType *>::getEmptyKey();
+ }
+
+ static inline TargetExtType *getTombstoneKey() {
+ return DenseMapInfo<TargetExtType *>::getTombstoneKey();
+ }
+
+ static unsigned getHashValue(const KeyTy &Key) {
+ return hash_combine(
+ Key.Name,
+ hash_combine_range(Key.TypeParams.begin(), Key.TypeParams.end()),
+ hash_combine_range(Key.IntParams.begin(), Key.IntParams.end()));
+ }
+
+ static unsigned getHashValue(const TargetExtType *FT) {
+ return getHashValue(KeyTy(FT));
+ }
+
+ static bool isEqual(const KeyTy &LHS, const TargetExtType *RHS) {
+ if (RHS == getEmptyKey() || RHS == getTombstoneKey())
+ return false;
+ return LHS == KeyTy(RHS);
+ }
+
+ static bool isEqual(const TargetExtType *LHS, const TargetExtType *RHS) {
+ return LHS == RHS;
+ }
+};
+
/// Structure for hashing arbitrary MDNode operands.
class MDNodeOpsKey {
ArrayRef<Metadata *> RawOps;
@@ -1439,6 +1488,8 @@ class LLVMContextImpl {
DenseMap<PointerType *, std::unique_ptr<ConstantPointerNull>> CPNConstants;
+ DenseMap<TargetExtType *, std::unique_ptr<ConstantTargetNone>> CTNConstants;
+
DenseMap<Type *, std::unique_ptr<UndefValue>> UVConstants;
DenseMap<Type *, std::unique_ptr<PoisonValue>> PVConstants;
@@ -1479,6 +1530,9 @@ class LLVMContextImpl {
StringMap<StructType *> NamedStructTypes;
unsigned NamedStructTypesUniqueID = 0;
+ using TargetExtTypeSet = DenseSet<TargetExtType *, TargetExtTypeKeyInfo>;
+ TargetExtTypeSet TargetExtTypes;
+
DenseMap<std::pair<Type *, uint64_t>, ArrayType *> ArrayTypes;
DenseMap<std::pair<Type *, ElementCount>, VectorType *> VectorTypes;
DenseMap<Type *, PointerType *> PointerTypes; // Pointers in AddrSpace = 0
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 311be6939e5a2..291f4f968a257 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -211,6 +211,9 @@ bool Type::isSizedDerivedType(SmallPtrSetImpl<Type*> *Visited) const {
if (auto *VTy = dyn_cast<VectorType>(this))
return VTy->getElementType()->isSized(Visited);
+ if (auto *TTy = dyn_cast<TargetExtType>(this))
+ return TTy->getLayoutType()->isSized(Visited);
+
return cast<StructType>(this)->isSized(Visited);
}
@@ -783,3 +786,82 @@ bool PointerType::isValidElementType(Type *ElemTy) {
bool PointerType::isLoadableOrStorableType(Type *ElemTy) {
return isValidElementType(ElemTy) && !ElemTy->isFunctionTy();
}
+
+//===----------------------------------------------------------------------===//
+// TargetExtType Implementation
+//===----------------------------------------------------------------------===//
+
+TargetExtType::TargetExtType(LLVMContext &C, StringRef Name,
+ ArrayRef<Type *> Types, ArrayRef<unsigned> Ints)
+ : Type(C, TargetExtTyID), Name(Name) {
+ NumContainedTys = Types.size();
+
+ // Parameter storage immediately follows the class in allocation.
+ Type **Params = reinterpret_cast<Type **>(this + 1);
+ ContainedTys = Params;
+ for (Type *T : Types)
+ *Params++ = T;
+
+ setSubclassData(Ints.size());
+ unsigned *IntParamSpace = reinterpret_cast<unsigned *>(Params);
+ IntParams = IntParamSpace;
+ for (unsigned IntParam : Ints)
+ *IntParamSpace++ = IntParam;
+}
+
+TargetExtType *TargetExtType::get(LLVMContext &C, StringRef Name,
+ ArrayRef<Type *> Types,
+ ArrayRef<unsigned> Ints) {
+ const TargetExtTypeKeyInfo::KeyTy Key(Name, Types, Ints);
+ TargetExtType *TT;
+ // Since we only want to allocate a fresh target type in case none is found
+ // and we don't want to perform two lookups (one for checking if existent and
+ // one for inserting the newly allocated one), here we instead lookup based on
+ // Key and update the reference to the target type in-place to a newly
+ // allocated one if not found.
+ auto Insertion = C.pImpl->TargetExtTypes.insert_as(nullptr, Key);
+ if (Insertion.second) {
+ // The target type was not found. Allocate one and update TargetExtTypes
+ // in-place.
+ TT = (TargetExtType *)C.pImpl->Alloc.Allocate(
+ sizeof(TargetExtType) + sizeof(Type *) * Types.size() +
+ sizeof(unsigned) * Ints.size(),
+ alignof(TargetExtType));
+ new (TT) TargetExtType(C, Name, Types, Ints);
+ *Insertion.first = TT;
+ } else {
+ // The target type was found. Just return it.
+ TT = *Insertion.first;
+ }
+ return TT;
+}
+
+namespace {
+struct TargetTypeInfo {
+ Type *LayoutType;
+ uint64_t Properties;
+
+ template <typename... ArgTys>
+ TargetTypeInfo(Type *LayoutType, ArgTys... Properties)
+ : LayoutType(LayoutType), Properties((0 | ... | Properties)) {}
+};
+} // anonymous namespace
+
+static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
+ LLVMContext &C = Ty->getContext();
+ StringRef Name = Ty->getName();
+ if (Name.startswith("spirv.")) {
+ return TargetTypeInfo(Type::getInt8PtrTy(C, 0), TargetExtType::HasZeroInit,
+ TargetExtType::CanBeGlobal);
+ }
+ return TargetTypeInfo(Type::getVoidTy(C));
+}
+
+Type *TargetExtType::getLayoutType() const {
+ return getTargetTypeInfo(this).LayoutType;
+}
+
+bool TargetExtType::hasProperty(Property Prop) const {
+ uint64_t Properties = getTargetTypeInfo(this).Properties;
+ return (Properties & Prop) == Prop;
+}
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 69029f365e797..4e05ecb3538f9 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -798,6 +798,13 @@ void Verifier::visitGlobalVariable(const GlobalVariable &GV) {
Check(!STy->containsScalableVectorType(),
"Globals cannot contain scalable vectors", &GV);
+ // Check if it's a target extension type that disallows being used as a
+ // global.
+ if (auto *TTy = dyn_cast<TargetExtType>(GV.getValueType()))
+ Check(TTy->hasProperty(TargetExtType::CanBeGlobal),
+ "Global @" + GV.getName() + " has illegal target extension type",
+ TTy);
+
if (!GV.hasInitializer()) {
visitGlobalValue(GV);
return;
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 748b8627be7ed..1bea80b69bc52 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -1942,6 +1942,9 @@ static bool canConvertValue(const DataLayout &DL, Type *OldTy, Type *NewTy) {
return false;
}
+ if (OldTy->isTargetExtTy() || NewTy->isTargetExtTy())
+ return false;
+
return true;
}
diff --git a/llvm/lib/Transforms/Utils/VNCoercion.cpp b/llvm/lib/Transforms/Utils/VNCoercion.cpp
index 264da2187754a..d179b8b5fcccc 100644
--- a/llvm/lib/Transforms/Utils/VNCoercion.cpp
+++ b/llvm/lib/Transforms/Utils/VNCoercion.cpp
@@ -57,10 +57,13 @@ bool canCoerceMustAliasedValueToLoad(Value *StoredVal, Type *LoadTy,
// The implementation below uses inttoptr for vectors of unequal size; we
// can't allow this for non integral pointers. We could teach it to extract
- // exact subvectors if desired.
+ // exact subvectors if desired.
if (StoredNI && StoreSize != DL.getTypeSizeInBits(LoadTy).getFixedSize())
return false;
+ if (StoredTy->isTargetExtTy() || LoadTy->isTargetExtTy())
+ return false;
+
return true;
}
diff --git a/llvm/test/Assembler/invalid-target-type-mixed.ll b/llvm/test/Assembler/invalid-target-type-mixed.ll
new file mode 100644
index 0000000000000..63adc22fc3581
--- /dev/null
+++ b/llvm/test/Assembler/invalid-target-type-mixed.ll
@@ -0,0 +1,6 @@
+; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s
+
+; CHECK: expected uint32 param
+define void @f(target("type", i32, 0, void) %a) {
+ ret void
+}
diff --git a/llvm/test/Assembler/target-type-mangled.ll b/llvm/test/Assembler/target-type-mangled.ll
new file mode 100644
index 0000000000000..4beae49334c2d
--- /dev/null
+++ b/llvm/test/Assembler/target-type-mangled.ll
@@ -0,0 +1,11 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; Check support for mangling of target extension types in intrinsics
+
+declare target("a", target("b")) @llvm.ssa.copy.ta_tbtt(target("a", target("b")) returned)
+declare target("a", void, i8, 5, 3) @llvm.ssa.copy.ta_isVoid_i8_5_3t(target("a", void, i8, 5, 3) returned)
+declare target("b") @llvm.ssa.copy.tbt(target("b") returned)
+
+; CHECK: declare target("a", target("b")) @llvm.ssa.copy.ta_tbtt(target("a", target("b")) returned)
+; CHECK: declare target("a", void, i8, 5, 3) @llvm.ssa.copy.ta_isVoid_i8_5_3t(target("a", void, i8, 5, 3) returned)
+; CHECK: declare target("b") @llvm.ssa.copy.tbt(target("b") returned)
+
diff --git a/llvm/test/Assembler/target-type-params.ll b/llvm/test/Assembler/target-type-params.ll
new file mode 100644
index 0000000000000..de7bf8265b6b7
--- /dev/null
+++ b/llvm/test/Assembler/target-type-params.ll
@@ -0,0 +1,16 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; Check support for basic target extension type properties
+
+declare void @g1(target("atype", void))
+declare void @g2(target("atype", i32))
+declare void @g3(target("atype", i32, 0))
+declare void @g4(target("atype", 0))
+declare void @g5(target("atype", 0, 1, 2))
+declare void @g6(target("atype", void, i32, float, {i32, bfloat}, 0, 1, 2))
+
+;CHECK: declare void @g1(target("atype", void))
+;CHECK: declare void @g2(target("atype", i32))
+;CHECK: declare void @g3(target("atype", i32, 0))
+;CHECK: declare void @g4(target("atype", 0))
+;CHECK: declare void @g5(target("atype", 0, 1, 2))
+;CHECK: declare void @g6(target("atype", void, i32, float, { i32, bfloat }, 0, 1, 2))
diff --git a/llvm/test/Assembler/target-type-properties.ll b/llvm/test/Assembler/target-type-properties.ll
new file mode 100644
index 0000000000000..49c9d812f1cf4
--- /dev/null
+++ b/llvm/test/Assembler/target-type-properties.ll
@@ -0,0 +1,16 @@
+; RUN: split-file %s %t
+; RUN: not llvm-as < %t/zeroinit-error.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-ZEROINIT %s
+; RUN: not llvm-as < %t/global-var.ll -o /dev/null 2>&1 | FileCheck --check-prefix=CHECK-GLOBALVAR %s
+; Check target extension type properties are verified in the assembler.
+
+;--- zeroinit-error.ll
+define void @foo() {
+ %val = freeze target("spirv.DeviceEvent") zeroinitializer
+ %val2 = freeze target("unknown_target_type") zeroinitializer
+; CHECK-ZEROINIT: error: invalid type for null constant
+ ret void
+}
+
+;--- global-var.ll
+ at global = external global target("unknown_target_type")
+; CHECK-GLOBALVAR: Global @global has illegal target extension type
diff --git a/llvm/test/Assembler/target-types.ll b/llvm/test/Assembler/target-types.ll
new file mode 100644
index 0000000000000..741a1a1596784
--- /dev/null
+++ b/llvm/test/Assembler/target-types.ll
@@ -0,0 +1,24 @@
+; RUN: llvm-as < %s | llvm-dis | FileCheck %s
+; Check support for basic target extension type usage
+
+ at global = global target("spirv.DeviceEvent") zeroinitializer
+
+define target("spirv.Sampler") @foo(target("spirv.Sampler") %a) {
+ ret target("spirv.Sampler") %a
+}
+
+define target("spirv.Event") @func2() {
+ %mem = alloca target("spirv.Event")
+ %val = load target("spirv.Event"), ptr %mem
+ ret target("spirv.Event") poison
+}
+
+; CHECK: @global = global target("spirv.DeviceEvent") zeroinitializer
+; CHECK: define target("spirv.Sampler") @foo(target("spirv.Sampler") %a) {
+; CHECK: ret target("spirv.Sampler") %a
+; CHECK: }
+; CHECK: define target("spirv.Event") @func2() {
+; CHECK: %mem = alloca target("spirv.Event")
+; CHECK: %val = load target("spirv.Event"), ptr %mem
+; CHECK: ret target("spirv.Event") poison
+; CHECK: }
diff --git a/llvm/test/Transforms/GVN/target-type.ll b/llvm/test/Transforms/GVN/target-type.ll
new file mode 100644
index 0000000000000..79305218648f0
--- /dev/null
+++ b/llvm/test/Transforms/GVN/target-type.ll
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=gvn < %s | FileCheck %s
+
+; Check that GVN can work with target extension types correctly.
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
+
+define target("spirv.DeviceEvent") @basic_alloc(target("spirv.DeviceEvent") %arg) {
+; CHECK-LABEL: @basic_alloc(
+; CHECK-NEXT: [[VAL:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: store target("spirv.DeviceEvent") [[ARG:%.*]], ptr [[VAL]], align 8
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[ARG]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ store target("spirv.DeviceEvent") %arg, ptr %val
+ %ret = load target("spirv.DeviceEvent"), ptr %val
+ ret target("spirv.DeviceEvent") %ret
+}
+
+define target("spirv.DeviceEvent") @nobitcast(ptr %arg) {
+; CHECK-LABEL: @nobitcast(
+; CHECK-NEXT: [[VAL:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: store ptr [[ARG:%.*]], ptr [[VAL]], align 8
+; CHECK-NEXT: [[RET:%.*]] = load target("spirv.DeviceEvent"), ptr [[VAL]], align 8
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[RET]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ store ptr %arg, ptr %val
+ %ret = load target("spirv.DeviceEvent"), ptr %val
+ ret target("spirv.DeviceEvent") %ret
+}
+
+define target("spirv.DeviceEvent") @viai64(target("spirv.DeviceEvent") %arg) {
+; CHECK-LABEL: @viai64(
+; CHECK-NEXT: [[VAL:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: [[BAR:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: store target("spirv.DeviceEvent") [[ARG:%.*]], ptr [[VAL]], align 8
+; CHECK-NEXT: [[IMEMCPY:%.*]] = load i64, ptr [[VAL]], align 4
+; CHECK-NEXT: store i64 [[IMEMCPY]], ptr [[BAR]], align 4
+; CHECK-NEXT: [[RET:%.*]] = load target("spirv.DeviceEvent"), ptr [[BAR]], align 8
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[RET]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ %bar = alloca target("spirv.DeviceEvent")
+ store target("spirv.DeviceEvent") %arg, ptr %val
+ %imemcpy = load i64, ptr %val
+ store i64 %imemcpy, ptr %bar
+ %ret = load target("spirv.DeviceEvent"), ptr %bar
+ ret target("spirv.DeviceEvent") %ret
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
diff --git a/llvm/test/Transforms/SROA/sroa-target.ll b/llvm/test/Transforms/SROA/sroa-target.ll
new file mode 100644
index 0000000000000..014baf93e5dea
--- /dev/null
+++ b/llvm/test/Transforms/SROA/sroa-target.ll
@@ -0,0 +1,62 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt -S -passes=sroa < %s | FileCheck %s
+
+; Check that SROA can work with target extension types correctly.
+
+target datalayout = "e-p:64:64:64-p1:16:16:16-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-n8:16:32:64"
+
+define target("spirv.DeviceEvent") @basic_alloc(target("spirv.DeviceEvent") %arg) {
+; CHECK-LABEL: @basic_alloc(
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[ARG:%.*]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ store target("spirv.DeviceEvent") %arg, ptr %val
+ %ret = load target("spirv.DeviceEvent"), ptr %val
+ ret target("spirv.DeviceEvent") %ret
+}
+
+define target("spirv.DeviceEvent") @via_memcpy(target("spirv.DeviceEvent") %arg) {
+; CHECK-LABEL: @via_memcpy(
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[ARG:%.*]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ %bar = alloca target("spirv.DeviceEvent")
+ store target("spirv.DeviceEvent") %arg, ptr %val
+ call void @llvm.memcpy.p0.p0.i64(ptr %bar, ptr %val, i64 8, i1 false)
+ %ret = load target("spirv.DeviceEvent"), ptr %bar
+ ret target("spirv.DeviceEvent") %ret
+}
+
+define target("spirv.DeviceEvent") @nobitcast(ptr %arg) {
+; CHECK-LABEL: @nobitcast(
+; CHECK-NEXT: [[VAL:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: store ptr [[ARG:%.*]], ptr [[VAL]], align 8
+; CHECK-NEXT: [[VAL_0_RET:%.*]] = load target("spirv.DeviceEvent"), ptr [[VAL]], align 8
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[VAL_0_RET]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ store ptr %arg, ptr %val
+ %ret = load target("spirv.DeviceEvent"), ptr %val
+ ret target("spirv.DeviceEvent") %ret
+}
+
+define target("spirv.DeviceEvent") @viai64(target("spirv.DeviceEvent") %arg) {
+; CHECK-LABEL: @viai64(
+; CHECK-NEXT: [[VAL:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: [[BAR:%.*]] = alloca target("spirv.DeviceEvent"), align 8
+; CHECK-NEXT: store target("spirv.DeviceEvent") [[ARG:%.*]], ptr [[VAL]], align 8
+; CHECK-NEXT: [[VAL_0_IMEMCPY:%.*]] = load i64, ptr [[VAL]], align 8
+; CHECK-NEXT: store i64 [[VAL_0_IMEMCPY]], ptr [[BAR]], align 8
+; CHECK-NEXT: [[BAR_0_RET:%.*]] = load target("spirv.DeviceEvent"), ptr [[BAR]], align 8
+; CHECK-NEXT: ret target("spirv.DeviceEvent") [[BAR_0_RET]]
+;
+ %val = alloca target("spirv.DeviceEvent")
+ %bar = alloca target("spirv.DeviceEvent")
+ store target("spirv.DeviceEvent") %arg, ptr %val
+ %imemcpy = load i64, ptr %val
+ store i64 %imemcpy, ptr %bar
+ %ret = load target("spirv.DeviceEvent"), ptr %bar
+ ret target("spirv.DeviceEvent") %ret
+}
+
+declare void @llvm.memcpy.p0.p0.i64(ptr, ptr, i64, i1)
diff --git a/llvm/tools/llvm-c-test/echo.cpp b/llvm/tools/llvm-c-test/echo.cpp
index 9a5d5d6820276..7a54e264103e7 100644
--- a/llvm/tools/llvm-c-test/echo.cpp
+++ b/llvm/tools/llvm-c-test/echo.cpp
@@ -159,6 +159,8 @@ struct TypeCloner {
return LLVMX86MMXTypeInContext(Ctx);
case LLVMTokenTypeKind:
return LLVMTokenTypeInContext(Ctx);
+ case LLVMTargetExtTypeKind:
+ assert(false && "Implement me");
}
fprintf(stderr, "%d is not a supported typekind\n", Kind);
diff --git a/llvm/unittests/IR/TypesTest.cpp b/llvm/unittests/IR/TypesTest.cpp
index 83fd55919fe7b..2944957a8b64a 100644
--- a/llvm/unittests/IR/TypesTest.cpp
+++ b/llvm/unittests/IR/TypesTest.cpp
@@ -61,6 +61,17 @@ TEST(TypesTest, CopyPointerType) {
EXPECT_FALSE(P2C0->isOpaque());
}
+TEST(TypesTest, TargetExtType) {
+ LLVMContext Context;
+ Type *A = TargetExtType::get(Context, "typea");
+ Type *Aparam = TargetExtType::get(Context, "typea", {}, {0, 1});
+ Type *Aparam2 = TargetExtType::get(Context, "typea", {}, {0, 1});
+ // Opaque types with same parameters are identical...
+ EXPECT_EQ(Aparam, Aparam2);
+ // ... but just having the same name is not enough.
+ EXPECT_NE(A, Aparam);
+}
+
TEST(TypedPointerType, PrintTest) {
std::string Buffer;
LLVMContext Context;
More information about the llvm-commits
mailing list