forked from OSchip/llvm-project
[inlineasm] Attach readonly and readnone to inline-asm instructions.
Previously, clang/llvm treated inline-asm instructions conservatively, choosing not to eliminate the instructions or hoisting them out of a loop even when it was safe to do so. This commit makes changes to attach a readonly or readnone attribute to an inline-asm instruction, which enables passes such as LICM and EarlyCSE to move or optimize away the instruction. rdar://problem/11358192 Differential Revision: http://reviews.llvm.org/D10546 llvm-svn: 241930
This commit is contained in:
parent
425b1a5106
commit
10bdb2b144
|
@ -1852,6 +1852,14 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
|||
std::vector<llvm::Value*> InOutArgs;
|
||||
std::vector<llvm::Type*> InOutArgTypes;
|
||||
|
||||
// An inline asm can be marked readonly if it meets the following conditions:
|
||||
// - it doesn't have any sideeffects
|
||||
// - it doesn't clobber memory
|
||||
// - it doesn't return a value by-reference
|
||||
// It can be marked readnone if it doesn't have any input memory constraints
|
||||
// in addition to meeting the conditions listed above.
|
||||
bool ReadOnly = true, ReadNone = true;
|
||||
|
||||
for (unsigned i = 0, e = S.getNumOutputs(); i != e; i++) {
|
||||
TargetInfo::ConstraintInfo &Info = OutputConstraintInfos[i];
|
||||
|
||||
|
@ -1915,6 +1923,7 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
|||
Args.push_back(Dest.getAddress());
|
||||
Constraints += "=*";
|
||||
Constraints += OutputConstraint;
|
||||
ReadOnly = ReadNone = false;
|
||||
}
|
||||
|
||||
if (Info.isReadWrite()) {
|
||||
|
@ -1959,6 +1968,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
|||
|
||||
TargetInfo::ConstraintInfo &Info = InputConstraintInfos[i];
|
||||
|
||||
if (Info.allowsMemory())
|
||||
ReadNone = false;
|
||||
|
||||
if (!Constraints.empty())
|
||||
Constraints += ',';
|
||||
|
||||
|
@ -2023,7 +2035,9 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
|||
for (unsigned i = 0, e = S.getNumClobbers(); i != e; i++) {
|
||||
StringRef Clobber = S.getClobber(i);
|
||||
|
||||
if (Clobber != "memory" && Clobber != "cc")
|
||||
if (Clobber == "memory")
|
||||
ReadOnly = ReadNone = false;
|
||||
else if (Clobber != "cc")
|
||||
Clobber = getTarget().getNormalizedGCCRegisterName(Clobber);
|
||||
|
||||
if (!Constraints.empty())
|
||||
|
@ -2063,6 +2077,16 @@ void CodeGenFunction::EmitAsmStmt(const AsmStmt &S) {
|
|||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::NoUnwind);
|
||||
|
||||
// Attach readnone and readonly attributes.
|
||||
if (!HasSideEffect) {
|
||||
if (ReadNone)
|
||||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::ReadNone);
|
||||
else if (ReadOnly)
|
||||
Result->addAttribute(llvm::AttributeSet::FunctionIndex,
|
||||
llvm::Attribute::ReadOnly);
|
||||
}
|
||||
|
||||
// Slap the source location of the inline asm into a !srcloc metadata on the
|
||||
// call.
|
||||
if (const GCCAsmStmt *gccAsmStmt = dyn_cast<GCCAsmStmt>(&S)) {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
// RUN: %clang_cc1 -triple armv7-apple-darwin -emit-llvm %s -o - | FileCheck %s
|
||||
|
||||
// CHECK: call i32 asm "foo0", {{.*}} [[READNONE:#[0-9]+]]
|
||||
// CHECK: call i32 asm "foo1", {{.*}} [[READNONE]]
|
||||
// CHECK: call i32 asm "foo2", {{.*}} [[NOATTRS:#[0-9]+]]
|
||||
// CHECK: call i32 asm sideeffect "foo3", {{.*}} [[NOATTRS]]
|
||||
// CHECK: call i32 asm "foo4", {{.*}} [[READONLY:#[0-9]+]]
|
||||
// CHECK: call i32 asm "foo5", {{.*}} [[READONLY]]
|
||||
// CHECK: call i32 asm "foo6", {{.*}} [[NOATTRS]]
|
||||
// CHECK: call void asm sideeffect "foo7", {{.*}} [[NOATTRS]]
|
||||
// CHECK: call void asm "foo8", {{.*}} [[NOATTRS]]
|
||||
|
||||
// CHECK: attributes [[READNONE]] = { nounwind readnone }
|
||||
// CHECK: attributes [[NOATTRS]] = { nounwind }
|
||||
// CHECK: attributes [[READONLY]] = { nounwind readonly }
|
||||
|
||||
int g0, g1;
|
||||
|
||||
struct S {
|
||||
int i;
|
||||
} g2;
|
||||
|
||||
void test_attrs(int a) {
|
||||
__asm__ ("foo0" : "=r"(g1) : "r"(a));
|
||||
__asm__ ("foo1" : "=r"(g1) : "r"(a) : "cc");
|
||||
__asm__ ("foo2" : "=r"(g1) : "r"(a) : "memory");
|
||||
__asm__ volatile("foo3" : "=r"(g1) : "r"(a));
|
||||
__asm__ ("foo4" : "=r"(g1) : "r"(a), "m"(g0));
|
||||
__asm__ ("foo5" : "=r"(g1) : "r"(a), "Q"(g0));
|
||||
__asm__ ("foo6" : "=r"(g1), "=m"(g0) : "r"(a));
|
||||
__asm__ ("foo7" : : "r"(a));
|
||||
__asm__ ("foo8" : "=r"(g2) : "r"(a));
|
||||
}
|
Loading…
Reference in New Issue