[llvm] r278081 - [WebAssembly] Fix bugs in WebAssemblyLowerEmscriptenExceptions pass

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 8 17:29:56 PDT 2016


Author: dschuff
Date: Mon Aug  8 19:29:55 2016
New Revision: 278081

URL: http://llvm.org/viewvc/llvm-project?rev=278081&view=rev
Log:
[WebAssembly] Fix bugs in WebAssemblyLowerEmscriptenExceptions pass

* Delete extra '_' prefixes from JS library function names. fixImports()
  function in JS glue code deals with this for wasm.
* Change command-line option names in order to be consistent with
  asm.js.
* Add missing lowering code for llvm.eh.typeid.for intrinsics
* Delete commas in mangled function names
* Fix a function argument attributes bug. Because we add the pointer to
  the original callee as the first argument of invoke wrapper, all
  argument attribute indices have to be incremented by one.

Patch by Heejin Ahn

Differential Revision: https://reviews.llvm.org/D23258

Modified:
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp?rev=278081&r1=278080&r2=278081&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenExceptions.cpp Mon Aug  8 19:29:55 2016
@@ -24,7 +24,7 @@
 /// This pass does following things:
 ///
 /// 1) Create three global variables: __THREW__, threwValue, and tempRet0.
-///    tempRet0 will be set within ___cxa_find_matching_catch() function in
+///    tempRet0 will be set within __cxa_find_matching_catch() function in
 ///    JS library, and __THREW__ and threwValue will be set in invoke wrappers
 ///    in JS glue code. For what invoke wrappers are, refer to 3).
 ///
@@ -77,31 +77,33 @@
 ///      %val = landingpad catch c1 catch c2 catch c3 ...
 ///      ... use %val ...
 ///    into
-///      %fmc = call @___cxa_find_matching_catch_N(c1, c2, c3, ...)
+///      %fmc = call @__cxa_find_matching_catch_N(c1, c2, c3, ...)
 ///      %val = {%fmc, tempRet0}
 ///      ... use %val ...
 ///    Here N is a number calculated based on the number of clauses.
-///    Global variable tempRet0 is set within ___cxa_find_matching_catch() in
+///    Global variable tempRet0 is set within __cxa_find_matching_catch() in
 ///    JS glue code.
 ///
 /// 5) Lower
 ///      resume {%a, %b}
 ///    into
-///      call @___resumeException(%a)
-///    where ___resumeException() is a function in JS glue code.
+///      call @__resumeException(%a)
+///    where __resumeException() is a function in JS glue code.
 ///
-/// TODO: Handle i64 types
+/// 6) Lower
+///      call @llvm.eh.typeid.for(type) (intrinsic)
+///    into
+///      call @llvm_eh_typeid_for(type)
+///    llvm_eh_typeid_for function will be generated in JS glue code.
 ///
 ///===----------------------------------------------------------------------===//
 
 #include "WebAssembly.h"
-#include "llvm/ADT/IndexedMap.h"
-#include "llvm/IR/Constants.h"
+#include "llvm/IR/CallSite.h"
 #include "llvm/IR/IRBuilder.h"
-#include "llvm/IR/Instructions.h"
 #include "llvm/IR/Module.h"
-#include "llvm/Pass.h"
 #include "llvm/Support/raw_ostream.h"
+#include <set>
 
 using namespace llvm;
 
@@ -114,9 +116,9 @@ class WebAssemblyLowerEmscriptenExceptio
   }
 
   bool runOnFunction(Function &F);
-  // Returns ___cxa_find_matching_catch_N function, where N = NumClauses + 2.
+  // Returns __cxa_find_matching_catch_N function, where N = NumClauses + 2.
   // This is because a landingpad instruction contains two more arguments,
-  // a personality function and a cleanup bit, and ___cxa_find_matching_catch_N
+  // a personality function and a cleanup bit, and __cxa_find_matching_catch_N
   // functions are named after the number of arguments in the original
   // landingpad instruction.
   Function *getFindMatchingCatch(Module &M, unsigned NumClauses);
@@ -126,8 +128,9 @@ class WebAssemblyLowerEmscriptenExceptio
   GlobalVariable *ThrewGV;      // __THREW__
   GlobalVariable *ThrewValueGV; // threwValue
   GlobalVariable *TempRet0GV;   // tempRet0
