[llvm] r277398 - [WebAssembly] Support CFI for WebAssembly target

Derek Schuff via llvm-commits llvm-commits at lists.llvm.org
Mon Aug 1 15:25:03 PDT 2016


Author: dschuff
Date: Mon Aug  1 17:25:02 2016
New Revision: 277398

URL: http://llvm.org/viewvc/llvm-project?rev=277398&view=rev
Log:
[WebAssembly] Support CFI for WebAssembly target

Summary: This patch implements CFI for WebAssembly. It modifies the
LowerTypeTest pass to pre-assign table indexes to functions that are
called indirectly, and lowers type checks to test against the
appropriate table indexes. It also modifies the WebAssembly backend to
support a special ".indidx" assembly directive that propagates the table
index assignments out to the linker.

Patch by Dominic Chen

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

Added:
    llvm/trunk/test/CodeGen/WebAssembly/cfi.ll
    llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll
Modified:
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
    llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp
    llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll
    llvm/trunk/test/Transforms/LowerTypeTests/function.ll

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h Mon Aug  1 17:25:02 2016
@@ -59,6 +59,7 @@ enum Directive {
   DotResult = UINT64_MAX - 1,  ///< .result
   DotLocal = UINT64_MAX - 2,   ///< .local
   DotEndFunc = UINT64_MAX - 3, ///< .endfunc
+  DotIndIdx = UINT64_MAX - 4,  /// < .indidx
 };
 
 } // end namespace WebAssembly
@@ -123,7 +124,8 @@ inline unsigned GetDefaultP2Align(unsign
   case WebAssembly::STORE_I64:
   case WebAssembly::STORE_F64:
     return 3;
-  default: llvm_unreachable("Only loads and stores have p2align values");
+  default:
+    llvm_unreachable("Only loads and stores have p2align values");
   }
 }
 

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp Mon Aug  1 17:25:02 2016
@@ -67,13 +67,18 @@ void WebAssemblyTargetAsmStreamer::emitE
 void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType(
     StringRef name, SmallVectorImpl<MVT> &SignatureVTs, size_t NumResults) {
   OS << "\t.functype\t" << name;
-  if (NumResults == 0) OS << ", void";
+  if (NumResults == 0)
+    OS << ", void";
   for (auto Ty : SignatureVTs) {
     OS << ", " << WebAssembly::TypeToString(Ty);
   }
   OS << "\n";
 }
 
+void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
+  OS << "\t.indidx  \t" << *Value << '\n';
+}
+
 // FIXME: What follows is not the real binary encoding.
 
 static void EncodeTypes(MCStreamer &Streamer, ArrayRef<MVT> Types) {
@@ -100,3 +105,8 @@ void WebAssemblyTargetELFStreamer::emitL
 void WebAssemblyTargetELFStreamer::emitEndFunc() {
   Streamer.EmitIntValue(WebAssembly::DotEndFunc, sizeof(uint64_t));
 }
+
+void WebAssemblyTargetELFStreamer::emitIndIdx(const MCExpr *Value) {
+  Streamer.EmitIntValue(WebAssembly::DotIndIdx, sizeof(uint64_t));
+  Streamer.EmitValue(Value, sizeof(uint64_t));
+}

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h Mon Aug  1 17:25:02 2016
@@ -43,6 +43,8 @@ public:
                                         size_t NumResults) {
     llvm_unreachable("emitIndirectFunctionType not implemented");
   }
+  /// .indidx
+  virtual void emitIndIdx(const MCExpr *Value) = 0;
 };
 
 /// This part is for ascii assembly output
@@ -59,6 +61,7 @@ public:
   void emitIndirectFunctionType(StringRef name,
                                 SmallVectorImpl<MVT> &SignatureVTs,
                                 size_t NumResults) override;
+  void emitIndIdx(const MCExpr *Value) override;
 };
 
 /// This part is for ELF object output
