Make instcombine promote inline asm calls to 'nounwind'
authorDuncan Sands <baldrick@free.fr>
Sun, 16 Dec 2007 15:51:49 +0000 (15:51 +0000)
committerDuncan Sands <baldrick@free.fr>
Sun, 16 Dec 2007 15:51:49 +0000 (15:51 +0000)
calls.  Remove special casing of inline asm from the
inliner.  There is a potential problem: the verifier
rejects invokes of inline asm (not sure why).  If an
asm call is not marked "nounwind" in some .ll, and
instcombine is not run, but the inliner is run, then
an illegal module will be created.  This is bad but
I'm not sure what the best approach is.  I'm tempted
to remove the check in the verifier...

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@45073 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Support/CallSite.h
lib/Transforms/Scalar/InstructionCombining.cpp
lib/Transforms/Utils/InlineFunction.cpp
lib/VMCore/Instructions.cpp
test/CFrontend/2007-12-16-AsmNoUnwind.c [new file with mode: 0644]
test/Transforms/Inline/2007-04-15-InlineEH.ll
test/Transforms/InstCombine/2007-12-16-AsmNoUnwind.ll [new file with mode: 0644]

index 5bb60a8a8af95afcd2cbf3fdf2a9b012dd90b58a..3735842e7244be5d5844b4a2ee492f5abcb8dd3a 100644 (file)
@@ -73,6 +73,9 @@ public:
   /// @brief Determine if the call does not access or only reads memory.
   bool onlyReadsMemory() const;
 
   /// @brief Determine if the call does not access or only reads memory.
   bool onlyReadsMemory() const;
 
+  /// @brief Determine if the call cannot unwind.
+  bool isNoUnwind() const;
+
   /// getType - Return the type of the instruction that generated this call site
   ///
   const Type *getType() const { return I->getType(); }
   /// getType - Return the type of the instruction that generated this call site
   ///
   const Type *getType() const { return I->getType(); }
index 653d35e34f49a8f37b0270626198cdc9496a0284..aa9e932fc527379c732c9d203e59c280093e6799 100644 (file)
@@ -7972,6 +7972,19 @@ Instruction *InstCombiner::visitCallSite(CallSite CS) {
       }
   }
 
       }
   }
 
+  if (isa<InlineAsm>(Callee) && !CS.isNoUnwind()) {
+    // Inline asm calls cannot throw - mark them 'nounwind'.
+    const ParamAttrsList *PAL = CS.getParamAttrs();
+    uint16_t RAttributes = PAL ? PAL->getParamAttrs(0) : 0;
+    RAttributes |= ParamAttr::NoUnwind;
+
+    ParamAttrsVector modVec;
+    modVec.push_back(ParamAttrsWithIndex::get(0, RAttributes));
+    PAL = ParamAttrsList::getModified(PAL, modVec);
+    CS.setParamAttrs(PAL);
+    Changed = true;
+  }
+
   return Changed ? CS.getInstruction() : 0;
 }
 
   return Changed ? CS.getInstruction() : 0;
 }
 
index e9f6b28e98b5259853d784452e9e069aba702c43..3d31f71300ac7855ff59c48afd10c3b6b27156c7 100644 (file)
@@ -69,9 +69,8 @@ static void HandleInlinedInvoke(InvokeInst *II, BasicBlock *FirstNewBlock,
           if (!isa<CallInst>(I)) continue;
           CallInst *CI = cast<CallInst>(I);
 
           if (!isa<CallInst>(I)) continue;
           CallInst *CI = cast<CallInst>(I);
 
-          // If this call cannot unwind or is an inline asm, don't
-          // convert it to an invoke.
-          if (CI->isNoUnwind() || isa<InlineAsm>(CI->getCalledValue()))
+          // If this call cannot unwind, don't convert it to an invoke.
+          if (CI->isNoUnwind())
             continue;
 
           // Convert this function call into an invoke instruction.
             continue;
 
           // Convert this function call into an invoke instruction.
index 5207ea52f49325370b0bc340a1d82d9cb6fbf2f6..511a0e851a10e9747a6ff5d5c66f52b78497ce36 100644 (file)
@@ -65,6 +65,12 @@ bool CallSite::onlyReadsMemory() const {
   else
     return cast<InvokeInst>(I)->onlyReadsMemory();
 }
   else
     return cast<InvokeInst>(I)->onlyReadsMemory();
 }
+bool CallSite::isNoUnwind() const {
+  if (CallInst *CI = dyn_cast<CallInst>(I))
+    return CI->isNoUnwind();
+  else
+    return cast<InvokeInst>(I)->isNoUnwind();
+}
 
 
 
 
 
 
diff --git a/test/CFrontend/2007-12-16-AsmNoUnwind.c b/test/CFrontend/2007-12-16-AsmNoUnwind.c
new file mode 100644 (file)
index 0000000..b080e6a
--- /dev/null
@@ -0,0 +1,3 @@
+// RUN: %llvmgcc %s -S -o - | grep nounwind
+
+void bar() { asm (""); }
index 73b0e215e8c51a66e228d30e87d50a51f35eb239..9d28755d289054e9f4500946c42daf744993a6ce 100644 (file)
@@ -8,7 +8,7 @@ target triple = "i686-pc-linux-gnu"
 
 define void @bc__support__high_resolution_time__clock() {
 entry:
 
 define void @bc__support__high_resolution_time__clock() {
 entry:
-       call void asm "rdtsc\0A\09movl %eax, $0\0A\09movl %edx, $1", "=*imr,=*imr,~{dirflag},~{fpsr},~{flags},~{dx},~{ax}"( i32* null, i32* null )
+       call void asm "rdtsc\0A\09movl %eax, $0\0A\09movl %edx, $1", "=*imr,=*imr,~{dirflag},~{fpsr},~{flags},~{dx},~{ax}"( i32* null, i32* null ) nounwind
        unreachable
 }
 
        unreachable
 }
 
diff --git a/test/Transforms/InstCombine/2007-12-16-AsmNoUnwind.ll b/test/Transforms/InstCombine/2007-12-16-AsmNoUnwind.ll
new file mode 100644 (file)
index 0000000..336c6d5
--- /dev/null
@@ -0,0 +1,7 @@
+; RUN: llvm-as < %s | opt -instcombine | llvm-dis | grep nounwind
+
+define void @bar() {
+entry:
+        call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"( )
+        ret void
+}