-  Function *ResumeF;
-  // ___cxa_find_matching_catch_N functions.
+  Function *ResumeF;            // __resumeException
+  Function *EHTypeIdF;          // llvm_eh_typeid_for
+  // __cxa_find_matching_catch_N functions.
   // Indexed by the number of clauses in an original landingpad instruction.
   DenseMap<int, Function *> FindMatchingCatches;
   // Map of <function signature string, invoke_ wrappers>
@@ -178,9 +181,9 @@ static inline std::string createGlobalVa
 
 // Simple function name mangler.
 // This function simply takes LLVM's string representation of parameter types
-// concatenate them with '_'. There are non-alphanumeric characters but llc is
-// ok with it, and we need to postprocess these names after the lowering phase
-// anyway.
+// and concatenate them with '_'. There are non-alphanumeric characters but llc
+// is ok with it, and we need to postprocess these names after the lowering
+// phase anyway.
 static std::string getSignature(FunctionType *FTy) {
   std::string Sig;
   raw_string_ostream OS(Sig);
@@ -191,6 +194,9 @@ static std::string getSignature(Function
     OS << "_...";
   Sig = OS.str();
   Sig.erase(std::remove_if(Sig.begin(), Sig.end(), isspace), Sig.end());
+  // When s2wasm parses .s file, a comma means the end of an argument. So a
+  // mangled function name can contain any character but a comma.
+  std::replace(Sig.begin(), Sig.end(), ',', '.');
   return Sig;
 }
 
@@ -203,7 +209,7 @@ Function *WebAssemblyLowerEmscriptenExce
   FunctionType *FTy = FunctionType::get(Int8PtrTy, Args, false);
   Function *F = Function::Create(
       FTy, GlobalValue::ExternalLinkage,
-      "___cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
+      "__cxa_find_matching_catch_" + Twine(NumClauses + 2), &M);
   FindMatchingCatches[NumClauses] = F;
   return F;
 }
@@ -239,10 +245,12 @@ WebAssemblyLowerEmscriptenExceptions::ge
 }
 
 bool WebAssemblyLowerEmscriptenExceptions::runOnModule(Module &M) {
-  IRBuilder<> Builder(M.getContext());
+  LLVMContext &C = M.getContext();
+  IRBuilder<> Builder(C);
   IntegerType *Int1Ty = Builder.getInt1Ty();
   PointerType *Int8PtrTy = Builder.getInt8PtrTy();
   IntegerType *Int32Ty = Builder.getInt32Ty();
+  Type *VoidTy = Builder.getVoidTy();
 
   // Create global variables __THREW__, threwValue, and tempRet0
   ThrewGV = new GlobalVariable(M, Int1Ty, false, GlobalValue::ExternalLinkage,
@@ -255,11 +263,15 @@ bool WebAssemblyLowerEmscriptenException
       M, Int32Ty, false, GlobalValue::ExternalLinkage, Builder.getInt32(0),
       createGlobalValueName(M, "tempRet0"));
 
-  // Register ___resumeException function
-  Type *VoidTy = Type::getVoidTy(M.getContext());
+  // Register __resumeException function
   FunctionType *ResumeFTy = FunctionType::get(VoidTy, Int8PtrTy, false);
   ResumeF = Function::Create(ResumeFTy, GlobalValue::ExternalLinkage,
-                             "___resumeException", &M);
+                             "__resumeException", &M);
+
+  // Register llvm_eh_typeid_for function
+  FunctionType *EHTypeIdTy = FunctionType::get(Int32Ty, Int8PtrTy, false);
+  EHTypeIdF = Function::Create(EHTypeIdTy, GlobalValue::ExternalLinkage,
+                               "llvm_eh_typeid_for", &M);
 
   bool Changed = false;
   for (Function &F : M) {
@@ -283,9 +295,9 @@ bool WebAssemblyLowerEmscriptenException
   Argument *Arg2 = &*(++F->arg_begin());
   Arg1->setName("threw");
   Arg2->setName("value");
-  BasicBlock *EntryBB = BasicBlock::Create(M.getContext(), "entry", F);
-  BasicBlock *ThenBB = BasicBlock::Create(M.getContext(), "if.then", F);
-  BasicBlock *EndBB = BasicBlock::Create(M.getContext(), "if.end", F);
+  BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F);
+  BasicBlock *ThenBB = BasicBlock::Create(C, "if.then", F);
+  BasicBlock *EndBB = BasicBlock::Create(C, "if.end", F);
 
   Builder.SetInsertPoint(EntryBB);
   Value *Threw = Builder.CreateLoad(ThrewGV, ThrewGV->getName() + ".val");