@@ -70,6 +73,7 @@ public:
   void emitResult(ArrayRef<MVT> Types) override;
   void emitLocal(ArrayRef<MVT> Types) override;
   void emitEndFunc() override;
+  void emitIndIdx(const MCExpr *Value) override;
 };
 
 } // end namespace llvm

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Mon Aug  1 17:25:02 2016
@@ -14,10 +14,10 @@
 ///
 //===----------------------------------------------------------------------===//
 
-#include "WebAssembly.h"
 #include "InstPrinter/WebAssemblyInstPrinter.h"
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
+#include "WebAssembly.h"
 #include "WebAssemblyMCInstLower.h"
 #include "WebAssemblyMachineFunctionInfo.h"
 #include "WebAssemblyRegisterInfo.h"
@@ -183,6 +183,15 @@ void WebAssemblyAsmPrinter::EmitFunction
 
   SmallVector<MVT, 4> ResultVTs;
   const Function &F(*MF->getFunction());
+
+  // Emit the function index.
+  if (MDNode *Idx = F.getMetadata("wasm.index")) {
+    assert(Idx->getNumOperands() == 1);
+
+    getTargetStreamer()->emitIndIdx(AsmPrinter::lowerConstant(
+        cast<ConstantAsMetadata>(Idx->getOperand(0))->getValue()));
+  }
+
   ComputeLegalValueVTs(F, TM, F.getReturnType(), ResultVTs);
 
   // If the return type needs to be legalized it will get converted into

Modified: llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp (original)
+++ llvm/trunk/lib/Transforms/IPO/LowerTypeTests.cpp Mon Aug  1 17:25:02 2016
@@ -13,7 +13,6 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/Transforms/IPO/LowerTypeTests.h"
-#include "llvm/Transforms/IPO.h"
 #include "llvm/ADT/EquivalenceClasses.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/ADT/Triple.h"
@@ -30,6 +29,7 @@
 #include "llvm/Pass.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/raw_ostream.h"
+#include "llvm/Transforms/IPO.h"
 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
 
 using namespace llvm;
@@ -79,8 +79,7 @@ bool BitSetInfo::containsValue(
     if (!Result)
       return false;
     COffset += APOffset.getZExtValue();
-    return containsValue(DL, GlobalLayout, GEP->getPointerOperand(),
-                         COffset);
+    return containsValue(DL, GlobalLayout, GEP->getPointerOperand(), COffset);
   }
 
   if (auto Op = dyn_cast<Operator>(V)) {
@@ -222,6 +221,9 @@ struct LowerTypeTests : public ModulePas
   IntegerType *Int64Ty;
   IntegerType *IntPtrTy;
 
+  // Indirect function call index assignment counter for WebAssembly
+  uint64_t IndirectIndex;
+
   // Mapping from type identifiers to the call sites that test them.
   DenseMap<Metadata *, std::vector<CallInst *>> TypeTestCallSites;
 
@@ -250,6 +252,10 @@ struct LowerTypeTests : public ModulePas
   void verifyTypeMDNode(GlobalObject *GO, MDNode *Type);
   void buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
                                  ArrayRef<Function *> Functions);
+  void buildBitSetsFromFunctionsX86(ArrayRef<Metadata *> TypeIds,
+                                    ArrayRef<Function *> Functions);
+  void buildBitSetsFromFunctionsWASM(ArrayRef<Metadata *> TypeIds,
+                                     ArrayRef<Function *> Functions);
   void buildBitSetsFromDisjointSet(ArrayRef<Metadata *> TypeIds,
                                    ArrayRef<GlobalObject *> Globals);
   bool lower();
