Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -2413,6 +2413,9 @@ **Null pointer constants** The identifier '``null``' is recognized as a null pointer constant and must be of :ref:`pointer type `. +**Token constants** + The identifier '``none``' is recognized as an empty token constant + and must be of :ref:`token type `. The one non-intuitive notation for constants is the hexadecimal form of floating point constants. For example, the form Index: include/llvm-c/Core.h =================================================================== --- include/llvm-c/Core.h +++ include/llvm-c/Core.h @@ -1185,6 +1185,7 @@ macro(ConstantInt) \ macro(ConstantPointerNull) \ macro(ConstantStruct) \ + macro(ConstantTokenNone) \ macro(ConstantVector) \ macro(GlobalValue) \ macro(GlobalAlias) \ Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -795,7 +795,32 @@ } }; +//===----------------------------------------------------------------------===// +/// ConstantTokenNone - a constant token which is empty +/// +class ConstantTokenNone : public Constant { + void *operator new(size_t, unsigned) = delete; + ConstantTokenNone(const ConstantTokenNone &) = delete; + + friend class Constant; + void destroyConstantImpl(); + Value *handleOperandChangeImpl(Value *From, Value *To, Use *U); + +protected: + explicit ConstantTokenNone(LLVMContext &Context) + : Constant(Type::getTokenTy(Context), ConstantTokenNoneVal, nullptr, 0) {} + // allocate space for exactly zero operands + void *operator new(size_t s) { return User::operator new(s, 0); } + +public: + /// Return the ConstantTokenNone. + static ConstantTokenNone *get(LLVMContext &Context); + /// @brief Methods to support type inquiry through isa, cast, and dyn_cast. + static bool classof(const Value *V) { + return V->getValueID() == ConstantTokenNoneVal; + } +}; /// BlockAddress - The address of a basic block. /// Index: include/llvm/IR/Value.def =================================================================== --- include/llvm/IR/Value.def +++ include/llvm/IR/Value.def @@ -70,6 +70,7 @@ HANDLE_CONSTANT(ConstantStruct) HANDLE_CONSTANT(ConstantVector) HANDLE_CONSTANT(ConstantPointerNull) +HANDLE_CONSTANT(ConstantTokenNone) HANDLE_METADATA_VALUE(MetadataAsValue) HANDLE_INLINE_ASM_VALUE(InlineAsm) @@ -79,7 +80,7 @@ // don't add new values here! HANDLE_CONSTANT_MARKER(ConstantFirstVal, Function) -HANDLE_CONSTANT_MARKER(ConstantLastVal, ConstantPointerNull) +HANDLE_CONSTANT_MARKER(ConstantLastVal, ConstantTokenNone) #undef HANDLE_GLOBAL_VALUE #undef HANDLE_CONSTANT Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -523,6 +523,7 @@ KEYWORD(zeroinitializer); KEYWORD(undef); KEYWORD(null); + KEYWORD(none); KEYWORD(to); KEYWORD(caller); KEYWORD(tail); Index: lib/AsmParser/LLParser.h =================================================================== --- lib/AsmParser/LLParser.h +++ lib/AsmParser/LLParser.h @@ -46,15 +46,15 @@ /// or a symbolic (%var) reference. This is just a discriminated union. struct ValID { enum { - t_LocalID, t_GlobalID, // ID in UIntVal. - t_LocalName, t_GlobalName, // Name in StrVal. - t_APSInt, t_APFloat, // Value in APSIntVal/APFloatVal. - t_Null, t_Undef, t_Zero, // No value. - t_EmptyArray, // No value: [] - t_Constant, // Value in ConstantVal. - t_InlineAsm, // Value in FTy/StrVal/StrVal2/UIntVal. - t_ConstantStruct, // Value in ConstantStructElts. - t_PackedConstantStruct // Value in ConstantStructElts. + t_LocalID, t_GlobalID, // ID in UIntVal. + t_LocalName, t_GlobalName, // Name in StrVal. + t_APSInt, t_APFloat, // Value in APSIntVal/APFloatVal. + t_Null, t_Undef, t_Zero, t_None, // No value. + t_EmptyArray, // No value: [] + t_Constant, // Value in ConstantVal. + t_InlineAsm, // Value in FTy/StrVal/StrVal2/UIntVal. + t_ConstantStruct, // Value in ConstantStructElts. + t_PackedConstantStruct // Value in ConstantStructElts. } Kind = t_LocalID; LLLexer::LocTy Loc; Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -2622,6 +2622,7 @@ case lltok::kw_null: ID.Kind = ValID::t_Null; break; case lltok::kw_undef: ID.Kind = ValID::t_Undef; break; case lltok::kw_zeroinitializer: ID.Kind = ValID::t_Zero; break; + case lltok::kw_none: ID.Kind = ValID::t_None; break; case lltok::lbrace: { // ValID ::= '{' ConstVector '}' @@ -4255,6 +4256,11 @@ return Error(ID.Loc, "invalid type for null constant"); V = Constant::getNullValue(Ty); return false; + case ValID::t_None: + if (!Ty->isTokenTy()) + return Error(ID.Loc, "invalid type for none constant"); + V = Constant::getNullValue(Ty); + return false; case ValID::t_Constant: if (ID.ConstantVal->getType() != Ty) return Error(ID.Loc, "constant expression type mismatch"); Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -49,7 +49,7 @@ kw_external, kw_thread_local, kw_localdynamic, kw_initialexec, kw_localexec, kw_zeroinitializer, - kw_undef, kw_null, + kw_undef, kw_null, kw_none, kw_to, kw_caller, kw_tail, Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -1328,6 +1328,11 @@ return; } + if (isa(CV)) { + Out << "none"; + return; + } + if (isa(CV)) { Out << "undef"; return; Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -81,8 +81,10 @@ if (const ConstantFP *CFP = dyn_cast(this)) return CFP->isZero() && !CFP->isNegative(); - // constant zero is zero for aggregates and cpnull is null for pointers. - return isa(this) || isa(this); + // constant zero is zero for aggregates, cpnull is null for pointers, none for + // tokens. + return isa(this) || isa(this) || + isa(this); } bool Constant::isAllOnesValue() const { @@ -204,6 +206,8 @@ case Type::ArrayTyID: case Type::VectorTyID: return ConstantAggregateZero::get(Ty); + case Type::TokenTyID: + return ConstantTokenNone::get(Ty->getContext()); default: // Function, Label, or Opaque type? llvm_unreachable("Cannot create a null constant of that type!"); @@ -1170,6 +1174,17 @@ return get(Elts); } +ConstantTokenNone *ConstantTokenNone::get(LLVMContext &Context) { + LLVMContextImpl *pImpl = Context.pImpl; + if (!pImpl->TheNoneToken) + pImpl->TheNoneToken = new ConstantTokenNone(Context); + return pImpl->TheNoneToken; +} + +/// Remove the constant from the constant table. +void ConstantTokenNone::destroyConstantImpl() { + llvm_unreachable("You can't ConstantTokenNone->destroyConstantImpl()!"); +} // Utility function for determining if a ConstantExpr is a CastOp or not. This // can't be inline because we don't want to #include Instruction.h into @@ -2875,6 +2890,11 @@ llvm_unreachable("Unsupported class for handleOperandChange()!"); } +Value *ConstantTokenNone::handleOperandChangeImpl(Value *From, Value *To, + Use *U) { + llvm_unreachable("Unsupported class for handleOperandChange()!"); +} + Value *UndefValue::handleOperandChangeImpl(Value *From, Value *To, Use *U) { llvm_unreachable("Unsupported class for handleOperandChange()!"); } Index: lib/IR/LLVMContextImpl.h =================================================================== --- lib/IR/LLVMContextImpl.h +++ lib/IR/LLVMContextImpl.h @@ -924,6 +924,8 @@ ConstantInt *TheTrueVal; ConstantInt *TheFalseVal; + ConstantTokenNone *TheNoneToken; + // Basic type instances. Type VoidTy, LabelTy, HalfTy, FloatTy, DoubleTy, MetadataTy, TokenTy; Type X86_FP80Ty, FP128Ty, PPC_FP128Ty, X86_MMXTy; Index: lib/IR/LLVMContextImpl.cpp =================================================================== --- lib/IR/LLVMContextImpl.cpp +++ lib/IR/LLVMContextImpl.cpp @@ -21,6 +21,7 @@ LLVMContextImpl::LLVMContextImpl(LLVMContext &C) : TheTrueVal(nullptr), TheFalseVal(nullptr), + TheNoneToken(nullptr), VoidTy(C, Type::VoidTyID), LabelTy(C, Type::LabelTyID), HalfTy(C, Type::HalfTyID), Index: lib/Transforms/IPO/MergeFunctions.cpp =================================================================== --- lib/Transforms/IPO/MergeFunctions.cpp +++ lib/Transforms/IPO/MergeFunctions.cpp @@ -656,7 +656,9 @@ } switch (L->getValueID()) { - case Value::UndefValueVal: return TypesRes; + case Value::UndefValueVal: + case Value::ConstantTokenNoneVal: + return TypesRes; case Value::ConstantIntVal: { const APInt &LInt = cast(L)->getValue(); const APInt &RInt = cast(R)->getValue(); Index: test/Assembler/token.ll =================================================================== --- test/Assembler/token.ll +++ test/Assembler/token.ll @@ -4,3 +4,8 @@ ; CHECK: declare void @llvm.token.foobar(token) declare void @llvm.token.foobar(token) + +define void @f() { + call void @llvm.token.foobar(token none) + ret void +}