Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1399,6 +1399,11 @@ This function attribute indicates that the function does not call itself either directly or indirectly down any possible call path. This produces undefined behavior at runtime if the function ever does recurse. +``nosideffects`` + This function attribute indicates that the function does not modify any + state that isn't accessbile from the IR (e.g. floating-point exception + registers). Functions with the nosideeffects attribute can be safely + speculated. ``nounwind`` This function attribute indicates that the function never raises an exception. If the function does raise an exception, its runtime Index: include/llvm/Bitcode/LLVMBitCodes.h =================================================================== --- include/llvm/Bitcode/LLVMBitCodes.h +++ include/llvm/Bitcode/LLVMBitCodes.h @@ -522,7 +522,8 @@ ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, ATTR_KIND_ALLOC_SIZE = 51, - ATTR_KIND_WRITEONLY = 52 + ATTR_KIND_WRITEONLY = 52, + ATTR_KIND_NO_SIDEEFFECTS = 53 }; enum ComdatSelectionKindCodes { Index: include/llvm/IR/Attributes.td =================================================================== --- include/llvm/IR/Attributes.td +++ include/llvm/IR/Attributes.td @@ -106,6 +106,9 @@ /// Mark the function as not returning. def NoReturn : EnumAttr<"noreturn">; +/// Function doesn't have sideeffects. +def NoSideEffects : EnumAttr<"nosideeffects">; + /// Function doesn't unwind stack. def NoUnwind : EnumAttr<"nounwind">; Index: include/llvm/IR/Function.h =================================================================== --- include/llvm/IR/Function.h +++ include/llvm/IR/Function.h @@ -366,6 +366,14 @@ removeFnAttr(Attribute::Convergent); } + /// @brief Determine if the call has sideeffects. + bool doesNotHaveSideEffects() const { + return hasFnAttribute(Attribute::NoSideEffects); + } + void setDoesNotHaveSideEffects() { + addFnAttr(Attribute::NoSideEffects); + } + /// Determine if the function is known not to recurse, directly or /// indirectly. bool doesNotRecurse() const { Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -89,6 +89,15 @@ // Parallels the convergent attribute on LLVM IR functions. def IntrConvergent : IntrinsicProperty; +// Calls to this intrinsics have no side effects, so it may be speculated. +def IntrNoSideEffects : IntrinsicProperty; + +// This property indicates that an intrinsic has side effects and cannot be +// CSE'd or speculated. This property can be used to override properties +// like IntrNoMem which include 'has no side effects' as part of its definition. +def IntrHasSideEffects : IntrinsicProperty; + + //===----------------------------------------------------------------------===// // Types used by intrinsics. //===----------------------------------------------------------------------===// @@ -448,7 +457,7 @@ // None of these intrinsics accesses memory at all...but that doesn't mean the // optimizers can change them aggressively. Special handling needed in a few // places. -let IntrProperties = [IntrNoMem] in { +let IntrProperties = [IntrNoMem, IntrHasSideEffects] in { def int_dbg_declare : Intrinsic<[], [llvm_metadata_ty, llvm_metadata_ty, Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -641,6 +641,7 @@ KEYWORD(nonnull); KEYWORD(noredzone); KEYWORD(noreturn); + KEYWORD(nosideeffects); KEYWORD(nounwind); KEYWORD(optnone); KEYWORD(optsize); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -1079,6 +1079,7 @@ case lltok::kw_noredzone: B.addAttribute(Attribute::NoRedZone); break; case lltok::kw_noreturn: B.addAttribute(Attribute::NoReturn); break; case lltok::kw_norecurse: B.addAttribute(Attribute::NoRecurse); break; + case lltok::kw_nosideeffects: B.addAttribute(Attribute::NoSideEffects); break; case lltok::kw_nounwind: B.addAttribute(Attribute::NoUnwind); break; case lltok::kw_optnone: B.addAttribute(Attribute::OptimizeNone); break; case lltok::kw_optsize: B.addAttribute(Attribute::OptimizeForSize); break; Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -187,6 +187,7 @@ kw_nonnull, kw_noredzone, kw_noreturn, + kw_nosideeffects, kw_nounwind, kw_optnone, kw_optsize, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -1429,6 +1429,8 @@ return Attribute::NoRedZone; case bitc::ATTR_KIND_NO_RETURN: return Attribute::NoReturn; + case bitc::ATTR_KIND_NO_SIDEEFFECTS: + return Attribute::NoSideEffects; case bitc::ATTR_KIND_NO_UNWIND: return Attribute::NoUnwind; case bitc::ATTR_KIND_OPTIMIZE_FOR_SIZE: Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -615,6 +615,8 @@ return bitc::ATTR_KIND_NO_INLINE; case Attribute::NoRecurse: return bitc::ATTR_KIND_NO_RECURSE; + case Attribute::NoSideEffects: + return bitc::ATTR_KIND_NO_SIDEEFFECTS; case Attribute::NonLazyBind: return bitc::ATTR_KIND_NON_LAZY_BIND; case Attribute::NonNull: Index: lib/IR/Attributes.cpp =================================================================== --- lib/IR/Attributes.cpp +++ lib/IR/Attributes.cpp @@ -282,6 +282,8 @@ return "noreturn"; if (hasAttribute(Attribute::NoRecurse)) return "norecurse"; + if (hasAttribute(Attribute::NoSideEffects)) + return "nosideeffects"; if (hasAttribute(Attribute::NoUnwind)) return "nounwind"; if (hasAttribute(Attribute::OptimizeNone)) @@ -519,6 +521,7 @@ case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; case Attribute::WriteOnly: return 1ULL << 53; + case Attribute::NoSideEffects: return 1ULL << 54; case Attribute::Dereferenceable: llvm_unreachable("dereferenceable attribute not supported in raw format"); break; Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -1302,6 +1302,7 @@ I->getKindAsEnum() == Attribute::NoRecurse || I->getKindAsEnum() == Attribute::InaccessibleMemOnly || I->getKindAsEnum() == Attribute::InaccessibleMemOrArgMemOnly || + I->getKindAsEnum() == Attribute::NoSideEffects || I->getKindAsEnum() == Attribute::AllocSize) { if (!isFunction) { CheckFailed("Attribute '" + I->getAsString() + Index: test/Analysis/BasicAA/intrinsics.ll =================================================================== --- test/Analysis/BasicAA/intrinsics.ll +++ test/Analysis/BasicAA/intrinsics.ll @@ -38,6 +38,6 @@ declare <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8*, i32) nounwind readonly declare void @llvm.arm.neon.vst1.p0i8.v8i16(i8*, <8 x i16>, i32) nounwind -; CHECK: attributes #0 = { argmemonly nounwind readonly } -; CHECK: attributes #1 = { argmemonly nounwind } +; CHECK: attributes #0 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #1 = { argmemonly nosideeffects nounwind } ; CHECK: attributes [[ATTR]] = { nounwind } Index: test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll =================================================================== --- test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll +++ test/Analysis/TypeBasedAliasAnalysis/functionattrs.ll @@ -77,7 +77,7 @@ ; CHECK: attributes #2 = { nounwind readonly } ; CHECK: attributes #3 = { nounwind } ; CHECK: attributes #4 = { nounwind readnone } -; CHECK: attributes #5 = { argmemonly nounwind } +; CHECK: attributes #5 = { argmemonly nosideeffects nounwind } ; Root note. !0 = !{ } Index: test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll =================================================================== --- test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll +++ test/Analysis/TypeBasedAliasAnalysis/intrinsics.ll @@ -22,8 +22,8 @@ declare <8 x i16> @llvm.arm.neon.vld1.v8i16.p0i8(i8*, i32) nounwind readonly declare void @llvm.arm.neon.vst1.p0i8.v8i16(i8*, <8 x i16>, i32) nounwind -; CHECK: attributes #0 = { argmemonly nounwind readonly } -; CHECK: attributes #1 = { argmemonly nounwind } +; CHECK: attributes #0 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #1 = { argmemonly nosideeffects nounwind } ; CHECK: attributes [[NUW]] = { nounwind } !0 = !{!"tbaa root", null} Index: test/Bitcode/attributes.ll =================================================================== --- test/Bitcode/attributes.ll +++ test/Bitcode/attributes.ll @@ -204,7 +204,7 @@ ; CHECK: define void @f34() { call void @nobuiltin() nobuiltin -; CHECK: call void @nobuiltin() #33 +; CHECK: call void @nobuiltin() #34 ret void; } @@ -334,6 +334,11 @@ ret void } +; CHECK: define void @f57() #33 +define void @f57() nosideeffects { + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -367,4 +372,5 @@ ; CHECK: attributes #30 = { allocsize(0) } ; CHECK: attributes #31 = { allocsize(0,1) } ; CHECK: attributes #32 = { writeonly } -; CHECK: attributes #33 = { nobuiltin } +; CHECK: attributes #33 = { nosideeffects } +; CHECK: attributes #34 = { nobuiltin } Index: test/Bitcode/compatibility-3.6.ll =================================================================== --- test/Bitcode/compatibility-3.6.ll +++ test/Bitcode/compatibility-3.6.ll @@ -1179,10 +1179,10 @@ ; CHECK: attributes #26 = { sspstrong } ; CHECK: attributes #27 = { uwtable } ; CHECK: attributes #28 = { "cpu"="cortex-a8" } -; CHECK: attributes #29 = { nounwind readnone } -; CHECK: attributes #30 = { argmemonly nounwind readonly } -; CHECK: attributes #31 = { argmemonly nounwind } -; CHECK: attributes #32 = { nounwind readonly } +; CHECK: attributes #29 = { nosideeffects nounwind readnone } +; CHECK: attributes #30 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #31 = { argmemonly nosideeffects nounwind } +; CHECK: attributes #32 = { nosideeffects nounwind readonly } ; CHECK: attributes #33 = { builtin } ;; Metadata Index: test/Bitcode/compatibility-3.7.ll =================================================================== --- test/Bitcode/compatibility-3.7.ll +++ test/Bitcode/compatibility-3.7.ll @@ -1242,10 +1242,10 @@ ; CHECK: attributes #29 = { "thunk" } ; CHECK: attributes #30 = { uwtable } ; CHECK: attributes #31 = { "cpu"="cortex-a8" } -; CHECK: attributes #32 = { nounwind readnone } -; CHECK: attributes #33 = { argmemonly nounwind readonly } -; CHECK: attributes #34 = { argmemonly nounwind } -; CHECK: attributes #35 = { nounwind readonly } +; CHECK: attributes #32 = { nosideeffects nounwind readnone } +; CHECK: attributes #33 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #34 = { argmemonly nosideeffects nounwind } +; CHECK: attributes #35 = { nosideeffects nounwind readonly } ; CHECK: attributes #36 = { builtin } ;; Metadata Index: test/Bitcode/compatibility-3.8.ll =================================================================== --- test/Bitcode/compatibility-3.8.ll +++ test/Bitcode/compatibility-3.8.ll @@ -1552,10 +1552,10 @@ ; CHECK: attributes #32 = { norecurse } ; CHECK: attributes #33 = { inaccessiblememonly } ; CHECK: attributes #34 = { inaccessiblemem_or_argmemonly } -; CHECK: attributes #35 = { nounwind readnone } -; CHECK: attributes #36 = { argmemonly nounwind readonly } -; CHECK: attributes #37 = { argmemonly nounwind } -; CHECK: attributes #38 = { nounwind readonly } +; CHECK: attributes #35 = { nosideeffects nounwind readnone } +; CHECK: attributes #36 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #37 = { argmemonly nosideeffects nounwind } +; CHECK: attributes #38 = { nosideeffects nounwind readonly } ; CHECK: attributes #39 = { builtin } ;; Metadata Index: test/Bitcode/compatibility.ll =================================================================== --- test/Bitcode/compatibility.ll +++ test/Bitcode/compatibility.ll @@ -1628,10 +1628,10 @@ ; CHECK: attributes #32 = { norecurse } ; CHECK: attributes #33 = { inaccessiblememonly } ; CHECK: attributes #34 = { inaccessiblemem_or_argmemonly } -; CHECK: attributes #35 = { nounwind readnone } -; CHECK: attributes #36 = { argmemonly nounwind readonly } -; CHECK: attributes #37 = { argmemonly nounwind } -; CHECK: attributes #38 = { nounwind readonly } +; CHECK: attributes #35 = { nosideeffects nounwind readnone } +; CHECK: attributes #36 = { argmemonly nosideeffects nounwind readonly } +; CHECK: attributes #37 = { argmemonly nosideeffects nounwind } +; CHECK: attributes #38 = { nosideeffects nounwind readonly } ; CHECK: attributes #39 = { writeonly } ; CHECK: attributes #40 = { builtin } Index: test/Bitcode/ptest-new.ll =================================================================== --- test/Bitcode/ptest-new.ll +++ test/Bitcode/ptest-new.ll @@ -23,4 +23,4 @@ declare i32 @llvm.x86.sse41.ptestnzc(<2 x i64>, <2 x i64>) nounwind readnone ; CHECK: attributes #0 = { nounwind } -; CHECK: attributes #1 = { nounwind readnone } +; CHECK: attributes #1 = { nosideeffects nounwind readnone } Index: test/Bitcode/ptest-old.ll =================================================================== --- test/Bitcode/ptest-old.ll +++ test/Bitcode/ptest-old.ll @@ -23,4 +23,4 @@ declare i32 @llvm.x86.sse41.ptestnzc(<4 x float>, <4 x float>) nounwind readnone ; CHECK: attributes #0 = { nounwind } -; CHECK: attributes #1 = { nounwind readnone } +; CHECK: attributes #1 = { nosideeffects nounwind readnone } Index: test/CodeGen/AMDGPU/addrspacecast-constantexpr.ll =================================================================== --- test/CodeGen/AMDGPU/addrspacecast-constantexpr.ll +++ test/CodeGen/AMDGPU/addrspacecast-constantexpr.ll @@ -98,7 +98,7 @@ ret i32 addrspace(3)* addrspacecast (i32 addrspace(4)* getelementptr ([256 x i32], [256 x i32] addrspace(4)* addrspacecast ([256 x i32] addrspace(3)* @lds.arr to [256 x i32] addrspace(4)*), i64 0, i64 8) to i32 addrspace(3)*) } -; HSA: attributes #0 = { argmemonly nounwind } +; HSA: attributes #0 = { argmemonly nosideeffects nounwind } ; HSA: attributes #1 = { nounwind } ; HSA: attributes #2 = { nounwind "amdgpu-queue-ptr" } Index: test/CodeGen/AMDGPU/annotate-kernel-features-hsa.ll =================================================================== --- test/CodeGen/AMDGPU/annotate-kernel-features-hsa.ll +++ test/CodeGen/AMDGPU/annotate-kernel-features-hsa.ll @@ -224,7 +224,7 @@ attributes #0 = { nounwind readnone } attributes #1 = { nounwind } -; HSA: attributes #0 = { nounwind readnone } +; HSA: attributes #0 = { nosideeffects nounwind readnone } ; HSA: attributes #1 = { nounwind } ; HSA: attributes #2 = { nounwind "amdgpu-work-group-id-y" } ; HSA: attributes #3 = { nounwind "amdgpu-work-group-id-z" } Index: test/Feature/intrinsics.ll =================================================================== --- test/Feature/intrinsics.ll +++ test/Feature/intrinsics.ll @@ -69,5 +69,5 @@ ret void } -; CHECK: attributes #0 = { nounwind readnone } +; CHECK: attributes #0 = { nosideeffects nounwind readnone } ; CHECK: attributes #1 = { noreturn nounwind } Index: test/Transforms/BBVectorize/simple-int.ll =================================================================== --- test/Transforms/BBVectorize/simple-int.ll +++ test/Transforms/BBVectorize/simple-int.ll @@ -503,4 +503,4 @@ ; CHECK: declare <2 x i64> @llvm.ctpop.v2i64(<2 x i64>) #0 ; CHECK: declare <2 x i64> @llvm.ctlz.v2i64(<2 x i64>, i1) #0 ; CHECK: declare <2 x i64> @llvm.cttz.v2i64(<2 x i64>, i1) #0 -; CHECK: attributes #0 = { nounwind readnone } +; CHECK: attributes #0 = { nosideeffects nounwind readnone } Index: test/Transforms/Inline/inline_invoke.ll =================================================================== --- test/Transforms/Inline/inline_invoke.ll +++ test/Transforms/Inline/inline_invoke.ll @@ -342,7 +342,7 @@ ; CHECK-NEXT: call void @_ZSt9terminatev() ; CHECK: attributes [[NUW]] = { nounwind } -; CHECK: attributes #1 = { nounwind readnone } +; CHECK: attributes #1 = { nosideeffects nounwind readnone } ; CHECK: attributes #2 = { ssp uwtable } -; CHECK: attributes #3 = { argmemonly nounwind } +; CHECK: attributes #3 = { argmemonly nosideeffects nounwind } ; CHECK: attributes #4 = { noreturn nounwind } Index: test/Transforms/Inline/noalias-calls.ll =================================================================== --- test/Transforms/Inline/noalias-calls.ll +++ test/Transforms/Inline/noalias-calls.ll @@ -22,13 +22,13 @@ ret void } -; CHECK: define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #2 { +; CHECK: define void @foo(i8* nocapture %a, i8* nocapture readonly %c, i8* nocapture %b) #3 { ; CHECK: entry: -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 16, i32 16, i1 false) #1, !noalias !0 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 false) #1, !noalias !3 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 false) #1, !alias.scope !5 -; CHECK: call void @hey() #1, !noalias !5 -; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %c, i64 16, i32 16, i1 false) #1, !noalias !3 +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %b, i64 16, i32 16, i1 false) #2, !noalias !0 +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %b, i8* %c, i64 16, i32 16, i1 false) #2, !noalias !3 +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %a, i8* %c, i64 16, i32 16, i1 false) #2, !alias.scope !5 +; CHECK: call void @hey() #2, !noalias !5 +; CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %c, i64 16, i32 16, i1 false) #2, !noalias !3 ; CHECK: ret void ; CHECK: } Index: test/Transforms/InstCombine/2012-04-23-Neon-Intrinsics.ll =================================================================== --- test/Transforms/InstCombine/2012-04-23-Neon-Intrinsics.ll +++ test/Transforms/InstCombine/2012-04-23-Neon-Intrinsics.ll @@ -131,5 +131,5 @@ declare <4 x i32> @llvm.aarch64.neon.umull.v4i32(<4 x i16>, <4 x i16>) nounwind readnone ; CHECK: attributes #0 = { nounwind readnone ssp } -; CHECK: attributes #1 = { nounwind readnone } +; CHECK: attributes #1 = { nosideeffects nounwind readnone } ; CHECK: attributes [[NUW]] = { nounwind } Index: test/Transforms/MemCpyOpt/memcpy.ll =================================================================== --- test/Transforms/MemCpyOpt/memcpy.ll +++ test/Transforms/MemCpyOpt/memcpy.ll @@ -206,6 +206,6 @@ declare void @f2(%struct.big*) ; CHECK: attributes [[NUW]] = { nounwind } -; CHECK: attributes #1 = { argmemonly nounwind } +; CHECK: attributes #1 = { argmemonly nosideeffects nounwind } ; CHECK: attributes #2 = { nounwind ssp } ; CHECK: attributes #3 = { nounwind ssp uwtable } Index: test/Transforms/ObjCARC/nested.ll =================================================================== --- test/Transforms/ObjCARC/nested.ll +++ test/Transforms/ObjCARC/nested.ll @@ -820,6 +820,6 @@ } -; CHECK: attributes #0 = { argmemonly nounwind } +; CHECK: attributes #0 = { argmemonly nosideeffects nounwind } ; CHECK: attributes #1 = { nonlazybind } ; CHECK: attributes [[NUW]] = { nounwind } Index: test/Transforms/SLPVectorizer/X86/call.ll =================================================================== --- test/Transforms/SLPVectorizer/X86/call.ll +++ test/Transforms/SLPVectorizer/X86/call.ll @@ -147,5 +147,5 @@ ; CHECK: declare <2 x double> @llvm.pow.v2f64(<2 x double>, <2 x double>) [[ATTR0]] ; CHECK: declare <2 x double> @llvm.exp2.v2f64(<2 x double>) [[ATTR0]] -; CHECK: attributes [[ATTR0]] = { nounwind readnone } +; CHECK: attributes [[ATTR0]] = { nosideeffects nounwind readnone } Index: utils/TableGen/CodeGenDAGPatterns.cpp =================================================================== --- utils/TableGen/CodeGenDAGPatterns.cpp +++ utils/TableGen/CodeGenDAGPatterns.cpp @@ -2822,9 +2822,9 @@ if (IntInfo->ModRef & CodeGenIntrinsic::MR_Mod) mayStore = true;// Intrinsics that can write to memory are 'mayStore'. - if (IntInfo->ModRef >= CodeGenIntrinsic::ReadWriteMem) - // ReadWriteMem intrinsics can have other strange effects. + if (IntInfo->hasSideEffects()) hasSideEffects = true; + } } Index: utils/TableGen/CodeGenIntrinsics.h =================================================================== --- utils/TableGen/CodeGenIntrinsics.h +++ utils/TableGen/CodeGenIntrinsics.h @@ -108,10 +108,29 @@ /// True if the intrinsic is marked as convergent. bool isConvergent; + bool hasSideEffects() const { + return hasSideEffectsProperty || + (ModRef >= CodeGenIntrinsic::ReadWriteMem && !hasNoSideEffectsProperty); + } + enum ArgAttribute { NoCapture, Returned, ReadOnly, WriteOnly, ReadNone }; std::vector> ArgumentAttributes; CodeGenIntrinsic(Record *R); + +private: + /// True if the IntrNoSideEffectsProperty has been set. + /// Use hasSideEffects() to query if this intrinsic has side effects + /// because intrinsics may have side effects even if this property + /// isn't set. + bool hasNoSideEffectsProperty; + + /// True if the IntrHasSideEffectsProperty hase been set. + /// Use hasSideEffects() to query if this intrinsic has side effects + /// because intrinsics may have side effects even if this property + /// isn't set. + bool hasSideEffectsProperty; + }; /// Read all of the intrinsics defined in the specified .td file. Index: utils/TableGen/CodeGenTarget.cpp =================================================================== --- utils/TableGen/CodeGenTarget.cpp +++ utils/TableGen/CodeGenTarget.cpp @@ -455,6 +455,8 @@ isNoReturn = false; isNoDuplicate = false; isConvergent = false; + hasNoSideEffectsProperty = false; + hasSideEffectsProperty = false; if (DefName.size() <= 4 || std::string(DefName.begin(), DefName.begin() + 4) != "int_") @@ -589,6 +591,10 @@ isConvergent = true; else if (Property->getName() == "IntrNoReturn") isNoReturn = true; + else if (Property->getName() == "IntrNoSideEffects") + hasNoSideEffectsProperty = true; + else if (Property->getName() == "IntrHasSideEffects") + hasSideEffectsProperty = true; else if (Property->isSubClassOf("NoCapture")) { unsigned ArgNo = Property->getValueAsInt("ArgNo"); ArgumentAttributes.push_back(std::make_pair(ArgNo, NoCapture)); @@ -608,6 +614,10 @@ llvm_unreachable("Unknown property!"); } + if (hasNoSideEffectsProperty && hasSideEffectsProperty) + PrintFatalError("Intrinsic '" + DefName + " has both IntrNoSideEffects" + " and IntrHasSideEffects properties"); + // Sort the argument attributes for later benefit. std::sort(ArgumentAttributes.begin(), ArgumentAttributes.end()); } Index: utils/TableGen/IntrinsicEmitter.cpp =================================================================== --- utils/TableGen/IntrinsicEmitter.cpp +++ utils/TableGen/IntrinsicEmitter.cpp @@ -461,6 +461,9 @@ if (L->isConvergent != R->isConvergent) return R->isConvergent; + if (L->hasSideEffects() != R->hasSideEffects()) + return R->hasSideEffects(); + // Try to order by readonly/readnone attribute. CodeGenIntrinsic::ModRefBehavior LK = L->ModRef; CodeGenIntrinsic::ModRefBehavior RK = R->ModRef; @@ -611,6 +614,13 @@ addComma = true; } + if (!intrinsic.hasSideEffects()) { + if (addComma) + OS << ","; + OS << "Attribute::NoSideEffects"; + addComma = true; + } + switch (intrinsic.ModRef) { case CodeGenIntrinsic::NoMem: if (addComma)