Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -602,6 +602,9 @@ ATTR_KIND_OPT_FOR_FUZZING = 57, ATTR_KIND_SHADOWCALLSTACK = 58, ATTR_KIND_SPECULATIVE_LOAD_HARDENING = 59, + ATTR_KIND_MASK = 60, + ATTR_KIND_VECTORLENGTH = 61, + ATTR_KIND_PASSTHRU = 62, }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -130,6 +130,15 @@ /// Return value is always equal to this argument. def Returned : EnumAttr<"returned">; +/// Return value that is equal to this argument on enabled lanes (mask). +def Passthru : EnumAttr<"passthru">; + +/// Mask argument that applies to this function. +def Mask : EnumAttr<"mask">; + +/// Dynamic Vector Length argument of this function. +def VectorLength : EnumAttr<"vlen">; + /// Function can return twice. def ReturnsTwice : EnumAttr<"returns_twice">; Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -88,6 +88,25 @@ int ArgNo = argNo; } +// VectorLength - The specified argument is the Dynamic Vector Length of the +// operation. +class VectorLength : IntrinsicProperty { + int ArgNo = argNo; +} + +// Mask - The specified argument contains the per-lane mask of this +// intrinsic. Inputs on masked-out lanes must not effect the result of this +// intrinsic (except for the Passthru argument). +class Mask : IntrinsicProperty { + int ArgNo = argNo; +} +// Passthru - The specified argument contains the per-lane return value +// for this vector intrinsic where the mask is false. +// (requires the Mask attribute in the same function) +class Passthru : IntrinsicProperty { + int ArgNo = argNo; +} + def IntrNoReturn : IntrinsicProperty; // IntrCold - Calls to this intrinsic are cold. @@ -989,6 +1008,257 @@ // Intrinsic to detect whether its argument is a constant. def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">; +//===---------------- Masked/Explicit Vector Length Intrinsics --------------===// + +// Memory Intrinsics +def int_evl_store : Intrinsic<[], [llvm_anyvector_ty, + LLVMAnyPointerType>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrArgMemOnly, Mask<2>, VectorLength<3>]>; + +def int_evl_load : Intrinsic<[llvm_anyvector_ty], + [LLVMAnyPointerType>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrReadMem, IntrArgMemOnly, Passthru<1>, Mask<2>, VectorLength<3>]>; + +def int_evl_gather: Intrinsic<[llvm_anyvector_ty], + [LLVMVectorOfAnyPointersToElt<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrReadMem, Passthru<1>, Mask<2>, VectorLength<3>]>; + +def int_evl_scatter: Intrinsic<[], + [llvm_anyvector_ty, + LLVMVectorOfAnyPointersToElt<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [Mask<2>, VectorLength<3>]>; + +def int_evl_expandload: Intrinsic<[llvm_anyvector_ty], + [LLVMPointerToElt<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrReadMem, Mask<2>, Passthru<1>, VectorLength<3>]>; + +def int_evl_compressstore: Intrinsic<[], + [llvm_anyvector_ty, + LLVMPointerToElt<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrArgMemOnly, Mask<2>, VectorLength<3>]>; + +// Reductions +def int_evl_reduce_fadd : Intrinsic<[llvm_anyfloat_ty], + [llvm_anyfloat_ty, + llvm_anyvector_ty, + LLVMVectorSameWidth<2, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, IntrSpeculatable, Mask<2>, VectorLength<3>]>; +def int_evl_reduce_fmul : Intrinsic<[llvm_anyfloat_ty], + [llvm_anyfloat_ty, + llvm_anyvector_ty, + LLVMVectorSameWidth<2, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<2>, VectorLength<3>]>; +def int_evl_reduce_add : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_mul : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_and : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_or : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_xor : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_smax : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_smin : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_umax : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_umin : Intrinsic<[llvm_anyint_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_fmax : Intrinsic<[llvm_anyfloat_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; +def int_evl_reduce_fmin : Intrinsic<[llvm_anyfloat_ty], + [llvm_anyvector_ty, + LLVMVectorSameWidth<1, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<1>, VectorLength<2>]>; + +// Binary operators +let IntrProperties = [IntrNoMem, Passthru<0>, Mask<2>, VectorLength<3>] in { + def int_evl_add : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_sub : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_mul : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_sdiv : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_udiv : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_srem : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_urem : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + + def int_evl_fadd : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_fsub : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_fmul : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_fdiv : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_frem : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + +// Logical operators + def int_evl_ashr : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_lshr : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_shl : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_or : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_and : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; + def int_evl_xor : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty]>; +} + +def int_evl_fma : Intrinsic<[ llvm_anyvector_ty ], + [ LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Passthru<0>, Mask<3>, VectorLength<4>]>; + +// Shuffle +def int_evl_expand: Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<2>, Passthru<0>, VectorLength<3>]>; + +def int_evl_compress: Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Mask<2>, Passthru<0>, VectorLength<3>]>; + +// Select +def int_evl_select : Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>, + LLVMMatchType<0>, + LLVMVectorSameWidth<0, llvm_i1_ty>, + llvm_i32_ty], + [IntrNoMem, Passthru<0>, Mask<2>, VectorLength<3>]>; + +// Compose +def int_evl_compose : Intrinsic<[llvm_anyvector_ty], + [LLVMMatchType<0>, + LLVMMatchType<0>, + llvm_i32_ty, + llvm_i32_ty], + [IntrNoMem, VectorLength<2>]>; + + + //===-------------------------- Masked Intrinsics -------------------------===// // Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -643,6 +643,7 @@ KEYWORD(inlinehint); KEYWORD(inreg); KEYWORD(jumptable); + KEYWORD(mask); KEYWORD(minsize); KEYWORD(naked); KEYWORD(nest); @@ -662,6 +663,7 @@ KEYWORD(optforfuzzing); KEYWORD(optnone); KEYWORD(optsize); + KEYWORD(passthru); KEYWORD(readnone); KEYWORD(readonly); KEYWORD(returned); @@ -683,6 +685,7 @@ KEYWORD(swifterror); KEYWORD(swiftself); KEYWORD(uwtable); + KEYWORD(vlen); KEYWORD(writeonly); KEYWORD(zeroext); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1295,14 +1295,17 @@ case lltok::kw_dereferenceable: case lltok::kw_dereferenceable_or_null: case lltok::kw_inalloca: + case lltok::kw_mask: case lltok::kw_nest: case lltok::kw_noalias: case lltok::kw_nocapture: case lltok::kw_nonnull: + case lltok::kw_passthru: case lltok::kw_returned: case lltok::kw_sret: case lltok::kw_swifterror: case lltok::kw_swiftself: + case lltok::kw_vlen: HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute on a function"); @@ -1583,10 +1586,12 @@ } case lltok::kw_inalloca: B.addAttribute(Attribute::InAlloca); break; case lltok::kw_inreg: B.addAttribute(Attribute::InReg); break; + case lltok::kw_mask: B.addAttribute(Attribute::Mask); break; case lltok::kw_nest: B.addAttribute(Attribute::Nest); break; case lltok::kw_noalias: B.addAttribute(Attribute::NoAlias); break; case lltok::kw_nocapture: B.addAttribute(Attribute::NoCapture); break; case lltok::kw_nonnull: B.addAttribute(Attribute::NonNull); break; + case lltok::kw_passthru: B.addAttribute(Attribute::Passthru); break; case lltok::kw_readnone: B.addAttribute(Attribute::ReadNone); break; case lltok::kw_readonly: B.addAttribute(Attribute::ReadOnly); break; case lltok::kw_returned: B.addAttribute(Attribute::Returned); break; @@ -1594,6 +1599,7 @@ case lltok::kw_sret: B.addAttribute(Attribute::StructRet); break; case lltok::kw_swifterror: B.addAttribute(Attribute::SwiftError); break; case lltok::kw_swiftself: B.addAttribute(Attribute::SwiftSelf); break; + case lltok::kw_vlen: B.addAttribute(Attribute::VectorLength); break; case lltok::kw_writeonly: B.addAttribute(Attribute::WriteOnly); break; case lltok::kw_zeroext: B.addAttribute(Attribute::ZExt); break; @@ -1684,12 +1690,15 @@ // Error handling. case lltok::kw_byval: case lltok::kw_inalloca: + case lltok::kw_mask: case lltok::kw_nest: case lltok::kw_nocapture: + case lltok::kw_passthru: case lltok::kw_returned: case lltok::kw_sret: case lltok::kw_swifterror: case lltok::kw_swiftself: + case lltok::kw_vlen: HaveError |= Error(Lex.getLoc(), "invalid use of parameter-only attribute"); break; @@ -3295,7 +3304,7 @@ ID.Kind = ValID::t_Constant; return false; } - + // Unary Operators. case lltok::kw_fneg: { unsigned Opc = Lex.getUIntVal(); @@ -3305,7 +3314,7 @@ ParseGlobalTypeAndValue(Val) || ParseToken(lltok::rparen, "expected ')' in unary constantexpr")) return true; - + // Check that the type is valid for the operator. switch (Opc) { case Instruction::FNeg: @@ -6170,11 +6179,11 @@ Valid = LHS->getType()->isIntOrIntVectorTy() || LHS->getType()->isFPOrFPVectorTy(); break; - case 1: - Valid = LHS->getType()->isIntOrIntVectorTy(); + case 1: + Valid = LHS->getType()->isIntOrIntVectorTy(); break; - case 2: - Valid = LHS->getType()->isFPOrFPVectorTy(); + case 2: + Valid = LHS->getType()->isFPOrFPVectorTy(); break; } Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -187,6 +187,7 @@ kw_inlinehint, kw_inreg, kw_jumptable, + kw_mask, kw_minsize, kw_naked, kw_nest, @@ -206,6 +207,7 @@ kw_optforfuzzing, kw_optnone, kw_optsize, + kw_passthru, kw_readnone, kw_readonly, kw_returned, @@ -225,6 +227,7 @@ kw_swifterror, kw_swiftself, kw_uwtable, + kw_vlen, kw_writeonly, kw_zeroext, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1331,6 +1331,8 @@ return Attribute::InReg; case bitc::ATTR_KIND_JUMP_TABLE: return Attribute::JumpTable; + case bitc::ATTR_KIND_MASK: + return Attribute::Mask; case bitc::ATTR_KIND_MIN_SIZE: return Attribute::MinSize; case bitc::ATTR_KIND_NAKED: @@ -1375,6 +1377,8 @@ return Attribute::OptimizeForSize; case bitc::ATTR_KIND_OPTIMIZE_NONE: return Attribute::OptimizeNone; + case bitc::ATTR_KIND_PASSTHRU: + return Attribute::Passthru; case bitc::ATTR_KIND_READ_NONE: return Attribute::ReadNone; case bitc::ATTR_KIND_READ_ONLY: @@ -1419,6 +1423,8 @@ return Attribute::SwiftSelf; case bitc::ATTR_KIND_UW_TABLE: return Attribute::UWTable; + case bitc::ATTR_KIND_VECTORLENGTH: + return Attribute::VectorLength; case bitc::ATTR_KIND_WRITEONLY: return Attribute::WriteOnly; case bitc::ATTR_KIND_Z_EXT: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -669,6 +669,12 @@ return bitc::ATTR_KIND_READ_ONLY; case Attribute::Returned: return bitc::ATTR_KIND_RETURNED; + case Attribute::Mask: + return bitc::ATTR_KIND_MASK; + case Attribute::VectorLength: + return bitc::ATTR_KIND_VECTORLENGTH; + case Attribute::Passthru: + return bitc::ATTR_KIND_PASSTHRU; case Attribute::ReturnsTwice: return bitc::ATTR_KIND_RETURNS_TWICE; case Attribute::SExt: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -257,6 +257,8 @@ return "byval"; if (hasAttribute(Attribute::Convergent)) return "convergent"; + if (hasAttribute(Attribute::VectorLength)) + return "vlen"; if (hasAttribute(Attribute::SwiftError)) return "swifterror"; if (hasAttribute(Attribute::SwiftSelf)) @@ -273,6 +275,10 @@ return "inreg"; if (hasAttribute(Attribute::JumpTable)) return "jumptable"; + if (hasAttribute(Attribute::Mask)) + return "mask"; + if (hasAttribute(Attribute::Passthru)) + return "passthru"; if (hasAttribute(Attribute::MinSize)) return "minsize"; if (hasAttribute(Attribute::Naked)) Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1653,11 +1653,14 @@ if (Attrs.isEmpty()) return; + bool SawMask = false; bool SawNest = false; + bool SawPassthru = false; bool SawReturned = false; bool SawSRet = false; bool SawSwiftSelf = false; bool SawSwiftError = false; + bool SawVectorLength = false; // Verify return value attributes. AttributeSet RetAttrs = Attrs.getRetAttributes(); @@ -1720,12 +1723,33 @@ SawSwiftError = true; } + if (ArgAttrs.hasAttribute(Attribute::VectorLength)) { + Assert(!SawVectorLength, "Cannot have multiple 'vlen' parameters!", + V); + SawVectorLength = true; + } + + if (ArgAttrs.hasAttribute(Attribute::Passthru)) { + Assert(!SawPassthru, "Cannot have multiple 'passthru' parameters!", + V); + SawPassthru = true; + } + + if (ArgAttrs.hasAttribute(Attribute::Mask)) { + Assert(!SawMask, "Cannot have multiple 'mask' parameters!", + V); + SawMask = true; + } + if (ArgAttrs.hasAttribute(Attribute::InAlloca)) { Assert(i == FT->getNumParams() - 1, "inalloca isn't on the last parameter!", V); } } + Assert(!SawPassthru || SawMask, + "Cannot have 'passthru' parameter without 'mask' parameter!", V); + if (!Attrs.hasAttributes(AttributeList::FunctionIndex)) return; @@ -3036,7 +3060,7 @@ /// visitUnaryOperator - Check the argument to the unary operator. /// void Verifier::visitUnaryOperator(UnaryOperator &U) { - Assert(U.getType() == U.getOperand(0)->getType(), + Assert(U.getType() == U.getOperand(0)->getType(), "Unary operators must have same type for" "operands and result!", &U); @@ -4857,7 +4881,7 @@ bool runOnFunction(Function &F) override { if (!V->verify(F) && FatalErrors) { - errs() << "in function " << F.getName() << '\n'; + errs() << "in function " << F.getName() << '\n'; report_fatal_error("Broken function found, compilation aborted!"); } return false; Index: lib/Transforms/Utils/CodeExtractor.cpp =================================================================== --- lib/Transforms/Utils/CodeExtractor.cpp +++ lib/Transforms/Utils/CodeExtractor.cpp @@ -775,6 +775,7 @@ case Attribute::InaccessibleMemOnly: case Attribute::InaccessibleMemOrArgMemOnly: case Attribute::JumpTable: + case Attribute::Mask: case Attribute::Naked: case Attribute::Nest: case Attribute::NoAlias: @@ -783,6 +784,7 @@ case Attribute::NoReturn: case Attribute::None: case Attribute::NonNull: + case Attribute::Passthru: case Attribute::ReadNone: case Attribute::ReadOnly: case Attribute::Returned: @@ -793,6 +795,7 @@ case Attribute::StructRet: case Attribute::SwiftError: case Attribute::SwiftSelf: + case Attribute::VectorLength: case Attribute::WriteOnly: case Attribute::ZExt: case Attribute::EndAttrKinds: Index: test/Bitcode/attributes.ll =================================================================== --- test/Bitcode/attributes.ll +++ test/Bitcode/attributes.ll @@ -351,6 +351,11 @@ ret void } +; CHECK: define <8 x double> @f60(<8 x double> passthru, <8 x i1> mask, i32 vlen) { +define <8 x double> @f60(<8 x double> passthru, <8 x i1> mask, i32 vlen) { + ret <8 x double> undef +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } Index: test/Verifier/evl_attribs.ll =================================================================== --- /dev/null +++ test/Verifier/evl_attribs.ll @@ -0,0 +1,13 @@ +; RUN: not llvm-as %s -o /dev/null 2>&1 | FileCheck %s + +declare void @a(<16 x i1> mask %a, <16 x i1> mask %b) +; CHECK: Cannot have multiple 'mask' parameters! + +declare void @b(<16 x i1> mask %a, i32 vlen %x, i32 vlen %y) +; CHECK: Cannot have multiple 'vlen' parameters! + +declare <16 x double> @c(<16 x double> passthru %a) +; CHECK: Cannot have 'passthru' parameter without 'mask' parameter! + +declare <16 x double> @d(<16 x double> passthru %a, <16 x i1> mask %M, <16 x double> passthru %b) +; CHECK: Cannot have multiple 'passthru' parameters! Index: utils/TableGen/CodeGenIntrinsics.h =================================================================== --- utils/TableGen/CodeGenIntrinsics.h +++ utils/TableGen/CodeGenIntrinsics.h @@ -137,7 +137,7 @@ // True if the intrinsic is marked as speculatable. bool isSpeculatable; - enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone }; + enum ArgAttribute { Mask, NoCapture, Passthru, Returned, ReadOnly, WriteOnly, ReadNone, VectorLength }; std::vector> ArgumentAttributes; bool hasProperty(enum SDNP Prop) const { Index: utils/TableGen/CodeGenTarget.cpp =================================================================== --- utils/TableGen/CodeGenTarget.cpp +++ utils/TableGen/CodeGenTarget.cpp @@ -695,6 +695,15 @@ } else if (Property->isSubClassOf("Returned")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, Returned)); + } else if (Property->isSubClassOf("VectorLength")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, VectorLength)); + } else if (Property->isSubClassOf("Mask")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, Mask)); + } else if (Property->isSubClassOf("Passthru")) { + unsigned ArgNo = Property->getValueAsInt("ArgNo"); + ArgumentAttributes.push_back(std::make_pair(ArgNo, Passthru)); } else if (Property->isSubClassOf("ReadOnly")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, ReadOnly)); Index: utils/TableGen/IntrinsicEmitter.cpp =================================================================== --- utils/TableGen/IntrinsicEmitter.cpp +++ utils/TableGen/IntrinsicEmitter.cpp @@ -595,6 +595,24 @@ OS << "Attribute::Returned"; addComma = true; break; + case CodeGenIntrinsic::VectorLength: + if (addComma) + OS << ","; + OS << "Attribute::VectorLength"; + addComma = true; + break; + case CodeGenIntrinsic::Mask: + if (addComma) + OS << ","; + OS << "Attribute::Mask"; + addComma = true; + break; + case CodeGenIntrinsic::Passthru: + if (addComma) + OS << ","; + OS << "Attribute::Passthru"; + addComma = true; + break; case CodeGenIntrinsic::ReadOnly: if (addComma) OS << ",";