@@ -305,7 +317,7 @@ bool WebAssemblyLowerEmscriptenException
   FTy = FunctionType::get(VoidTy, Params, false);
   F = Function::Create(FTy, GlobalValue::ExternalLinkage, "setTempRet0", &M);
   F->arg_begin()->setName("value");
-  EntryBB = BasicBlock::Create(M.getContext(), "entry", F);
+  EntryBB = BasicBlock::Create(C, "entry", F);
   Builder.SetInsertPoint(EntryBB);
   Builder.CreateStore(&*F->arg_begin(), TempRet0GV);
   Builder.CreateRetVoid();
@@ -315,10 +327,12 @@ bool WebAssemblyLowerEmscriptenException
 
 bool WebAssemblyLowerEmscriptenExceptions::runOnFunction(Function &F) {
   Module &M = *F.getParent();
-  IRBuilder<> Builder(M.getContext());
+  LLVMContext &C = F.getContext();
+  IRBuilder<> Builder(C);
   bool Changed = false;
   SmallVector<Instruction *, 64> ToErase;
   SmallPtrSet<LandingPadInst *, 32> LandingPads;
+  bool AllowExceptions = true; // will later change based on whitelist option
 
   for (BasicBlock &BB : F) {
     auto *II = dyn_cast<InvokeInst>(BB.getTerminator());
@@ -328,7 +342,8 @@ bool WebAssemblyLowerEmscriptenException
     LandingPads.insert(II->getLandingPadInst());
     Builder.SetInsertPoint(II);
 
-    if (canThrow(II->getCalledValue())) {
+    bool NeedInvoke = AllowExceptions && canThrow(II->getCalledValue());
+    if (NeedInvoke) {
       // If we are calling a function that is noreturn, we must remove that
       // attribute. The code we insert here does expect it to return, after we
       // catch the exception.
@@ -336,7 +351,7 @@ bool WebAssemblyLowerEmscriptenException
         if (auto *F = dyn_cast<Function>(II->getCalledValue()))
           F->removeFnAttr(Attribute::NoReturn);
         AttributeSet NewAttrs = II->getAttributes();
-        NewAttrs.removeAttribute(M.getContext(), AttributeSet::FunctionIndex,
+        NewAttrs.removeAttribute(C, AttributeSet::FunctionIndex,
                                  Attribute::NoReturn);
         II->setAttributes(NewAttrs);
       }
@@ -354,8 +369,32 @@ bool WebAssemblyLowerEmscriptenException
       CallInst *NewCall = Builder.CreateCall(getInvokeWrapper(M, II), CallArgs);
       NewCall->takeName(II);
       NewCall->setCallingConv(II->getCallingConv());
-      NewCall->setAttributes(II->getAttributes());
       NewCall->setDebugLoc(II->getDebugLoc());
+
+      // Because we added the pointer to the callee as first argument, all
+      // argument attribute indices have to be incremented by one.
+      SmallVector<AttributeSet, 8> AttributesVec;
+      const AttributeSet &InvokePAL = II->getAttributes();
+      CallSite::arg_iterator AI = II->arg_begin();
+      unsigned i = 1; // Argument attribute index starts from 1
+      for (unsigned e = II->getNumArgOperands(); i <= e; ++AI, ++i) {
+        if (InvokePAL.hasAttributes(i)) {
+          AttrBuilder B(InvokePAL, i);
+          AttributesVec.push_back(AttributeSet::get(C, i + 1, B));
+        }
+      }
+      // Add any return attributes.
+      if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex))
+        AttributesVec.push_back(
+            AttributeSet::get(C, InvokePAL.getRetAttributes()));
+      // Add any function attributes.
+      if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex))
+        AttributesVec.push_back(
+            AttributeSet::get(C, InvokePAL.getFnAttributes()));
+      // Reconstruct the AttributesList based on the vector we constructed.
+      AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec);
+      NewCall->setAttributes(NewCallPAL);
+
       II->replaceAllUsesWith(NewCall);
       ToErase.push_back(II);
 
