1//=== WebAssemblyRefTypeMem2Local.cpp - WebAssembly RefType Mem2Local -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8///
9/// \file
10/// Assign reference type allocas to local addrspace (addrspace(1)) so that
11/// their loads and stores can be lowered to local.gets/local.sets.
12///
13//===----------------------------------------------------------------------===//
14
15#include "Utils/WasmAddressSpaces.h"
16#include "Utils/WebAssemblyTypeUtilities.h"
17#include "WebAssembly.h"
18#include "llvm/IR/Analysis.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/InstVisitor.h"
21#include "llvm/IR/Instructions.h"
22#include "llvm/IR/PassManager.h"
23#include "llvm/IR/ValueHandle.h"
24#include "llvm/Pass.h"
25using namespace llvm;
26
27#define DEBUG_TYPE "wasm-ref-type-mem2local"
28
29namespace {
30class WebAssemblyRefTypeMem2LocalImpl
31 : public InstVisitor<WebAssemblyRefTypeMem2LocalImpl> {
32 bool Changed = false;
33
34public:
35 void visitAllocaInst(AllocaInst &AI);
36 bool runOnFunction(Function &F);
37};
38
39class WebAssemblyRefTypeMem2LocalLegacy final : public FunctionPass {
40 StringRef getPassName() const override {
41 return "WebAssembly Reference Types Memory to Local";
42 }
43
44 void getAnalysisUsage(AnalysisUsage &AU) const override {
45 AU.setPreservesCFG();
46 FunctionPass::getAnalysisUsage(AU);
47 }
48
49 bool runOnFunction(Function &F) override;
50
51public:
52 static char ID;
53 WebAssemblyRefTypeMem2LocalLegacy() : FunctionPass(ID) {}
54};
55} // End anonymous namespace
56
57char WebAssemblyRefTypeMem2LocalLegacy::ID = 0;
58INITIALIZE_PASS(WebAssemblyRefTypeMem2LocalLegacy, DEBUG_TYPE,
59 "Assign reference type allocas to local address space", true,
60 false)
61
62FunctionPass *llvm::createWebAssemblyRefTypeMem2LocalLegacyPass() {
63 return new WebAssemblyRefTypeMem2LocalLegacy();
64}
65
66void WebAssemblyRefTypeMem2LocalImpl::visitAllocaInst(AllocaInst &AI) {
67 if (WebAssembly::isWebAssemblyReferenceType(Ty: AI.getAllocatedType())) {
68 Changed = true;
69 IRBuilder<> IRB(&AI);
70 auto *NewAI = IRB.CreateAlloca(Ty: AI.getAllocatedType(),
71 AddrSpace: WebAssembly::WASM_ADDRESS_SPACE_VAR, ArraySize: nullptr,
72 Name: AI.getName() + ".var");
73 // Preserve the original alloca's alignment.
74 NewAI->setAlignment(AI.getAlign());
75
76 // The below is basically equivalent to AI.replaceAllUsesWith(NewAI), but we
77 // cannot use it because it requires the old and new types be the same,
78 // which is not true here because the address spaces are different.
79 if (AI.hasValueHandle())
80 ValueHandleBase::ValueIsRAUWd(Old: &AI, New: NewAI);
81 if (AI.isUsedByMetadata())
82 ValueAsMetadata::handleRAUW(From: &AI, To: NewAI);
83 while (!AI.materialized_use_empty()) {
84 Use &U = *AI.materialized_use_begin();
85 U.set(NewAI);
86 }
87
88 AI.eraseFromParent();
89 }
90}
91
92bool WebAssemblyRefTypeMem2LocalImpl::runOnFunction(Function &F) {
93 LLVM_DEBUG(dbgs() << "********** WebAssembly RefType Mem2Local **********\n"
94 "********** Function: "
95 << F.getName() << '\n');
96
97 if (F.getFnAttribute(Kind: "target-features")
98 .getValueAsString()
99 .contains(Other: "+reference-types"))
100 visit(F);
101 return Changed;
102}
103
104bool WebAssemblyRefTypeMem2LocalLegacy::runOnFunction(Function &F) {
105 WebAssemblyRefTypeMem2LocalImpl Impl;
106 return Impl.runOnFunction(F);
107}
108
109PreservedAnalyses
110WebAssemblyRefTypeMem2LocalPass::run(Function &F,
111 FunctionAnalysisManager &FAM) {
112 WebAssemblyRefTypeMem2LocalImpl Impl;
113 return Impl.runOnFunction(F)
114 ? PreservedAnalyses::none().preserveSet<CFGAnalyses>()
115 : PreservedAnalyses::all();
116}
117