Index: docs/LangRef.rst =================================================================== --- docs/LangRef.rst +++ docs/LangRef.rst @@ -1381,6 +1381,9 @@ 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 has no side effects + and 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 @@ -520,7 +520,8 @@ ATTR_KIND_NO_RECURSE = 48, ATTR_KIND_INACCESSIBLEMEM_ONLY = 49, ATTR_KIND_INACCESSIBLEMEM_OR_ARGMEMONLY = 50, - ATTR_KIND_ALLOC_SIZE = 51 + ATTR_KIND_ALLOC_SIZE = 51, + ATTR_KIND_NO_SIDEEFFECTS = 52 }; 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 @@ -351,6 +351,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 @@ -77,6 +77,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. //===----------------------------------------------------------------------===// @@ -436,7 +445,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 @@ -639,6 +639,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 @@ -1083,6 +1083,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 @@ -144,6 +144,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 @@ -1427,6 +1427,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 @@ -593,6 +593,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)) @@ -516,6 +518,7 @@ case Attribute::InaccessibleMemOrArgMemOnly: return 1ULL << 50; case Attribute::SwiftSelf: return 1ULL << 51; case Attribute::SwiftError: return 1ULL << 52; + case Attribute::NoSideEffects: return 1ULL << 53; 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 @@ -1280,6 +1280,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/Bindings/llvm-c/invalid-bitcode.test =================================================================== --- test/Bindings/llvm-c/invalid-bitcode.test +++ test/Bindings/llvm-c/invalid-bitcode.test @@ -1,13 +1,13 @@ ; RUN: not llvm-c-test --module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s ; RUN: not llvm-c-test --lazy-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -CHECK: Error parsing bitcode: Unknown attribute kind (52) +CHECK: Error parsing bitcode: Unknown attribute kind (53) ; RUN: not llvm-c-test --new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s ; RUN: not llvm-c-test --lazy-new-module-dump < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=NEW %s -NEW: Error with new bitcode parser: Unknown attribute kind (52) +NEW: Error with new bitcode parser: Unknown attribute kind (53) ; RUN: llvm-c-test --test-diagnostic-handler < %S/Inputs/invalid.ll.bc 2>&1 | FileCheck --check-prefix=DIAGNOSTIC %s 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() #32 +; CHECK: call void @nobuiltin() #33 ret void; } @@ -328,6 +328,11 @@ ret i8* null } +; CHECK: define void @f56() #32 +define void @f56() nosideeffects { + ret void +} + ; CHECK: attributes #0 = { noreturn } ; CHECK: attributes #1 = { nounwind } ; CHECK: attributes #2 = { readnone } @@ -360,4 +365,5 @@ ; CHECK: attributes #29 = { inaccessiblemem_or_argmemonly } ; CHECK: attributes #30 = { allocsize(0) } ; CHECK: attributes #31 = { allocsize(0,1) } -; CHECK: attributes #32 = { nobuiltin } +; CHECK: attributes #32 = { nosideeffects } +; CHECK: attributes #33 = { 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 @@ -1580,10 +1580,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/invalid.ll =================================================================== --- test/Bitcode/invalid.ll +++ test/Bitcode/invalid.ll @@ -1,6 +1,6 @@ ; RUN: not llvm-dis < %s.bc 2>&1 | FileCheck %s -; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (52) +; CHECK: llvm-dis{{(\.EXE|\.exe)?}}: error: Unknown attribute kind (53) ; invalid.ll.bc has an invalid attribute number. ; The test checks that LLVM reports the error and doesn't access freed memory 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/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/LTO/X86/invalid.ll =================================================================== --- test/LTO/X86/invalid.ll +++ test/LTO/X86/invalid.ll @@ -1,4 +1,4 @@ ; RUN: not llvm-lto %S/Inputs/invalid.ll.bc 2>&1 | FileCheck %s -; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (52) +; CHECK: llvm-lto{{.*}}: error loading file '{{.*}}/Inputs/invalid.ll.bc': Unknown attribute kind (53) 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 @@ -109,6 +109,11 @@ /// isConvergent - True if the intrinsic is marked as convergent. bool isConvergent; + bool hasSideEffects() const { + return hasSideEffectsProperty || + (ModRef >= CodeGenIntrinsic::ReadWriteMem && !hasNoSideEffectsProperty); + } + enum ArgAttribute { NoCapture, ReadOnly, @@ -117,6 +122,20 @@ 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; + }; /// LoadIntrinsics - Read all of the intrinsics defined in the specified 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)); @@ -602,6 +608,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; @@ -599,6 +602,13 @@ addComma = true; } + if (!intrinsic.hasSideEffects()) { + if (addComma) + OS << ","; + OS << "Attribute::NoSideEffects"; + addComma = true; + } + switch (intrinsic.ModRef) { case CodeGenIntrinsic::NoMem: if (addComma)