@@ -267,8 +273,7 @@ ModulePass *llvm::createLowerTypeTestsPa
 /// Build a bit set for TypeId using the object layouts in
 /// GlobalLayout.
 BitSetInfo LowerTypeTests::buildBitSet(
-    Metadata *TypeId,
-    const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) {
+    Metadata *TypeId, const DenseMap<GlobalObject *, uint64_t> &GlobalLayout) {
   BitSetBuilder BSB;
 
   // Compute the byte offset of each address associated with this type
@@ -281,8 +286,9 @@ BitSetInfo LowerTypeTests::buildBitSet(
       if (Type->getOperand(1) != TypeId)
         continue;
       uint64_t Offset =
-          cast<ConstantInt>(cast<ConstantAsMetadata>(Type->getOperand(0))
-                                ->getValue())->getZExtValue();
+          cast<ConstantInt>(
+              cast<ConstantAsMetadata>(Type->getOperand(0))->getValue())
+              ->getZExtValue();
       BSB.addOffset(GlobalAndOffset.second + Offset);
     }
   }
@@ -311,8 +317,8 @@ ByteArrayInfo *LowerTypeTests::createByt
   // we know the offset and mask to use.
   auto ByteArrayGlobal = new GlobalVariable(
       *M, Int8Ty, /*isConstant=*/true, GlobalValue::PrivateLinkage, nullptr);
-  auto MaskGlobal = new GlobalVariable(
-      *M, Int8Ty, /*isConstant=*/true, GlobalValue::PrivateLinkage, nullptr);
+  auto MaskGlobal = new GlobalVariable(*M, Int8Ty, /*isConstant=*/true,
+                                       GlobalValue::PrivateLinkage, nullptr);
 
   ByteArrayInfos.emplace_back();
   ByteArrayInfo *BAI = &ByteArrayInfos.back();