@@ -374,8 +413,8 @@ bool WebAssemblyLowerEmscriptenException
       CallInst *NewCall = Builder.CreateCall(II->getCalledValue(), CallArgs);
       NewCall->takeName(II);
       NewCall->setCallingConv(II->getCallingConv());
-      NewCall->setAttributes(II->getAttributes());
       NewCall->setDebugLoc(II->getDebugLoc());
+      NewCall->setAttributes(II->getAttributes());
       II->replaceAllUsesWith(NewCall);
       ToErase.push_back(II);
 
@@ -399,7 +438,7 @@ bool WebAssemblyLowerEmscriptenException
       Builder.SetInsertPoint(RI);
       Value *Low = Builder.CreateExtractValue(Input, 0, "low");
 
-      // Create a call to ___resumeException function
+      // Create a call to __resumeException function
       Value *Args[] = {Low};
       Builder.CreateCall(ResumeF, Args);
 
@@ -409,6 +448,26 @@ bool WebAssemblyLowerEmscriptenException
     }
   }
 
+  // Process llvm.eh.typeid.for intrinsics
+  for (BasicBlock &BB : F) {
+    for (Instruction &I : BB) {
+      auto *CI = dyn_cast<CallInst>(&I);
+      if (!CI)
+        continue;
+      const Function *Callee = CI->getCalledFunction();
+      if (!Callee)
+        continue;
+      if (Callee->getIntrinsicID() != Intrinsic::eh_typeid_for)
+        continue;
+
+      Builder.SetInsertPoint(CI);
+      CallInst *NewCI =
+          Builder.CreateCall(EHTypeIdF, CI->getArgOperand(0), "typeid");
+      CI->replaceAllUsesWith(NewCI);
+      ToErase.push_back(CI);
+    }
+  }
+
   // Look for orphan landingpads, can occur in blocks with no predecesors
   for (BasicBlock &BB : F) {
     Instruction *I = BB.getFirstNonPHI();
@@ -437,7 +496,7 @@ bool WebAssemblyLowerEmscriptenException
         FMCArgs.push_back(Clause);
     }
 
-    // Create a call to ___cxa_find_matching_catch_N function
+    // Create a call to __cxa_find_matching_catch_N function
     Function *FMCF = getFindMatchingCatch(M, FMCArgs.size());
     CallInst *FMCI = Builder.CreateCall(FMCF, FMCArgs, "fmc");
     Value *Undef = UndefValue::get(LPI->getType());

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=278081&r1=278080&r2=278081&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Mon Aug  8 19:29:55 2016
@@ -31,7 +31,7 @@ using namespace llvm;
 
 // Emscripten's asm.js-style exception handling
 static cl::opt<bool> EnableEmExceptionHandling(
-    "wasm-em-exception-handling",
+    "enable-emscripten-cxx-exceptions",
     cl::desc("WebAssembly Emscripten-style exception handling"),
     cl::init(false));
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll?rev=278081&r1=278080&r2=278081&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll Mon Aug  8 19:29:55 2016
@@ -30,17 +30,20 @@ lpad:
   %2 = extractvalue { i8*, i32 } %0, 1
   br label %catch.dispatch
 ; CHECK: lpad:
-; CHECK-NEXT: %[[FMC:.*]] = call i8* @___cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* null)
+; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* null)
 ; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0
 ; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]]
 ; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1
 ; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 0
-; CHECK-NEXT: extractvalue { i8*, i32 } %[[IVI2]], 1
+; CHECK-NEXT: %[[CDR:.*]] = extractvalue { i8*, i32 } %[[IVI2]], 1
 
 catch.dispatch:                                   ; preds = %lpad
   %3 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
   %matches = icmp eq i32 %2, %3
   br i1 %matches, label %catch1, label %catch
+; CHECK: catch.dispatch:
+; CHECK-NEXT: %[[TYPEID:.*]] = call i32 @llvm_eh_typeid_for(i8* bitcast (i8** @_ZTIi to i8*))
+; CHECK-NEXT: %matches = icmp eq i32 %[[CDR]], %[[TYPEID]]
 
 catch1:                                           ; preds = %catch.dispatch
   %4 = call i8* @__cxa_begin_catch(i8* %1)
