Index: lib/Transforms/IPO/LowerTypeTests.cpp =================================================================== --- lib/Transforms/IPO/LowerTypeTests.cpp +++ lib/Transforms/IPO/LowerTypeTests.cpp @@ -827,30 +827,36 @@ ConstantArray::get(JumpTableType, JumpTableEntries)); } -// Assign a dummy layout based using an incrementing counter, and store this as -// metadata. During generation of the indexed indirect function call table, the -// backend will ensure that the appropriate indexes are used. +// Assign each disjoint set to a different indirect function call table using +// an incrementing counter. Then, eliminate explicit type tests. This is safe +// because the type homogeneity of each disjoint set is checked at load-time. +// Additionally, calls to out of bounds table entries will trap at runtime. void LowerTypeTests::buildBitSetsFromFunctionsWASM( ArrayRef TypeIds, ArrayRef Functions) { assert(!Functions.empty()); - // Build a dummy layout. - DenseMap GlobalLayout; - for (Function *F : Functions) - GlobalLayout[F] = IndirectIndex++; + // Manually lower type tests by eliminating explicit type tests. + for (Metadata *TypeId : TypeIds) { + // Replace each type test with true, and let simplifycfg remove the branch. + for (CallInst *TypeTest : TypeTestCallSites[TypeId]) { + ConstantInt *True = ConstantInt::getTrue(TypeTest->getContext()); + TypeTest->replaceAllUsesWith(True); + TypeTest->eraseFromParent(); - // Pass a NULL pointer as the subtracted "jump table" offset. - lowerTypeTestCalls(TypeIds, - ConstantPointerNull::get(cast(Int32PtrTy)), - GlobalLayout); + ++NumTypeTestCallsLowered; + } + } // Generate metadata for the indirect function indexes. - for (const auto &P : GlobalLayout) { - MDNode *MD = MDNode::get(P.first->getContext(), + for (const auto F : Functions) { + MDNode *MD = MDNode::get(F->getContext(), ArrayRef(ConstantAsMetadata::get( - ConstantInt::get(Int64Ty, P.second)))); - cast(P.first)->setMetadata("wasm.index", MD); + ConstantInt::get(Int64Ty, IndirectIndex)))); + F->setMetadata("wasm.index", MD); } + + // Increment the counter to put each disjoint set in a different table. + IndirectIndex += 1; } void LowerTypeTests::buildBitSetsFromDisjointSet( Index: test/Transforms/LowerTypeTests/function-disjoint.ll =================================================================== --- test/Transforms/LowerTypeTests/function-disjoint.ll +++ test/Transforms/LowerTypeTests/function-disjoint.ll @@ -31,12 +31,14 @@ 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 + ; WASM32-NOT: icmp ult 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 + ; WASM32-NOT: icmp ult i64 {{.*}}, 1 %y = call i1 @llvm.type.test(i8* %p, metadata !"typeid2") %z = add i1 %x, %y + ; WASM32-NOT: br i1 {{.*}} label %cont, label %trap + ; WASM32: add i1 true, true ret i1 %z } Index: test/Transforms/LowerTypeTests/function-ext.ll =================================================================== --- test/Transforms/LowerTypeTests/function-ext.ll +++ test/Transforms/LowerTypeTests/function-ext.ll @@ -12,7 +12,8 @@ define i1 @bar(i8* %ptr) { ; X64: icmp eq i64 {{.*}}, ptrtoint ([1 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64) - ; WASM32: icmp eq i64 {{.*}}, 0 + ; WASM32-NOT: icmp eq i64 {{.*}}, 0 + ; WASM32: ret i1 true %p = call i1 @llvm.type.test(i8* %ptr, metadata !"void") ret i1 %p } Index: test/Transforms/LowerTypeTests/function.ll =================================================================== --- test/Transforms/LowerTypeTests/function.ll +++ test/Transforms/LowerTypeTests/function.ll @@ -12,13 +12,13 @@ ; 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 ()*) ; X64: define private void @[[FNAME]]() -; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I0:[0-9]+]] +; WASM32: define void @f() !type !{{[0-9]+}} !wasm.index ![[I:[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]+]] +; WASM32: define void @g() !type !{{[0-9]+}} !wasm.index ![[I]] define void @g() !type !0 { ret void } @@ -29,11 +29,12 @@ define i1 @foo(i8* %p) { ; X64: sub i64 {{.*}}, ptrtoint ([2 x <{ i8, i32, i8, i8, i8 }>]* @[[JT]] to i64) - ; WASM32: sub i64 {{.*}}, 0 - ; WASM32: icmp ult i64 {{.*}}, 2 + ; WASM32-NOT: sub i64 {{.*}}, 0 + ; WASM32-NOT: icmp ult i64 {{.*}}, 2 + ; WASM32-NOT: br i1 {{.*}} label %cont, label %trap + ; WASM32: ret i1 true %x = call i1 @llvm.type.test(i8* %p, metadata !"typeid1") ret i1 %x } -; WASM32: ![[I0]] = !{i64 0} -; WASM32: ![[I1]] = !{i64 1} +; WASM32: ![[I]] = !{i64 0}