@@ -588,8 +594,7 @@ void LowerTypeTests::lowerTypeTestCalls(
 
 void LowerTypeTests::verifyTypeMDNode(GlobalObject *GO, MDNode *Type) {
   if (Type->getNumOperands() != 2)
-    report_fatal_error(
-        "All operands of type metadata must have 2 elements");
+    report_fatal_error("All operands of type metadata must have 2 elements");
 
   if (GO->isThreadLocal())
     report_fatal_error("Bit set element may not be thread-local");
@@ -612,9 +617,6 @@ void LowerTypeTests::verifyTypeMDNode(Gl
 static const unsigned kX86JumpTableEntrySize = 8;
 
 unsigned LowerTypeTests::getJumpTableEntrySize() {
-  if (Arch != Triple::x86 && Arch != Triple::x86_64)
-    report_fatal_error("Unsupported architecture for jump tables");
-
   return kX86JumpTableEntrySize;
 }
 
@@ -625,9 +627,6 @@ unsigned LowerTypeTests::getJumpTableEnt
 Constant *LowerTypeTests::createJumpTableEntry(GlobalObject *Src,
                                                Function *Dest,
                                                unsigned Distance) {
-  if (Arch != Triple::x86 && Arch != Triple::x86_64)
-    report_fatal_error("Unsupported architecture for jump tables");
-
   const unsigned kJmpPCRel32Code = 0xe9;
   const unsigned kInt3Code = 0xcc;
 
@@ -652,18 +651,27 @@ Constant *LowerTypeTests::createJumpTabl
 }
 
 Type *LowerTypeTests::getJumpTableEntryType() {
-  if (Arch != Triple::x86 && Arch != Triple::x86_64)
-    report_fatal_error("Unsupported architecture for jump tables");
-
   return StructType::get(M->getContext(),
                          {Int8Ty, Int32Ty, Int8Ty, Int8Ty, Int8Ty},
                          /*Packed=*/true);
 }
 
-/// Given a disjoint set of type identifiers and functions, build a jump table
-/// for the functions, build the bit sets and lower the llvm.type.test calls.
+/// Given a disjoint set of type identifiers and functions, build the bit sets
+/// and lower the llvm.type.test calls, architecture dependently.
 void LowerTypeTests::buildBitSetsFromFunctions(ArrayRef<Metadata *> TypeIds,
                                                ArrayRef<Function *> Functions) {
+  if (Arch == Triple::x86 || Arch == Triple::x86_64)
+    buildBitSetsFromFunctionsX86(TypeIds, Functions);
+  else if (Arch == Triple::wasm32 || Arch == Triple::wasm64)
+    buildBitSetsFromFunctionsWASM(TypeIds, Functions);
+  else
+    report_fatal_error("Unsupported architecture for jump tables");
+}
+
+/// Given a disjoint set of type identifiers and functions, build a jump table
+/// for the functions, build the bit sets and lower the llvm.type.test calls.
+void LowerTypeTests::buildBitSetsFromFunctionsX86(
+    ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
   // Unlike the global bitset builder, the function bitset builder cannot
   // re-arrange functions in a particular order and base its calculations on the
   // layout of the functions' entry points, as we have no idea how large a
@@ -795,6 +803,40 @@ void LowerTypeTests::buildBitSetsFromFun
       ConstantArray::get(JumpTableType, JumpTableEntries));
 }
 
+/// Assign a dummy layout using an incrementing counter, tag each function
+/// with its index represented as metadata, and lower each type test to an
+/// integer range comparison. During generation of the indirect function call
+/// table in the backend, it will assign the given indexes.
+/// Note: Dynamic linking is not supported, as the WebAssembly ABI has not yet
+/// been finalized.
+void LowerTypeTests::buildBitSetsFromFunctionsWASM(
+    ArrayRef<Metadata *> TypeIds, ArrayRef<Function *> Functions) {
+  assert(!Functions.empty());
+
+  // Build consecutive monotonic integer ranges for each call target set
+  DenseMap<GlobalObject *, uint64_t> GlobalLayout;
+  for (Function *F : Functions) {
+    // Skip functions that are not address taken, to avoid bloating the table
+    if (!F->hasAddressTaken())
+      continue;
+
+    // Store metadata with the index for each function
+    MDNode *MD = MDNode::get(F->getContext(),
+                             ArrayRef<Metadata *>(ConstantAsMetadata::get(
+                                 ConstantInt::get(Int64Ty, IndirectIndex))));
+    F->setMetadata("wasm.index", MD);
+
+    // Assign the counter value
+    GlobalLayout[F] = IndirectIndex++;
+  }
+
+  // The indirect function table index space starts at zero, so pass a NULL
+  // pointer as the subtracted "jump table" offset.
+  lowerTypeTestCalls(TypeIds,
+                     ConstantPointerNull::get(cast<PointerType>(Int32PtrTy)),
+                     GlobalLayout);
+}
+
 void LowerTypeTests::buildBitSetsFromDisjointSet(
     ArrayRef<Metadata *> TypeIds, ArrayRef<GlobalObject *> Globals) {
   llvm::DenseMap<Metadata *, uint64_t> TypeIdIndices;
@@ -900,8 +942,7 @@ bool LowerTypeTests::lower() {
 
     auto BitSetMDVal = dyn_cast<MetadataAsValue>(CI->getArgOperand(1));
     if (!BitSetMDVal)
-      report_fatal_error(
-          "Second argument of llvm.type.test must be metadata");
+      report_fatal_error("Second argument of llvm.type.test must be metadata");
     auto BitSet = BitSetMDVal->getMetadata();
 
     // Add the call site to the list of call sites for this type identifier. We
@@ -939,7 +980,8 @@ bool LowerTypeTests::lower() {
   for (GlobalClassesTy::iterator I = GlobalClasses.begin(),
                                  E = GlobalClasses.end();
        I != E; ++I) {
-    if (!I->isLeader()) continue;
+    if (!I->isLeader())
+      continue;
     ++NumTypeIdDisjointSets;
 
     unsigned MaxIndex = 0;
@@ -1000,6 +1042,7 @@ static void init(LowerTypeTests *LTT, Mo
   LTT->Int64Ty = Type::getInt64Ty(M.getContext());
   LTT->IntPtrTy = DL.getIntPtrType(M.getContext(), 0);
   LTT->TypeTestCallSites.clear();
+  LTT->IndirectIndex = 0;
 }
 
 bool LowerTypeTests::runOnModule(Module &M) {

Added: llvm/trunk/test/CodeGen/WebAssembly/cfi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfi.ll?rev=277398&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfi.ll (added)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfi.ll Mon Aug  1 17:25:02 2016
@@ -0,0 +1,53 @@
+; RUN: opt -S -lowertypetests < %s | llc -asm-verbose=false -disable-wasm-fallthrough-return-opt | FileCheck %s
+
+; Tests that we correctly assign indexes for control flow integrity.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+ at 0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
+
+; CHECK-LABEL: h:
+; CHECK-NOT: .indidx
+define void @h() !type !0 {
+  ret void
+}
+
+; CHECK-LABEL: f:
+; CHECK: .indidx 0
+define void @f() !type !0 {
+  ret void
+}
+
+; CHECK-LABEL: g:
+; CHECK: .indidx 1
+define void @g() !type !1 {
+  ret void
+}
+
+!0 = !{i32 0, !"typeid1"}
+!1 = !{i32 0, !"typeid2"}
+
+declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
+declare void @llvm.trap() nounwind noreturn
+
+; CHECK-LABEL: foo:
+; CHECK: br_if
+; CHECK: br_if
+; CHECK: unreachable
+define i1 @foo(i8* %p) {
+  %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
+  br i1 %x, label %contx, label %trap
+
+trap:
+  tail call void @llvm.trap() #1
+  unreachable
+
+contx:
+  %y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2")
+  br i1 %y, label %conty, label %trap
+
+conty:
+  %z = add i1 %x, %y
+  ret i1 %z
+}

Added: llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll?rev=277398&view=auto
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll (added)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function-disjoint.ll Mon Aug  1 17:25:02 2016
@@ -0,0 +1,45 @@
+; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X64 %s
+; RUN: opt -S -lowertypetests -mtriple=wasm32-unknown-unknown < %s | FileCheck --check-prefix=WASM32 %s
+
+; Tests that we correctly handle bitsets with disjoint call target sets.
+
+target datalayout = "e-p:64:64"
+
+; X64: @[[JT0:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[FNAME:.*]] to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; X64: @[[JT1:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[GNAME:.*]] to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; WASM32: private constant [0 x i8] zeroinitializer
+ at 0 = private unnamed_addr constant [2 x void ()*] [void ()* @f, void ()* @g], align 16
+
+; X64: @f = alias void (), bitcast ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to void ()*)
+; X64: @g = alias void (), bitcast ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to void ()*)
+
+; X64: define private void @[[FNAME]]()
+; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]]
+define void @f() !type !0 {
+  ret void
+}
+
+; X64: define private void @[[GNAME]]()
+; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
+define void @g() !type !1 {
+  ret void
+}
+
+!0 = !{i32 0, !"typeid1"}
+!1 = !{i32 0, !"typeid2"}
+
+declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
+
+define i1 @foo(i8* %p) {
+  ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT0]] to i64)
+  ; WASM32: icmp eq i64 {{.*}}, 0
+  %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
+  ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT1]] to i64)
+  ; WASM32: icmp eq i64 {{.*}}, 1
+  %y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2")
+  %z = add i1 %x, %y
+  ret i1 %z
+}
+
+; WASM32: ![[I0]] = !{i64 0}
+; WASM32: ![[I1]] = !{i64 1}