@@ -81,7 +84,7 @@ lpad:
   %2 = extractvalue { i8*, i32 } %0, 1
   br label %filter.dispatch
 ; CHECK: lpad:
-; CHECK-NEXT: %[[FMC:.*]] = call i8* @___cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*))
+; CHECK-NEXT: %[[FMC:.*]] = call i8* @__cxa_find_matching_catch_4(i8* bitcast (i8** @_ZTIi to i8*), i8* bitcast (i8** @_ZTIc to i8*))
 ; CHECK-NEXT: %[[IVI1:.*]] = insertvalue { i8*, i32 } undef, i8* %[[FMC]], 0
 ; CHECK-NEXT: %[[TEMPRET0_VAL:.*]] = load i32, i32* @[[TEMPRET0]]
 ; CHECK-NEXT: %[[IVI2:.*]] = insertvalue { i8*, i32 } %[[IVI1]], i32 %[[TEMPRET0_VAL]], 1
@@ -104,11 +107,54 @@ eh.resume:
 ; CHECK-NEXT: insertvalue
 ; CHECK-NEXT: %[[LPAD_VAL:.*]] = insertvalue
 ; CHECK-NEXT: %[[LOW:.*]] = extractvalue { i8*, i32 } %[[LPAD_VAL]], 0
-; CHECK-NEXT: call void @___resumeException(i8* %[[LOW]])
+; CHECK-NEXT: call void @__resumeException(i8* %[[LOW]])
 ; CHECK-NEXT: unreachable
 }
 
+; Test if argument attributes indices in newly created call instructions are correct
+define void @arg_attributes() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
+; CHECK-LABEL: @arg_attributes(
+entry:
+  %0 = invoke noalias i8* @bar(i8 signext 1, i8 zeroext 2)
+          to label %invoke.cont unwind label %lpad
+; CHECK: entry:
+; CHECK-NEXT: store i1 false, i1* @[[__THREW__]]
+; CHECK-NEXT: %0 = call noalias i8* @"__invoke_i8*_i8_i8"(i8* (i8, i8)* @bar, i8 signext 1, i8 zeroext 2)
+
+invoke.cont:                                      ; preds = %entry
+  br label %try.cont
+
+lpad:                                             ; preds = %entry
+  %1 = landingpad { i8*, i32 }
+          catch i8* bitcast (i8** @_ZTIi to i8*)
+          catch i8* null
+  %2 = extractvalue { i8*, i32 } %1, 0
+  %3 = extractvalue { i8*, i32 } %1, 1
+  br label %catch.dispatch
+
+catch.dispatch:                                   ; preds = %lpad
+  %4 = call i32 @llvm.eh.typeid.for(i8* bitcast (i8** @_ZTIi to i8*))
+  %matches = icmp eq i32 %3, %4
+  br i1 %matches, label %catch1, label %catch
+
+catch1:                                           ; preds = %catch.dispatch
+  %5 = call i8* @__cxa_begin_catch(i8* %2)
+  %6 = bitcast i8* %5 to i32*
+  %7 = load i32, i32* %6, align 4
+  call void @__cxa_end_catch()
+  br label %try.cont
+
+try.cont:                                         ; preds = %catch, %catch1, %invoke.cont
+  ret void
+
+catch:                                            ; preds = %catch.dispatch
+  %8 = call i8* @__cxa_begin_catch(i8* %2)
+  call void @__cxa_end_catch()
+  br label %try.cont
+}
+
 declare void @foo(i32)
+declare i8* @bar(i8, i8)
 
 declare i32 @__gxx_personality_v0(...)
 declare i32 @llvm.eh.typeid.for(i8*)
@@ -117,9 +163,9 @@ declare void @__cxa_end_catch()
 declare void @__cxa_call_unexpected(i8*)
 
 ; JS glue functions and invoke wrappers registration
-; CHECK: declare void @___resumeException(i8*)
+; CHECK: declare void @__resumeException(i8*)
 ; CHECK: declare void @__invoke_void_i32(void (i32)*, i32)
-; CHECK: declare i8* @___cxa_find_matching_catch_4(i8*, i8*)
+; CHECK: declare i8* @__cxa_find_matching_catch_4(i8*, i8*)
 
 ; setThrew function creation
 ; CHECK-LABEL: define void @setThrew(i1 %threw, i32 %value) {




More information about the llvm-commits mailing list