Index: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp +++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp @@ -261,12 +261,15 @@ } } + // If the SCC contains both functions that read and functions that write, then + // we cannot add readonly attributes. + if (ReadsMemory && WritesMemory) + return false; + // Success! Functions in this SCC do not access memory, or only read memory. // Give them the appropriate attribute. bool MadeChange = false; - assert(!(ReadsMemory && WritesMemory) && - "Function marked read-only and write-only"); for (Function *F : SCCNodes) { if (F->doesNotAccessMemory()) // Already perfect! Index: llvm/trunk/test/Transforms/FunctionAttrs/read-write-scc.ll =================================================================== --- llvm/trunk/test/Transforms/FunctionAttrs/read-write-scc.ll +++ llvm/trunk/test/Transforms/FunctionAttrs/read-write-scc.ll @@ -0,0 +1,20 @@ +; RUN: opt -S -functionattrs < %s | FileCheck %s +; RUN: opt -S -passes=function-attrs < %s | FileCheck %s + +@i = global i32 0 + +define void @foo() { +; CHECK-LABEL: define void @foo() #0 { + store i32 1, i32* @i + call void @bar() + ret void +} + +define void @bar() { +; CHECK-LABEL: define void @bar() #0 { + %i = load i32, i32* @i + call void @foo() + ret void +} + +; CHECK: attributes #0 = { nofree nounwind }