diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp index 28703a2787e0d8..be1cfbaef3e431 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp @@ -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; +} diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h index 79588a9f566981..41e358c159b48e 100644 --- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h +++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h @@ -67,6 +67,9 @@ class WebAssemblyTTIImpl final : public BasicTTIImplBase { 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 index 00000000000000..f828f7afb5961e --- /dev/null +++ b/llvm/test/Transforms/Inline/WebAssembly/inline-target-features.ll @@ -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" }