Modified: llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function-ext.ll Mon Aug  1 17:25:02 2016
@@ -1,16 +1,19 @@
-; RUN: opt -S -lowertypetests < %s | FileCheck %s
+; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X64 %s
+; RUN: opt -S -lowertypetests -mtriple=wasm32-unknown-unknown < %s | FileCheck --check-prefix=WASM32 %s
 
 ; Tests that we correctly handle external references, including the case where
 ; all functions in a bitset are external references.
 
-target triple = "x86_64-unknown-linux-gnu"
+; X64: @[[JT:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @foo to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; WASM32: private constant [0 x i8] zeroinitializer
 
+; WASM32: declare !type !{{[0-9]+}} void @foo()
 declare !type !0 void @foo()
 
-; CHECK: @[[JT:.*]] = private constant [1 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @foo to i64), i64 ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
-
 define i1 @bar(i8* %ptr) {
-  ; CHECK: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+  ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+  ; WASM32: sub i64 {{.*}}, 0
+  ; WASM32: icmp ult i64 {{.*}}, 1
   %p = call i1 @llvm.type.test(i8* %ptr, metadata !"void")
   ret i1 %p
 }
@@ -18,3 +21,4 @@ define i1 @bar(i8* %ptr) {
 declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
 
 !0 = !{i64 0, !"void"}
+; WASM-NOT: !{i64 0}

Modified: llvm/trunk/test/Transforms/LowerTypeTests/function.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/LowerTypeTests/function.ll?rev=277398&r1=277397&r2=277398&view=diff
==============================================================================
--- llvm/trunk/test/Transforms/LowerTypeTests/function.ll (original)
+++ llvm/trunk/test/Transforms/LowerTypeTests/function.ll Mon Aug  1 17:25:02 2016
@@ -1,22 +1,25 @@
-; RUN: opt -S -lowertypetests < %s | FileCheck %s
+; RUN: opt -S -lowertypetests -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck --check-prefix=X64 %s
+; RUN: opt -S -lowertypetests -mtriple=wasm32-unknown-unknown < %s | FileCheck --check-prefix=WASM32 %s
 
-; Tests that we correctly create a jump table for bitsets containing 2 or more
-; functions.
+; Tests that we correctly handle bitsets containing 2 or more functions.
 
-target triple = "x86_64-unknown-linux-gnu"
 target datalayout = "e-p:64:64"
 
-; CHECK: @[[JT:.*]] = private constant [2 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[FNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>, <{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[GNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 13) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; X64: @[[JT:.*]] = private constant [2 x <{ i8, i32, i8, i8, i8 }>] [<{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[FNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 5) to i32), i8 -52, i8 -52, i8 -52 }>, <{ i8, i32, i8, i8, i8 }> <{ i8 -23, i32 trunc (i64 sub (i64 sub (i64 ptrtoint (void ()* @[[GNAME:.*]] to i64), i64 ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)), i64 13) to i32), i8 -52, i8 -52, i8 -52 }>], section ".text"
+; WASM32: private constant [0 x i8] zeroinitializer
+ at 0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
 
-; CHECK: @f = alias void (), bitcast ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to void ()*)
-; CHECK: @g = alias void (), bitcast (<{ i8, i32, i8, i8, i8 }>* getelementptr inbounds ([2 x <{ i8, i32, i8, i8, i8 }>], [2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]], i64 0, i64 1) to void ()*)
+; X64: @f = alias void (), bitcast ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to void ()*)
+; X64: @g = alias void (), bitcast (<{ i8, i32, i8, i8, i8 }>* getelementptr inbounds ([2 x <{ i8, i32, i8, i8, i8 }>], [2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]], i64 0, i64 1) to void ()*)
 
-; CHECK: define private void @[[FNAME]]()
+; X64: define private void @[[FNAME]]()
+; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]]
 define void @f() !type !0 {
   ret void
 }
 
-; CHECK: define private void @[[GNAME]]()
+; X64: define private void @[[GNAME]]()
+; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I1:[0-9]+]]
 define void @g() !type !0 {
   ret void
 }
@@ -26,7 +29,12 @@ define void @g() !type !0 {
 declare i1 @llvm.type.test(i8* %ptr, metadata %bitset) nounwind readnone
 
 define i1 @foo(i8* %p) {
-  ; CHECK: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+  ; X64: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64)
+  ; WASM32: sub i64 {{.*}}, 0
+  ; WASM32: icmp ult i64 {{.*}}, 2
   %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1")
   ret i1 %x
 }
+
+; WASM32: ![[I0]] = !{i64 0}
+; WASM32: ![[I1]] = !{i64 1}




More information about the llvm-commits mailing list