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/IRBuilder.h" |
19 | #include "llvm/IR/InstVisitor.h" |
20 | #include "llvm/IR/ValueHandle.h" |
21 | #include "llvm/Pass.h" |
22 | using namespace llvm; |
23 | |
24 | #define DEBUG_TYPE "wasm-ref-type-mem2local" |
25 | |
26 | namespace { |
27 | class WebAssemblyRefTypeMem2Local final |
28 | : public FunctionPass, |
29 | public InstVisitor<WebAssemblyRefTypeMem2Local> { |
30 | StringRef getPassName() const override { |
31 | return "WebAssembly Reference Types Memory to Local" ; |
32 | } |
33 | |
34 | void getAnalysisUsage(AnalysisUsage &AU) const override { |
35 | AU.setPreservesCFG(); |
36 | FunctionPass::getAnalysisUsage(AU); |
37 | } |
38 | |
39 | bool runOnFunction(Function &F) override; |
40 | bool Changed = false; |
41 | |
42 | public: |
43 | static char ID; |
44 | WebAssemblyRefTypeMem2Local() : FunctionPass(ID) {} |
45 | |
46 | void visitAllocaInst(AllocaInst &AI); |
47 | }; |
48 | } // End anonymous namespace |
49 | |
50 | char WebAssemblyRefTypeMem2Local::ID = 0; |
51 | INITIALIZE_PASS(WebAssemblyRefTypeMem2Local, DEBUG_TYPE, |
52 | "Assign reference type allocas to local address space" , true, |
53 | false) |
54 | |
55 | FunctionPass *llvm::createWebAssemblyRefTypeMem2Local() { |
56 | return new WebAssemblyRefTypeMem2Local(); |
57 | } |
58 | |
59 | void WebAssemblyRefTypeMem2Local::visitAllocaInst(AllocaInst &AI) { |
60 | if (WebAssembly::isWebAssemblyReferenceType(Ty: AI.getAllocatedType())) { |
61 | Changed = true; |
62 | IRBuilder<> IRB(AI.getContext()); |
63 | IRB.SetInsertPoint(&AI); |
64 | auto *NewAI = IRB.CreateAlloca(Ty: AI.getAllocatedType(), |
65 | AddrSpace: WebAssembly::WASM_ADDRESS_SPACE_VAR, ArraySize: nullptr, |
66 | Name: AI.getName() + ".var" ); |
67 | |
68 | // The below is basically equivalent to AI.replaceAllUsesWith(NewAI), but we |
69 | // cannot use it because it requires the old and new types be the same, |
70 | // which is not true here because the address spaces are different. |
71 | if (AI.hasValueHandle()) |
72 | ValueHandleBase::ValueIsRAUWd(Old: &AI, New: NewAI); |
73 | if (AI.isUsedByMetadata()) |
74 | ValueAsMetadata::handleRAUW(From: &AI, To: NewAI); |
75 | while (!AI.materialized_use_empty()) { |
76 | Use &U = *AI.materialized_use_begin(); |
77 | U.set(NewAI); |
78 | } |
79 | |
80 | AI.eraseFromParent(); |
81 | } |
82 | } |
83 | |
84 | bool WebAssemblyRefTypeMem2Local::runOnFunction(Function &F) { |
85 | LLVM_DEBUG(dbgs() << "********** WebAssembly RefType Mem2Local **********\n" |
86 | "********** Function: " |
87 | << F.getName() << '\n'); |
88 | |
89 | if (F.getFnAttribute(Kind: "target-features" ) |
90 | .getValueAsString() |
91 | .contains(Other: "+reference-types" )) |
92 | visit(F); |
93 | return Changed; |
94 | } |
95 | |