diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp index e74068e22f4cd..6bb99f54fe9e0 100644 --- a/llvm/lib/CodeGen/ValueTypes.cpp +++ b/llvm/lib/CodeGen/ValueTypes.cpp @@ -252,6 +252,29 @@ MVT MVT::getVT(Type *Ty, bool HandleUnknown){ default: if (HandleUnknown) return MVT(MVT::Other); llvm_unreachable("Unknown type!"); + case Type::PointerTyID: { + if (HandleUnknown) + return MVT(MVT::Other); + // A pointer normally cannot be lowered to a value type without a + // DataLayout, so it is an "unknown" type here. The exception is the + // WebAssembly reference types: EVT::getTypeForEVT maps MVT::externref / + // MVT::funcref to opaque pointers in address spaces 10 and 20, and that + // mapping has to be invertible so that DataLayout-free EVT helpers can + // recover the element type of an / vector + // during type legalization instead of crashing. + // + // Address spaces 10 and 20 are not reserved for WebAssembly, but a target + // only reaches this code with such a pointer if it first produced an + // externref/funcref MVT, which only WebAssembly does. + switch (cast(Ty)->getAddressSpace()) { + case 10: + return MVT(MVT::externref); + case 20: + return MVT(MVT::funcref); + default: + llvm_unreachable("Unknown type!"); + } + } case Type::VoidTyID: return MVT::isVoid; case Type::ByteTyID: diff --git a/llvm/test/Transforms/SLPVectorizer/WebAssembly/externref-no-vectorize.ll b/llvm/test/Transforms/SLPVectorizer/WebAssembly/externref-no-vectorize.ll new file mode 100644 index 0000000000000..27298fb6ce4e9 --- /dev/null +++ b/llvm/test/Transforms/SLPVectorizer/WebAssembly/externref-no-vectorize.ll @@ -0,0 +1,48 @@ +; RUN: opt < %s -passes=slp-vectorizer -mtriple=wasm32-unknown-unknown -S | FileCheck %s + +; A WebAssembly reference type cannot be vectorized. +; This used to crash type legalization while the SLP vectorizer was computing +; the cost for a value. + +target datalayout = "e-m:e-p:32:32-p10:8:8-p20:8:8-i64:64-i128:128-n32:64-S128-ni:1:10:20" +target triple = "wasm32-unknown-unknown" + +%externref = type ptr addrspace(10) + +declare %externref @foo() +declare void @bar(%externref) + +; Two externref phis that feed two calls are candidates for being gathered into +; a vector but they must be left scalar. Derived the following C code: +; +; __externref_t foo(void); +; void bar(__externref_t); +; void test(int flag, __externref_t ref1, __externref_t ref2) { +; if (flag) { +; ref1 = foo(); +; ref2 = foo(); +; } +; bar(ref1); bar(ref2); +; } +; +; CHECK-LABEL: @test( +; CHECK-NOT: phi <{{.*}} x ptr addrspace(10)> +; CHECK-NOT: call void @bar(<{{.*}} x ptr addrspace(10)> +; CHECK: ret void +define void @test(i32 %flag, %externref %ref1, %externref %ref2) { +entry: + %c = icmp eq i32 %flag, 0 + br i1 %c, label %join, label %then + +then: + %a = tail call %externref @foo() + %b = tail call %externref @foo() + br label %join + +join: + %p1 = phi %externref [ %a, %then ], [ %ref1, %entry ] + %p2 = phi %externref [ %b, %then ], [ %ref2, %entry ] + tail call void @bar(%externref %p1) + tail call void @bar(%externref %p2) + ret void +}