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.getContext());
70 IRB.SetInsertPoint(&AI);
71 auto *NewAI = IRB.CreateAlloca(Ty: AI.getAllocatedType(),
72 AddrSpace: WebAssembly::WASM_ADDRESS_SPACE_VAR, ArraySize: nullptr,
73 Name: AI.getName() + ".var");
74 // Preserve the original alloca's alignment.
75 NewAI->setAlignment(AI.getAlign());
76
77 // The below is basically equivalent to AI.replaceAllUsesWith(NewAI), but we
78 // cannot use it because it requires the old and new types be the same,
79 // which is not true here because the address spaces are different.
80 if (AI.hasValueHandle())
81 ValueHandleBase::ValueIsRAUWd(Old: &AI, New: NewAI);
82 if (AI.isUsedByMetadata())
83 ValueAsMetadata::handleRAUW(From: &AI, To: NewAI);
84 while (!AI.materialized_use_empty()) {
85 Use &U = *AI.materialized_use_begin();
86 U.set(NewAI);
87 }
88
89 AI.eraseFromParent();
90 }
91}
92
93bool WebAssemblyRefTypeMem2LocalImpl::runOnFunction(Function &F) {
94 LLVM_DEBUG(dbgs() << "********** WebAssembly RefType Mem2Local **********\n"
95 "********** Function: "
96 << F.getName() << '\n');
97
98 if (F.getFnAttribute(Kind: "target-features")
99 .getValueAsString()
100 .contains(Other: "+reference-types"))
101 visit(F);
102 return Changed;
103}
104
105bool WebAssemblyRefTypeMem2LocalLegacy::runOnFunction(Function &F) {
106 WebAssemblyRefTypeMem2LocalImpl Impl;
107 return Impl.runOnFunction(F);
108}
109
110PreservedAnalyses
111WebAssemblyRefTypeMem2LocalPass::run(Function &F,
112 FunctionAnalysisManager &FAM) {
113 WebAssemblyRefTypeMem2LocalImpl Impl;
114 return Impl.runOnFunction(F)
115 ? PreservedAnalyses::none().preserveSet<CFGAnalyses>()
116 : PreservedAnalyses::all();
117}
118