forked from llvm/llvm-project
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[WebAssembly] Add RefTypeMem2Local pass (llvm#81965)
This adds `WebAssemblyRefTypeMem2Local` pass, which changes the address spaces of reference type `alloca`s to `addrspace(1)`. This in turn changes the address spaces of all `load` and `store` instructions that use the `alloca`s. `addrspace(1)` is `WASM_ADDRESS_SPACE_VAR`, and loads and stores to this address space become `local.get`s and `local.set`s, thanks to the Wasm local IR support added in llvm@82f92e3. In a follow-up PR, I am planning to replace the usage of mem2reg pass with this to solve the reference type `alloca` problems described in llvm#81575.
- Loading branch information
Showing
5 changed files
with
152 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
91 changes: 91 additions & 0 deletions
91
llvm/lib/Target/WebAssembly/WebAssemblyRefTypeMem2Local.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,91 @@ | ||
//=== WebAssemblyRefTypeMem2Local.cpp - WebAssembly RefType Mem2Local -----===// | ||
// | ||
// 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 | ||
/// Assign reference type allocas to local addrspace (addrspace(1)) so that | ||
/// their loads and stores can be lowered to local.gets/local.sets. | ||
/// | ||
//===----------------------------------------------------------------------===// | ||
|
||
#include "Utils/WasmAddressSpaces.h" | ||
#include "Utils/WebAssemblyTypeUtilities.h" | ||
#include "WebAssembly.h" | ||
#include "llvm/IR/IRBuilder.h" | ||
#include "llvm/IR/InstVisitor.h" | ||
#include "llvm/IR/ValueHandle.h" | ||
#include "llvm/Pass.h" | ||
using namespace llvm; | ||
|
||
#define DEBUG_TYPE "wasm-ref-type-mem2local" | ||
|
||
namespace { | ||
class WebAssemblyRefTypeMem2Local final | ||
: public FunctionPass, | ||
public InstVisitor<WebAssemblyRefTypeMem2Local> { | ||
StringRef getPassName() const override { | ||
return "WebAssembly Reference Types Memory to Local"; | ||
} | ||
|
||
void getAnalysisUsage(AnalysisUsage &AU) const override { | ||
AU.setPreservesCFG(); | ||
FunctionPass::getAnalysisUsage(AU); | ||
} | ||
|
||
bool runOnFunction(Function &F) override; | ||
bool Changed = false; | ||
|
||
public: | ||
static char ID; | ||
WebAssemblyRefTypeMem2Local() : FunctionPass(ID) {} | ||
|
||
void visitAllocaInst(AllocaInst &AI); | ||
}; | ||
} // End anonymous namespace | ||
|
||
char WebAssemblyRefTypeMem2Local::ID = 0; | ||
INITIALIZE_PASS(WebAssemblyRefTypeMem2Local, DEBUG_TYPE, | ||
"Assign reference type allocas to local address space", true, | ||
false) | ||
|
||
FunctionPass *llvm::createWebAssemblyRefTypeMem2Local() { | ||
return new WebAssemblyRefTypeMem2Local(); | ||
} | ||
|
||
void WebAssemblyRefTypeMem2Local::visitAllocaInst(AllocaInst &AI) { | ||
if (WebAssembly::isWebAssemblyReferenceType(AI.getAllocatedType())) { | ||
Changed = true; | ||
IRBuilder<> IRB(AI.getContext()); | ||
IRB.SetInsertPoint(&AI); | ||
auto *NewAI = IRB.CreateAlloca(AI.getAllocatedType(), | ||
WebAssembly::WASM_ADDRESS_SPACE_VAR, nullptr, | ||
AI.getName() + ".var"); | ||
|
||
// The below is basically equivalent to AI.replaceAllUsesWith(NewAI), but we | ||
// cannot use it because it requires the old and new types be the same, | ||
// which is not true here because the address spaces are different. | ||
if (AI.hasValueHandle()) | ||
ValueHandleBase::ValueIsRAUWd(&AI, NewAI); | ||
if (AI.isUsedByMetadata()) | ||
ValueAsMetadata::handleRAUW(&AI, NewAI); | ||
while (!AI.materialized_use_empty()) { | ||
Use &U = *AI.materialized_use_begin(); | ||
U.set(NewAI); | ||
} | ||
|
||
AI.eraseFromParent(); | ||
} | ||
} | ||
|
||
bool WebAssemblyRefTypeMem2Local::runOnFunction(Function &F) { | ||
LLVM_DEBUG(dbgs() << "********** WebAssembly RefType Mem2Local **********\n" | ||
"********** Function: " | ||
<< F.getName() << '\n'); | ||
|
||
visit(F); | ||
return Changed; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,57 @@ | ||
; RUN: opt < %s -wasm-ref-type-mem2local -S | FileCheck %s | ||
|
||
target triple = "wasm32-unknown-unknown" | ||
|
||
%externref = type ptr addrspace(10) | ||
%funcref = type ptr addrspace(20) | ||
|
||
declare %externref @get_externref() | ||
declare %funcref @get_funcref() | ||
declare i32 @get_i32() | ||
declare void @take_externref(%externref) | ||
declare void @take_funcref(%funcref) | ||
declare void @take_i32(i32) | ||
|
||
; Reference type allocas should be moved to addrspace(1) | ||
; CHECK-LABEL: @test_ref_type_mem2local | ||
define void @test_ref_type_mem2local() { | ||
entry: | ||
%alloc.externref = alloca %externref, align 1 | ||
%eref = call %externref @get_externref() | ||
store %externref %eref, ptr %alloc.externref, align 1 | ||
%eref.loaded = load %externref, ptr %alloc.externref, align 1 | ||
call void @take_externref(%externref %eref.loaded) | ||
; CHECK: %alloc.externref.var = alloca ptr addrspace(10), align 1, addrspace(1) | ||
; CHECK-NEXT: %eref = call ptr addrspace(10) @get_externref() | ||
; CHECK-NEXT: store ptr addrspace(10) %eref, ptr addrspace(1) %alloc.externref.var, align 1 | ||
; CHECK-NEXT: %eref.loaded = load ptr addrspace(10), ptr addrspace(1) %alloc.externref.var, align 1 | ||
; CHECK-NEXT: call void @take_externref(ptr addrspace(10) %eref.loaded) | ||
|
||
%alloc.funcref = alloca %funcref, align 1 | ||
%fref = call %funcref @get_funcref() | ||
store %funcref %fref, ptr %alloc.funcref, align 1 | ||
%fref.loaded = load %funcref, ptr %alloc.funcref, align 1 | ||
call void @take_funcref(%funcref %fref.loaded) | ||
; CHECK-NEXT: %alloc.funcref.var = alloca ptr addrspace(20), align 1, addrspace(1) | ||
; CHECK-NEXT: %fref = call ptr addrspace(20) @get_funcref() | ||
; CHECK-NEXT: store ptr addrspace(20) %fref, ptr addrspace(1) %alloc.funcref.var, align 1 | ||
; CHECK-NEXT: %fref.loaded = load ptr addrspace(20), ptr addrspace(1) %alloc.funcref.var, align 1 | ||
; CHECK-NEXT: call void @take_funcref(ptr addrspace(20) %fref.loaded) | ||
|
||
ret void | ||
} | ||
|
||
; POD type allocas should stay the same | ||
; CHECK-LABEL: @test_pod_type | ||
define void @test_pod_type() { | ||
entry: | ||
%alloc.i32 = alloca i32 | ||
%i32 = call i32 @get_i32() | ||
store i32 %i32, ptr %alloc.i32 | ||
%i32.loaded = load i32, ptr %alloc.i32 | ||
call void @take_i32(i32 %i32.loaded) | ||
; CHECK: %alloc.i32 = alloca i32, align 4{{$}} | ||
; CHECK-NOT: addrspace(1) | ||
|
||
ret void | ||
} |