Skip to content

[WebAssembly] Refactor Wasm Reference Types as TargetExtType - #71540

Closed
pmatos wants to merge 4 commits into
llvm:mainfrom
pmatos:RefTypesAsTargetExtTypes
Closed

[WebAssembly] Refactor Wasm Reference Types as TargetExtType#71540
pmatos wants to merge 4 commits into
llvm:mainfrom
pmatos:RefTypesAsTargetExtTypes

Conversation

@pmatos

@pmatos pmatos commented Nov 7, 2023

Copy link
Copy Markdown
Contributor

Originally reference types were designed as pointers to different address spaces.

More recently TargetExtType were added to LLVM IR making it easier to represent reference types. This refactoring gets rid of wasm reftypes as pointers and just uses target extension types to represent them.

TODO:

  • externref
  • funcref
  • documentation

@llvmbot

llvmbot commented Nov 7, 2023

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-backend-webassembly

Author: Paulo Matos (pmatos)

Changes

Originally reference types were designed as pointers to different address spaces.

More recently TargetExtType were added to LLVM IR making it easier to represent reference types. This refactoring gets rid of wasm reftypes as pointers and just uses target extension types to represent them.


Patch is 28.06 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/71540.diff

30 Files Affected:

  • (modified) clang/test/CodeGen/WebAssembly/builtins-table.c (+8-8)
  • (modified) clang/test/CodeGen/WebAssembly/wasm-externref.c (+4-4)
  • (modified) clang/test/CodeGen/builtins-wasm.c (+1-1)
  • (modified) llvm/include/llvm/IR/Intrinsics.h (+1)
  • (modified) llvm/include/llvm/IR/Type.h (+8-2)
  • (modified) llvm/lib/CodeGen/ValueTypes.cpp (+2)
  • (modified) llvm/lib/IR/Function.cpp (+6-2)
  • (modified) llvm/lib/IR/Type.cpp (+5-2)
  • (modified) llvm/lib/Target/WebAssembly/CMakeLists.txt (-1)
  • (modified) llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h (-2)
  • (modified) llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h (+2-3)
  • (modified) llvm/lib/Target/WebAssembly/WebAssembly.h (-2)
  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp (-4)
  • (removed) llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp (-86)
  • (modified) llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (-2)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-globalget.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-globalset.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll (+3-9)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-ptrtoint.ll (+3-8)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-tableget.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-tableset.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-load.ll (+2-2)
  • (modified) llvm/test/CodeGen/WebAssembly/externref-unsized-store.ll (+2-2)
  • (modified) llvm/test/CodeGen/WebAssembly/ref-null.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/table-copy.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/table-fill.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/table-grow.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/table-size.ll (+1-1)
  • (modified) llvm/test/CodeGen/WebAssembly/table-types.ll (+1-1)
  • (modified) llvm/utils/gn/secondary/llvm/lib/Target/WebAssembly/BUILD.gn (-1)
diff --git a/clang/test/CodeGen/WebAssembly/builtins-table.c b/clang/test/CodeGen/WebAssembly/builtins-table.c
index 74bb2442fe552fc..eeed335855e4089 100644
--- a/clang/test/CodeGen/WebAssembly/builtins-table.c
+++ b/clang/test/CodeGen/WebAssembly/builtins-table.c
@@ -7,17 +7,17 @@ static __externref_t table[0];
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_get
 // CHECK-SAME: (i32 noundef [[INDEX:%.*]]) #[[ATTR0:[0-9]+]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call ptr addrspace(10) @llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
