[WebAssembly] Allow inlining functions with different features
authorThomas Lively <tlively@google.com>
Thu, 13 Aug 2020 20:57:43 +0000 (13:57 -0700)
committerThomas Lively <tlively@google.com>
Thu, 13 Aug 2020 20:57:43 +0000 (13:57 -0700)
Allow inlining only when the Callee has a subset of the Caller's
features. In principle, we should be able to inline regardless of any
features because WebAssembly supports features at module granularity,
not function granularity, but without this restriction it would be
possible for a module to "forget" about features if all the functions
that used them were inlined.

Requested in PR46812.

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

llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp
llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h
llvm/test/Transforms/Inline/WebAssembly/inline-target-features.ll [new file with mode: 0644]

index 28703a2..be1cfba 100644 (file)
@@ -84,3 +84,21 @@ unsigned WebAssemblyTTIImpl::getVectorInstrCost(unsigned Opcode, Type *Val,
 
   return Cost;
 }
+
+bool WebAssemblyTTIImpl::areInlineCompatible(const Function *Caller,
+                                             const Function *Callee) const {
+  // Allow inlining only when the Callee has a subset of the Caller's
+  // features. In principle, we should be able to inline regardless of any
+  // features because WebAssembly supports features at module granularity, not
+  // function granularity, but without this restriction it would be possible for
+  // a module to "forget" about features if all the functions that used them
+  // were inlined.
+  const TargetMachine &TM = getTLI()->getTargetMachine();
+
+  const FeatureBitset &CallerBits =
+      TM.getSubtargetImpl(*Caller)->getFeatureBits();
+  const FeatureBitset &CalleeBits =
+      TM.getSubtargetImpl(*Callee)->getFeatureBits();
+
+  return (CallerBits & CalleeBits) == CalleeBits;
+}
index 79588a9..41e358c 100644 (file)
@@ -67,6 +67,9 @@ public:
   unsigned getVectorInstrCost(unsigned Opcode, Type *Val, unsigned Index);
 
   /// @}
+
+  bool areInlineCompatible(const Function *Caller,
+                           const Function *Callee) const;
 };
 
 } // end namespace llvm
diff --git a/llvm/test/Transforms/Inline/WebAssembly/inline-target-features.ll b/llvm/test/Transforms/Inline/WebAssembly/inline-target-features.ll
new file mode 100644 (file)
index 0000000..f828f7a
--- /dev/null
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -mtriple=wasm32-unknown-unknown -S -inline | FileCheck %s
+
+; Check that having functions can be inlined into callers only when
+; they have a subset of the caller's features.
+
+target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
+target triple = "wasm32-unknown-unknown"
+
+declare void @foo()
+
+define internal void @uses_simd() #0 {
+; CHECK-LABEL: @uses_simd(
+; CHECK-NEXT:    tail call void @foo()
+; CHECK-NEXT:    ret void
+;
+  tail call void @foo()
+  ret void
+}
+
+define void @many_features() #1 {
+; CHECK-LABEL: @many_features(
+; CHECK-NEXT:    tail call void @foo()
+; CHECK-NEXT:    ret void
+;
+  tail call fastcc void @uses_simd()
+  ret void
+}
+
+define void @few_features() #2 {
+; CHECK-LABEL: @few_features(
+; CHECK-NEXT:    tail call fastcc void @uses_simd()
+; CHECK-NEXT:    ret void
+;
+  tail call fastcc void @uses_simd()
+  ret void
+}
+
+attributes #0 = { "target-cpu"="mvp" "target-features"="+simd128"}
+attributes #1 = { "target-cpu"="bleeding-edge" "target-features"="+simd128" }
+attributes #2 = { "target-cpu"="mvp" "target-features"="+multivalue" }