forked from OSchip/llvm-project
Reland: "[WebAssembly] Add new pass to lower int/ptr conversions of reftypes"
Add new pass LowerRefTypesIntPtrConv to generate debugtrap
instruction for an inttoptr and ptrtoint of a reference type instead
of erroring, since calling these instructions on non-integral pointers
has been since allowed (see ac81cb7e6
).
Differential Revision: https://reviews.llvm.org/D107102
This commit is contained in:
parent
735da5f5ad
commit
d3a0a65bf0
|
@ -36,6 +36,7 @@ add_llvm_target(WebAssemblyCodeGen
|
|||
WebAssemblyLowerBrUnless.cpp
|
||||
WebAssemblyLowerEmscriptenEHSjLj.cpp
|
||||
WebAssemblyLowerGlobalDtors.cpp
|
||||
WebAssemblyLowerRefTypesIntPtrConv.cpp
|
||||
WebAssemblyMachineFunctionInfo.cpp
|
||||
WebAssemblyMCInstLower.cpp
|
||||
WebAssemblyMCLowerPrePass.cpp
|
||||
|
|
|
@ -31,6 +31,7 @@ ModulePass *createWebAssemblyLowerGlobalDtors();
|
|||
ModulePass *createWebAssemblyAddMissingPrototypes();
|
||||
ModulePass *createWebAssemblyFixFunctionBitcasts();
|
||||
FunctionPass *createWebAssemblyOptimizeReturned();
|
||||
FunctionPass *createWebAssemblyLowerRefTypesIntPtrConv();
|
||||
|
||||
// ISel and immediate followup passes.
|
||||
FunctionPass *createWebAssemblyISelDag(WebAssemblyTargetMachine &TM,
|
||||
|
@ -85,6 +86,7 @@ void initializeWebAssemblyRegNumberingPass(PassRegistry &);
|
|||
void initializeWebAssemblyDebugFixupPass(PassRegistry &);
|
||||
void initializeWebAssemblyPeepholePass(PassRegistry &);
|
||||
void initializeWebAssemblyMCLowerPrePassPass(PassRegistry &);
|
||||
void initializeWebAssemblyLowerRefTypesIntPtrConvPass(PassRegistry &);
|
||||
|
||||
namespace WebAssembly {
|
||||
enum TargetIndex {
|
||||
|
|
|
@ -24,6 +24,7 @@
|
|||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Support/MathExtras.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
#define DEBUG_TYPE "wasm-isel"
|
||||
|
@ -48,32 +49,11 @@ public:
|
|||
return "WebAssembly Instruction Selection";
|
||||
}
|
||||
|
||||
void checkForInvalidNodes(const Function &F) {
|
||||
// This function will check for uses of ptrtoint on reference types and
|
||||
// report a fatal error if these are found.
|
||||
for (const BasicBlock &BB : F) {
|
||||
for (const Instruction &I : BB) {
|
||||
if (const PtrToIntInst *PTI = dyn_cast<const PtrToIntInst>(&I)) {
|
||||
const Value *V = PTI->getPointerOperand();
|
||||
if (WebAssemblyTargetLowering::isFuncrefType(V->getType()) ||
|
||||
WebAssemblyTargetLowering::isExternrefType(V->getType()))
|
||||
report_fatal_error("ptrtoint not allowed on reference types");
|
||||
} else if (const IntToPtrInst *ITP = dyn_cast<const IntToPtrInst>(&I)) {
|
||||
if (WebAssemblyTargetLowering::isFuncrefType(ITP->getDestTy()) ||
|
||||
WebAssemblyTargetLowering::isExternrefType(ITP->getDestTy()))
|
||||
report_fatal_error("inttoptr not allowed on reference types");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool runOnMachineFunction(MachineFunction &MF) override {
|
||||
LLVM_DEBUG(dbgs() << "********** ISelDAGToDAG **********\n"
|
||||
"********** Function: "
|
||||
<< MF.getName() << '\n');
|
||||
|
||||
checkForInvalidNodes(MF.getFunction());
|
||||
|
||||
Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
|
||||
|
||||
return SelectionDAGISel::runOnMachineFunction(MF);
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
//=== 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 "WebAssembly.h"
|
||||
#include "WebAssemblySubtarget.h"
|
||||
#include "llvm/IR/InstIterator.h"
|
||||
#include "llvm/Pass.h"
|
||||
|
||||
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";
|
||||
}
|
||||
|
||||
static bool isRefType(Type *T);
|
||||
|
||||
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::isRefType(Type *T) {
|
||||
return WebAssemblyTargetLowering::isFuncrefType(T) ||
|
||||
WebAssemblyTargetLowering::isExternrefType(T);
|
||||
}
|
||||
|
||||
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 && isRefType(PTI->getPointerOperand()->getType())) &&
|
||||
!(ITP && isRefType(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();
|
||||
}
|
|
@ -332,6 +332,7 @@ public:
|
|||
void addPostRegAlloc() override;
|
||||
bool addGCPasses() override { return false; }
|
||||
void addPreEmitPass() override;
|
||||
bool addPreISel() override;
|
||||
|
||||
// No reg alloc
|
||||
bool addRegAssignAndRewriteFast() override { return false; }
|
||||
|
@ -518,6 +519,12 @@ void WebAssemblyPassConfig::addPreEmitPass() {
|
|||
addPass(createWebAssemblyMCLowerPrePass());
|
||||
}
|
||||
|
||||
bool WebAssemblyPassConfig::addPreISel() {
|
||||
TargetPassConfig::addPreISel();
|
||||
addPass(createWebAssemblyLowerRefTypesIntPtrConv());
|
||||
return false;
|
||||
}
|
||||
|
||||
yaml::MachineFunctionInfo *
|
||||
WebAssemblyTargetMachine::createDefaultFuncInfoYAML() const {
|
||||
return new yaml::WebAssemblyFunctionInfo();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: not --crash llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types 2>&1 | FileCheck %s
|
||||
|
||||
%extern = type opaque
|
||||
%externref = type %extern addrspace(10)*
|
||||
|
@ -8,4 +8,10 @@ define %externref @int_to_externref(i32 %i) {
|
|||
ret %externref %ref
|
||||
}
|
||||
|
||||
; CHECK-ERROR: LLVM ERROR: inttoptr not allowed on reference types
|
||||
|
||||
; 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
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
; RUN: not --crash llc --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types < %s 2>&1 | FileCheck %s --check-prefix=CHECK-ERROR
|
||||
; RUN: llc < %s --mtriple=wasm32-unknown-unknown -asm-verbose=false -mattr=+reference-types 2>&1 | FileCheck %s
|
||||
|
||||
%extern = type opaque
|
||||
%externref = type %extern addrspace(10)*
|
||||
|
@ -8,4 +8,9 @@ define i32 @externref_to_int(%externref %ref) {
|
|||
ret i32 %i
|
||||
}
|
||||
|
||||
; CHECK-ERROR: LLVM ERROR: ptrtoint not allowed on reference types
|
||||
; CHECK-LABEL: externref_to_int:
|
||||
; CHECK-NEXT: .functype externref_to_int (externref) -> (i32)
|
||||
; CHECK-NEXT: .local i32
|
||||
; CHECK-NEXT: unreachable
|
||||
; CHECK-NEXT: local.get 1
|
||||
; CHECK-NEXT: end_function
|
||||
|
|
|
@ -52,6 +52,7 @@ static_library("LLVMWebAssemblyCodeGen") {
|
|||
"WebAssemblyLowerBrUnless.cpp",
|
||||
"WebAssemblyLowerEmscriptenEHSjLj.cpp",
|
||||
"WebAssemblyLowerGlobalDtors.cpp",
|
||||
"WebAssemblyLowerRefTypesIntPtrConv.cpp",
|
||||
"WebAssemblyMCInstLower.cpp",
|
||||
"WebAssemblyMCLowerPrePass.cpp",
|
||||
"WebAssemblyMachineFunctionInfo.cpp",
|
||||
|
|
Loading…
Reference in New Issue