-// CHECK-NEXT:    ret ptr addrspace(10) [[TMP0]]
+// CHECK-NEXT:    [[TMP0:%.*]] = call target("wasm.externref") @llvm.wasm.table.get.externref(ptr addrspace(1) @table, i32 [[INDEX]])
+// CHECK-NEXT:    ret target("wasm.externref") [[TMP0]]
 //
 __externref_t test_builtin_wasm_table_get(int index) {
   return __builtin_wasm_table_get(table, index);
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_set
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.externref") [[REF:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]])
+// CHECK-NEXT:    call void @llvm.wasm.table.set.externref(ptr addrspace(1) @table, i32 [[INDEX]], target("wasm.externref") [[REF]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_set(int index, __externref_t ref) {
@@ -35,9 +35,9 @@ int test_builtin_wasm_table_size() {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_grow
-// CHECK-SAME: (ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (target("wasm.externref") [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr addrspace(1) @table, ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    [[TMP0:%.*]] = call i32 @llvm.wasm.table.grow.externref(ptr addrspace(1) @table, target("wasm.externref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret i32 [[TMP0]]
 //
 int test_builtin_wasm_table_grow(__externref_t ref, int nelem) {
@@ -45,9 +45,9 @@ int test_builtin_wasm_table_grow(__externref_t ref, int nelem) {
 }
 
 // CHECK-LABEL: define {{[^@]+}}@test_builtin_wasm_table_fill
-// CHECK-SAME: (i32 noundef [[INDEX:%.*]], ptr addrspace(10) [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
+// CHECK-SAME: (i32 noundef [[INDEX:%.*]], target("wasm.externref") [[REF:%.*]], i32 noundef [[NELEM:%.*]]) #[[ATTR0]] {
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    call void @llvm.wasm.table.fill.externref(ptr addrspace(1) @table, i32 [[INDEX]], ptr addrspace(10) [[REF]], i32 [[NELEM]])
+// CHECK-NEXT:    call void @llvm.wasm.table.fill.externref(ptr addrspace(1) @table, i32 [[INDEX]], target("wasm.externref") [[REF]], i32 [[NELEM]])
 // CHECK-NEXT:    ret void
 //
 void test_builtin_wasm_table_fill(int index, __externref_t ref, int nelem) {
diff --git a/clang/test/CodeGen/WebAssembly/wasm-externref.c b/clang/test/CodeGen/WebAssembly/wasm-externref.c
index 788438bb4a86a33..d226c51b7fd4efb 100644
--- a/clang/test/CodeGen/WebAssembly/wasm-externref.c
+++ b/clang/test/CodeGen/WebAssembly/wasm-externref.c
@@ -7,10 +7,10 @@ void helper(externref_t);
 
 // CHECK-LABEL: @handle(
 // CHECK-NEXT:  entry:
-// CHECK-NEXT:    [[OBJ_ADDR:%.*]] = alloca ptr addrspace(10), align 1
-// CHECK-NEXT:    store ptr addrspace(10) [[OBJ:%.*]], ptr [[OBJ_ADDR]], align 1
-// CHECK-NEXT:    [[TMP0:%.*]] = load ptr addrspace(10), ptr [[OBJ_ADDR]], align 1
-// CHECK-NEXT:    call void @helper(ptr addrspace(10) [[TMP0]])
+// CHECK-NEXT:    [[OBJ_ADDR:%.*]] = alloca target("wasm.externref"), align 1
+// CHECK-NEXT:    store target("wasm.externref") [[OBJ:%.*]], ptr [[OBJ_ADDR]], align 1
+// CHECK-NEXT:    [[TMP0:%.*]] = load target("wasm.externref"), ptr [[OBJ_ADDR]], align 1
+// CHECK-NEXT:    call void @helper(target("wasm.externref") [[TMP0]])
 // CHECK-NEXT:    ret void
 //
 void handle(externref_t obj) {
diff --git a/clang/test/CodeGen/builtins-wasm.c b/clang/test/CodeGen/builtins-wasm.c
index d486d12085f9fce..135334c0cd0a193 100644
--- a/clang/test/CodeGen/builtins-wasm.c
+++ b/clang/test/CodeGen/builtins-wasm.c
@@ -804,6 +804,6 @@ f32x4 relaxed_dot_bf16x8_add_f32_f32x4(u16x8 a, u16x8 b, f32x4 c) {
 
 __externref_t externref_null() {
   return __builtin_wasm_ref_null_extern();
-  // WEBASSEMBLY: tail call ptr addrspace(10) @llvm.wasm.ref.null.extern()
+  // WEBASSEMBLY: tail call target("wasm.externref") @llvm.wasm.ref.null.extern()
   // WEBASSEMBLY-NEXT: ret
 }
diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 0dfe9f029f9b1a7..0121717423a407a 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -136,6 +136,7 @@ namespace Intrinsic {
       AMX,
       PPCQuad,
       AArch64Svcount,
+      WasmExternref,
     } Kind;
 
     union {
diff --git a/llvm/include/llvm/IR/Type.h b/llvm/include/llvm/IR/Type.h
index c38078cc6087ef7..4156f00e6d19c71 100644
--- a/llvm/include/llvm/IR/Type.h
+++ b/llvm/include/llvm/IR/Type.h
@@ -303,13 +303,19 @@ class Type {
     // If it's a primitive, it is always sized.
     if (getTypeID() == IntegerTyID || isFloatingPointTy() ||
         getTypeID() == PointerTyID || getTypeID() == X86_MMXTyID ||
-        getTypeID() == X86_AMXTyID)
+        getTypeID() == X86_AMXTyID || getTypeID() == TargetExtTyID)
       return true;
+      
     // If it is not something that can have a size (e.g. a function or label),
     // it doesn't have a size.
     if (getTypeID() != StructTyID && getTypeID() != ArrayTyID &&
-        !isVectorTy() && getTypeID() != TargetExtTyID)
+        !isVectorTy())
       return false;
+
+    // A target extension type will be sized depending on its alignment type.
+    //if (getTypeID() == TargetExtTyID)
+    //  return static_cast<TargetExtType>(this)->getLayoutType()->isSized();
+
     // Otherwise we have to try harder to decide.
     return isSizedDerivedType(Visited);
   }
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index 2d16ff2dfb2fbf5..e9d6a14228b0934 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -590,6 +590,8 @@ MVT MVT::getVT(Type *Ty, bool HandleUnknown){
     TargetExtType *TargetExtTy = cast<TargetExtType>(Ty);
     if (TargetExtTy->getName() == "aarch64.svcount")
       return MVT(MVT::aarch64svcount);
+    else if(TargetExtTy->getName() == "wasm.externref")
+      return MVT(MVT::externref);
     else if (TargetExtTy->getName().starts_with("spirv."))
       return MVT(MVT::spirvbuiltin);
     if (HandleUnknown)
diff --git a/llvm/lib/IR/Function.cpp b/llvm/lib/IR/Function.cpp
index 658aa67a38c937f..acb3468bd189a3a 100644
--- a/llvm/lib/IR/Function.cpp
+++ b/llvm/lib/IR/Function.cpp
@@ -1162,7 +1162,7 @@ static void DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
     DecodeIITType(NextElt, Infos, Info, OutputTable);
     return;
   case IIT_EXTERNREF:
-    OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 10));
+    OutputTable.push_back(IITDescriptor::get(IITDescriptor::WasmExternref, 0));
     return;
   case IIT_FUNCREF:
     OutputTable.push_back(IITDescriptor::get(IITDescriptor::Pointer, 20));
@@ -1318,7 +1318,8 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::PPCQuad: return Type::getPPC_FP128Ty(Context);
   case IITDescriptor::AArch64Svcount:
     return TargetExtType::get(Context, "aarch64.svcount");
-
+  case IITDescriptor::WasmExternref:
+    return TargetExtType::get(Context, "wasm.externref");
   case IITDescriptor::Integer:
     return IntegerType::get(Context, D.Integer_Width);
   case IITDescriptor::Vector:
@@ -1479,6 +1480,9 @@ static bool matchIntrinsicType(
     case IITDescriptor::AArch64Svcount:
       return !isa<TargetExtType>(Ty) ||
              cast<TargetExtType>(Ty)->getName() != "aarch64.svcount";
+    case IITDescriptor::WasmExternref:
+      return !isa<TargetExtType>(Ty) ||
+             cast<TargetExtType>(Ty)->getName() != "wasm.externref";
     case IITDescriptor::Vector: {
       VectorType *VT = dyn_cast<VectorType>(Ty);
       return !VT || VT->getElementCount() != D.Vector_Width ||
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 006278d16484c1c..1b3a7c980e33c42 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -261,8 +261,7 @@ PointerType *Type::getInt8PtrTy(LLVMContext &C, unsigned AS) {
 }
 
 Type *Type::getWasm_ExternrefTy(LLVMContext &C) {
-  // opaque pointer in addrspace(10)
-  static PointerType *Ty = PointerType::get(C, 10);
+  static TargetExtType *Ty = TargetExtType::get(C, "wasm.externref", {}, {});
   return Ty;
 }
 
@@ -844,6 +843,10 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
     return TargetTypeInfo(ScalableVectorType::get(Type::getInt1Ty(C), 16),
                           TargetExtType::HasZeroInit);
 
+  // Opaque types in the WebAssembly name space.
+  if (Name == "wasm.externref")
+    return TargetTypeInfo(PointerType::getUnqual(C), TargetExtType::HasZeroInit, TargetExtType::CanBeGlobal);
+
   return TargetTypeInfo(Type::getVoidTy(C));
 }
 
diff --git a/llvm/lib/Target/WebAssembly/CMakeLists.txt b/llvm/lib/Target/WebAssembly/CMakeLists.txt
index bb2ccea5c145985..9cd1af14832724c 100644
--- a/llvm/lib/Target/WebAssembly/CMakeLists.txt
+++ b/llvm/lib/Target/WebAssembly/CMakeLists.txt
@@ -35,7 +35,6 @@ add_llvm_target(WebAssemblyCodeGen
   WebAssemblyInstrInfo.cpp
   WebAssemblyLowerBrUnless.cpp
   WebAssemblyLowerEmscriptenEHSjLj.cpp
-  WebAssemblyLowerRefTypesIntPtrConv.cpp
   WebAssemblyMachineFunctionInfo.cpp
   WebAssemblyMCInstLower.cpp
   WebAssemblyMCLowerPrePass.cpp
diff --git a/llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h b/llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h
index 2239badca69c35a..9603b338e90b24e 100644
--- a/llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h
+++ b/llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h
@@ -25,8 +25,6 @@ enum WasmAddressSpace : unsigned {
   // to these pointers are lowered to global.get / global.set or local.get /
   // local.set, as appropriate.
   WASM_ADDRESS_SPACE_VAR = 1,
-  // A non-integral address space for externref values
-  WASM_ADDRESS_SPACE_EXTERNREF = 10,
   // A non-integral address space for funcref values
   WASM_ADDRESS_SPACE_FUNCREF = 20,
 };
diff --git a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
index a8860477a2472cf..670cf46ba30b0b2 100644
--- a/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
+++ b/llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h
@@ -28,9 +28,8 @@ namespace WebAssembly {
 
 /// Return true if this is a WebAssembly Externref Type.
 inline bool isWebAssemblyExternrefType(const Type *Ty) {
-  return Ty->isPointerTy() &&
-         Ty->getPointerAddressSpace() ==
-             WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF;
+  const TargetExtType *TargetTy = dyn_cast<TargetExtType>(Ty);
+  return TargetTy && TargetTy->getName() == "wasm.externref";
 }
 
 /// Return true if this is a WebAssembly Funcref Type.
diff --git a/llvm/lib/Target/WebAssembly/WebAssembly.h b/llvm/lib/Target/WebAssembly/WebAssembly.h
index 91765ad117bdb01..4a1fec52ce7a699 100644
--- a/llvm/lib/Target/WebAssembly/WebAssembly.h
+++ b/llvm/lib/Target/WebAssembly/WebAssembly.h
@@ -29,7 +29,6 @@ ModulePass *createWebAssemblyLowerEmscriptenEHSjLj();
 ModulePass *createWebAssemblyAddMissingPrototypes();
 ModulePass *createWebAssemblyFixFunctionBitcasts();
 FunctionPass *createWebAssemblyOptimizeReturned();
-FunctionPass *createWebAssemblyLowerRefTypesIntPtrConv();
 
 // ISel and immediate followup passes.
 FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
@@ -72,7 +71,6 @@ void initializeWebAssemblyFixIrreducibleControlFlowPass(PassRegistry &);
 void initializeWebAssemblyLateEHPreparePass(PassRegistry &);
 void initializeWebAssemblyLowerBrUnlessPass(PassRegistry &);
 void initializeWebAssemblyLowerEmscriptenEHSjLjPass(PassRegistry &);
-void initializeWebAssemblyLowerRefTypesIntPtrConvPass(PassRegistry &);
 void initializeWebAssemblyMCLowerPrePassPass(PassRegistry &);
 void initializeWebAssemblyMemIntrinsicResultsPass(PassRegistry &);
 void initializeWebAssemblyNullifyDebugValueListsPass(PassRegistry &);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 4bcf89690505edd..ab40061807e5557 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -364,8 +364,6 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering(
 
 MVT WebAssemblyTargetLowering::getPointerTy(const DataLayout &DL,
                                             uint32_t AS) const {
-  if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF)
-    return MVT::externref;
   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF)
     return MVT::funcref;
   return TargetLowering::getPointerTy(DL, AS);
@@ -373,8 +371,6 @@ MVT WebAssemblyTargetLowering::getPointerTy(const DataLayout &DL,
 
 MVT WebAssemblyTargetLowering::getPointerMemTy(const DataLayout &DL,
                                                uint32_t AS) const {
-  if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_EXTERNREF)
-    return MVT::externref;
   if (AS == WebAssembly::WasmAddressSpace::WASM_ADDRESS_SPACE_FUNCREF)
     return MVT::funcref;
   return TargetLowering::getPointerMemTy(DL, AS);
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
deleted file mode 100644
index e0a219211228581..000000000000000
--- a/llvm/lib/Target/WebAssembly/WebAssemblyLowerRefTypesIntPtrConv.cpp
+++ /dev/null
@@ -1,86 +0,0 @@
-//=== WebAssemblyLowerRefTypesIntPtrConv.cpp -
-//                     Lower IntToPtr and PtrToInt on Reference Types   ---===//
-//
-// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
-// See https://llvm.org/LICENSE.txt for license information.
-// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-//
-//===----------------------------------------------------------------------===//
-///
-/// \file
-/// Lowers IntToPtr and PtrToInt instructions on reference types to
-/// Trap instructions since they have been allowed to operate
-/// on non-integral pointers.
-///
-//===----------------------------------------------------------------------===//
-
-#include "Utils/WebAssemblyTypeUtilities.h"
-#include "WebAssembly.h"
-#include "WebAssemblySubtarget.h"
-#include "llvm/IR/InstIterator.h"
-#include "llvm/Pass.h"
-#include <set>
-
-using namespace llvm;
-
-#define DEBUG_TYPE "wasm-lower-reftypes-intptr-conv"
-
-namespace {
-class WebAssemblyLowerRefTypesIntPtrConv final : public FunctionPass {
-  StringRef getPassName() const override {
-    return "WebAssembly Lower RefTypes Int-Ptr Conversions";
-  }
-
-  bool runOnFunction(Function &MF) override;
-
-public:
-  static char ID; // Pass identification
-  WebAssemblyLowerRefTypesIntPtrConv() : FunctionPass(ID) {}
-};
-} // end anonymous namespace
-
-char WebAssemblyLowerRefTypesIntPtrConv::ID = 0;
-INITIALIZE_PASS(WebAssemblyLowerRefTypesIntPtrConv, DEBUG_TYPE,
-                "WebAssembly Lower RefTypes Int-Ptr Conversions", false, false)
-
-FunctionPass *llvm::createWebAssemblyLowerRefTypesIntPtrConv() {
-  return new WebAssemblyLowerRefTypesIntPtrConv();
-}
-
-bool WebAssemblyLowerRefTypesIntPtrConv::runOnFunction(Function &F) {
-  LLVM_DEBUG(dbgs() << "********** Lower RefTypes IntPtr Convs **********\n"
-                       "********** Function: "
-                    << F.getName() << '\n');
-
-  // This function will check for uses of ptrtoint and inttoptr on reference
-  // types and replace them with a trap instruction.
-  //
-  // We replace the instruction by a trap instruction
-  // and its uses by null in the case of inttoptr and 0 in the
-  // case of ptrtoint.
-  std::set<Instruction *> worklist;
-
-  for (inst_iterator I = inst_begin(F), E = inst_end(F); I != E; ++I) {
-    PtrToIntInst *PTI = dyn_cast<PtrToIntInst>(&*I);
-    IntToPtrInst *ITP = dyn_cast<IntToPtrInst>(&*I);
-    if (!(PTI && WebAssembly::isWebAssemblyReferenceType(
-                     PTI->getPointerOperand()->getType())) &&
-        !(ITP && WebAssembly::isWebAssemblyReferenceType(ITP->getDestTy())))
-      continue;
-
-    UndefValue *U = UndefValue::get(I->getType());
-    I->replaceAllUsesWith(U);
-
-    Function *TrapIntrin =
-        Intrinsic::getDeclaration(F.getParent(), Intrinsic::debugtrap);
-    CallInst::Create(TrapIntrin, {}, "", &*I);
-
-    worklist.insert(&*I);
-  }
-
-  // erase each instruction replaced by trap
-  for (Instruction *I : worklist)
-    I->eraseFromParent();
-
-  return !worklist.empty();
-}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 2db1b6493cc4768..df71b9828142a2f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -87,7 +87,6 @@ extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeWebAssemblyTarget() {
   initializeWebAssemblyDebugFixupPass(PR);
   initializeWebAssemblyPeepholePass(PR);
   initializeWebAssemblyMCLowerPrePassPass(PR);
-  initializeWebAssemblyLowerRefTypesIntPtrConvPass(PR);
   initializeWebAssemblyFixBrTableDefaultsPass(PR);
   initializeWebAssemblyDAGToDAGISelPass(PR);
 }
@@ -609,7 +608,6 @@ void WebAssemblyPassConfig::addPreEmitPass() {
 
 bool WebAssemblyPassConfig::addPreISel() {
   TargetPassConfig::addPreISel();
-  addPass(createWebAssemblyLowerRefTypesIntPtrConv());
   return false;
 }
 
diff --git a/llvm/test/CodeGen/WebAssembly/externref-globalget.ll b/llvm/test/CodeGen/WebAssembly/externref-globalget.ll
index cdf98c42439f2d2..9ee98150a66f3fb 100644
--- a/llvm/test/CodeGen/WebAssembly/externref-globalget.ll
+++ b/llvm/test/CodeGen/WebAssembly/externref-globalget.ll
@@ -1,6 +1,6 @@
 ; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types | FileCheck %s
 
-%externref = type ptr addrspace(10) ;; addrspace 10 is nonintegral
+%externref = type target("wasm.externref") ;; addrspace 10 is nonintegral
 
 @externref_global = local_unnamed_addr addrspace(1) global %externref undef
 
diff --git a/llvm/test/CodeGen/WebAssembly/externref-globalset.ll b/llvm/test/CodeGen/WebAssembly/externref-globalset.ll
index 5bfd673e89fa126..c5f9fe1fff8bf82 100644
--- a/llvm/test/CodeGen/WebAssembly/externref-globalset.ll
+++ b/llvm/test/CodeGen/WebAssembly/externref-globalset.ll
@@ -1,6 +1,6 @@
 ; RUN: llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s | FileCheck %s
 
-%externref = type ptr addrspace(10) ;; addrspace 10 is nonintegral
+%externref = type target("wasm.externref") ;; addrspace 10 is nonintegral
 
 @externref_global = local_unnamed_addr addrspace(1) global %externref undef
 
diff --git a/llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll b/llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll
index 64f955b6ed0f0a0..bdf04f73c54a78e 100644
--- a/llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll
+++ b/llvm/test/CodeGen/WebAssembly/externref-inttoptr.ll
@@ -1,16 +1,10 @@
-; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types 2>&1 | FileCheck %s
+; RUN: not llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
 
-%externref = type ptr addrspace(10)
+%externref = type target("wasm.externref")
 
 define %externref @int_to_externref(i32 %i) {
   %ref = inttoptr i32 %i to %externref
   ret %externref %ref
 }
 
-
-; CHECK-LABEL: int_to_externref:
-; CHECK-NEXT: .functype       int_to_externref (i32) -> (externref)
-; CHECK-NEXT: .local externref
-; CHECK-NEXT: unreachable
-; CHECK-NEXT: local.get 1
-; CHECK-NEXT: end_function
+# CHECK-ERROR: error: invalid cast opcode for cast from 'i32' to 'target("wa...
[truncated]

@pmatos

pmatos commented Nov 7, 2023

Copy link
Copy Markdown
Contributor Author

The current patch implements successfully all the refactoring needed for externref. I will work on funcref next.

This refactoring was triggered by the discussion at #71069 .
Also the issue #71388 is currently blocking this. I include a workaround in the current patch.

@github-actions

github-actions Bot commented Nov 7, 2023

Copy link
Copy Markdown

⚠️ C/C++ code formatter, clang-format found issues in your code. ⚠️

You can test this locally with the following command:
git-clang-format --diff 915f6c3d6a4377e2672a95c656374d71df62e95a c642159c3db5a5ac56ea2d8d7a177bc274597429 -- clang/test/CodeGen/WebAssembly/builtins-table.c clang/test/CodeGen/WebAssembly/wasm-externref.c clang/test/CodeGen/builtins-wasm.c llvm/include/llvm/IR/Intrinsics.h llvm/lib/CodeGen/ValueTypes.cpp llvm/lib/IR/Function.cpp llvm/lib/IR/Type.cpp llvm/lib/Target/WebAssembly/Utils/WasmAddressSpaces.h llvm/lib/Target/WebAssembly/Utils/WebAssemblyTypeUtilities.h llvm/lib/Target/WebAssembly/WebAssembly.h llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
View the diff from clang-format here.
diff --git a/llvm/lib/CodeGen/ValueTypes.cpp b/llvm/lib/CodeGen/ValueTypes.cpp
index fc77eb65d4..76eaaf9321 100644
--- a/llvm/lib/CodeGen/ValueTypes.cpp
+++ b/llvm/lib/CodeGen/ValueTypes.cpp
@@ -590,9 +590,9 @@ MVT MVT::getVT(Type *Ty, bool HandleUnknown){
     TargetExtType *TargetExtTy = cast<TargetExtType>(Ty);
     if (TargetExtTy->getName() == "aarch64.svcount")
       return MVT(MVT::aarch64svcount);
-    else if(TargetExtTy->getName() == "wasm.externref")
+    else if (TargetExtTy->getName() == "wasm.externref")
       return MVT(MVT::externref);
-    else if(TargetExtTy->getName() == "wasm.funcref")
+    else if (TargetExtTy->getName() == "wasm.funcref")
       return MVT(MVT::funcref);
     else if (TargetExtTy->getName().starts_with("spirv."))
       return MVT(MVT::spirvbuiltin);
diff --git a/llvm/lib/IR/Type.cpp b/llvm/lib/IR/Type.cpp
index 127dc5b914..3ddd15886f 100644
--- a/llvm/lib/IR/Type.cpp
+++ b/llvm/lib/IR/Type.cpp
@@ -840,7 +840,8 @@ static TargetTypeInfo getTargetTypeInfo(const TargetExtType *Ty) {
 
   // Opaque types in the WebAssembly name space.
   if (Name.startswith("wasm."))
-    return TargetTypeInfo(PointerType::getUnqual(C), TargetExtType::HasZeroInit, TargetExtType::CanBeGlobal);
+    return TargetTypeInfo(PointerType::getUnqual(C), TargetExtType::HasZeroInit,
+                          TargetExtType::CanBeGlobal);
 
   return TargetTypeInfo(Type::getVoidTy(C));
 }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
index 35d7d431bd..2393368a62 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp
@@ -1238,8 +1238,7 @@ WebAssemblyTargetLowering::LowerCall(CallLoweringInfo &CLI,
     SDValue TableSetOps[] = {Chain, Sym, TableSlot, Callee};
     SDValue TableSet = DAG.getMemIntrinsicNode(
         WebAssemblyISD::TABLE_SET, DL, DAG.getVTList(MVT::Other), TableSetOps,
-        MVT::funcref,
-        MachinePointerInfo(),
+        MVT::funcref, MachinePointerInfo(),
         CLI.CB->getCalledOperand()->getPointerAlignment(DAG.getDataLayout()),
         MachineMemOperand::MOStore);
 

@pmatos
pmatos requested a review from tlively November 7, 2023 19:51

@tlively tlively left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Very cool! LGTM so far. It's really nice that we can delete that entire pass out of the backend. Where can I read more about these new target extension types?

@pmatos

pmatos commented Nov 8, 2023

Copy link
Copy Markdown
Contributor Author

Very cool! LGTM so far. It's really nice that we can delete that entire pass out of the backend. Where can I read more about these new target extension types?

Thanks, working next on funcref.
About docs, there's not a lot but there's something here:
https://llvm.org/docs/LangRef.html#target-extension-type

and of course, the api:
https://llvm.org/doxygen/classllvm_1_1TargetExtType.html

Originally reference types were designed as pointers to different
address spaces.

More recently TargetExtType were added to LLVM IR making it easier
to represent reference types. This refactoring gets rid of wasm
reftypes as pointers and just uses target extension types to
represent them.
@pmatos
pmatos force-pushed the RefTypesAsTargetExtTypes branch from 18fc2c1 to c642159 Compare November 17, 2023 10:23
lnihlen added a commit to lnihlen/llvm-project that referenced this pull request May 26, 2024
lnihlen added a commit to lnihlen/llvm-project that referenced this pull request Jun 15, 2024
hoodmane added a commit to hoodmane/llvm-project that referenced this pull request Jun 11, 2026
Originally llvm#71540 by Paolo Matos, I picked it up and finished it.

Model WebAssembly externref and funcref as target("wasm.externref") /
target("wasm.funcref") TargetExtTypes instead of pointers in non-integral
address spaces 10 and 20.

The entire WebAssemblyLowerRefTypesIntPtrConv can be removed.

This breaks the GlobalISel handling for reference types, I just disabled
GlobalISel handling for functions that use them.

I added intrinsics for `wasm.ptr.to_funcref` and `wasm.funcref.to_ptr`.
ptr.to_funcref does a table.get from the indirect function pointer table. As a
special case, 0 is converted to the null funcref rather than doing table.get on
0. `wasm.funcref.to_ptr` is only handled when we call it immediately, otherwise
it will fail to lower. We could dynamically put the funcref into the table to
make it work but that would require a stack of spilled funcrefs and isn't worth
the effort.

In the process of looking into this, I noticed that clang used to allow casting
from funcref to function pointer but if the cast result escaped it would hit
`Cannot select: FUNCREF_TO_PTR` in the backend. I added a diagnostic that says
"a funcref can only be converted to a pointer to be directly called" to make
this a little cleaner.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
Co-authored-by: Paulo Matos <pmatos@igalia.com>
hoodmane added a commit to hoodmane/llvm-project that referenced this pull request Jun 11, 2026
Originally llvm#71540 by Paolo Matos, I picked it up and finished it.

Model WebAssembly externref and funcref as target("wasm.externref") /
target("wasm.funcref") TargetExtTypes instead of pointers in non-integral
address spaces 10 and 20.

The entire WebAssemblyLowerRefTypesIntPtrConv can be removed.

This breaks the GlobalISel handling for reference types, I just disabled
GlobalISel handling for functions that use them.

I added intrinsics for `wasm.ptr.to_funcref` and `wasm.funcref.to_ptr`.
ptr.to_funcref does a table.get from the indirect function pointer table. As a
special case, 0 is converted to the null funcref rather than doing table.get on
0. `wasm.funcref.to_ptr` is only handled when we call it immediately, otherwise
it will fail to lower. We could dynamically put the funcref into the table to
make it work but that would require a stack of spilled funcrefs and isn't worth
the effort.

In the process of looking into this, I noticed that clang used to allow casting
from funcref to function pointer but if the cast result escaped it would hit
`Cannot select: FUNCREF_TO_PTR` in the backend. I added a diagnostic that says
"a funcref can only be converted to a pointer to be directly called" to make
this a little cleaner.

Co-authored-by: Hood Chatham <roberthoodchatham@gmail.com>
Co-authored-by: Paulo Matos <pmatos@igalia.com>
dschuff pushed a commit that referenced this pull request Jun 25, 2026
Originally #71540 by Paolo Matos, I picked it up and finished it.
Resolves #69894.

Model WebAssembly externref and funcref as target("wasm.externref") /
target("wasm.funcref") TargetExtTypes instead of pointers in
non-integral address spaces 10 and 20.

The entire WebAssemblyLowerRefTypesIntPtrConv can be removed.

This breaks the GlobalISel handling for reference types, I just disabled
GlobalISel handling for functions that use them.

I added intrinsics for `wasm.ptr.to_funcref` and `wasm.funcref.to_ptr`.
ptr.to_funcref does a table.get from the indirect function pointer
table. As a special case, 0 is converted to the null funcref rather than
doing table.get on 0. `wasm.funcref.to_ptr` is only handled when we call
it immediately, otherwise it will fail to lower. We could dynamically
put the funcref into the table to make it work but that would require a
stack of spilled funcrefs and isn't worth the effort.

In the process of looking into this, I noticed that clang used to allow
casting from funcref to function pointer but if the cast result escaped
it would hit `Cannot select: FUNCREF_TO_PTR` in the backend. I added a
diagnostic that says "a funcref can only be converted to a pointer to be
directly called" to make this a little cleaner.

cc @QuantumSegfault

---------

Co-authored-by: Paulo Matos <pmatos@igalia.com>
@QuantumSegfault

Copy link
Copy Markdown
Contributor

Done in PR #203165

maarcosrmz pushed a commit to maarcosrmz/llvm-project that referenced this pull request Jul 1, 2026
Originally llvm#71540 by Paolo Matos, I picked it up and finished it.
Resolves llvm#69894.

Model WebAssembly externref and funcref as target("wasm.externref") /
target("wasm.funcref") TargetExtTypes instead of pointers in
non-integral address spaces 10 and 20.

The entire WebAssemblyLowerRefTypesIntPtrConv can be removed.

This breaks the GlobalISel handling for reference types, I just disabled
GlobalISel handling for functions that use them.

I added intrinsics for `wasm.ptr.to_funcref` and `wasm.funcref.to_ptr`.
ptr.to_funcref does a table.get from the indirect function pointer
table. As a special case, 0 is converted to the null funcref rather than
doing table.get on 0. `wasm.funcref.to_ptr` is only handled when we call
it immediately, otherwise it will fail to lower. We could dynamically
put the funcref into the table to make it work but that would require a
stack of spilled funcrefs and isn't worth the effort.

In the process of looking into this, I noticed that clang used to allow
casting from funcref to function pointer but if the cast result escaped
it would hit `Cannot select: FUNCREF_TO_PTR` in the backend. I added a
diagnostic that says "a funcref can only be converted to a pointer to be
directly called" to make this a little cleaner.

cc @QuantumSegfault

---------

Co-authored-by: Paulo Matos <pmatos@igalia.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants