1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-26 12:43:36 +01:00

[WebAssembly] Add memory intrinsics handling to mayThrow()

Summary:
Previously, `WebAssembly::mayThrow()` assumed all inputs are global
addresses. But when intrinsics, such as `memcpy`, `memmove`, or `memset`
are lowered to external symbols in instruction selection and later
emitted as library calls. And these functions don't throw.

This patch adds handling to those memory intrinsics to `mayThrow`
function. But while most of libcalls don't throw, we can't guarantee all
of them don't throw, so currently we conservatively return true for all
other external symbols.

I think a better way to solve this problem is to embed 'nounwind' info
in `TargetLowering::CallLoweringInfo`, so that we can access the info
from the backend. This will also enable transferring 'nounwind'
properties of LLVM IR instructions. Currently we don't transfer that
info and we can only access properties of callee functions, if the
callees are within the module. Other targets don't need this info in the
backend because they do all the processing before isel, but it will help
us because that info will reduce code size increase in fixing unwind
destination mismatches in CFGStackify.

But for now we return false for these memory intrinsics and true for all
other libcalls conservatively.

Reviewers: dschuff

Subscribers: sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits

Tags: #llvm

Differential Revision: https://reviews.llvm.org/D68553

llvm-svn: 373967
This commit is contained in:
Heejin Ahn 2019-10-07 21:14:45 +00:00
parent aa1651acf6
commit 737d120caf
2 changed files with 61 additions and 1 deletions

View File

@ -50,7 +50,21 @@ bool WebAssembly::mayThrow(const MachineInstr &MI) {
return false;
const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI.getOpcode()));
assert(MO.isGlobal());
assert(MO.isGlobal() || MO.isSymbol());
if (MO.isSymbol()) {
// Some intrinsics are lowered to calls to external symbols, which are then
// lowered to calls to library functions. Most of libcalls don't throw, but
// we only list some of them here now.
// TODO Consider adding 'nounwind' info in TargetLowering::CallLoweringInfo
// instead for more accurate info.
const char *Name = MO.getSymbolName();
if (strcmp(Name, "memcpy") == 0 || strcmp(Name, "memmove") == 0 ||
strcmp(Name, "memset") == 0)
return false;
return true;
}
const auto *F = dyn_cast<Function>(MO.getGlobal());
if (!F)
return true;

View File

@ -664,11 +664,51 @@ if.end: ; preds = %cont, %catch.start,
ret void
}
%class.Object = type { i8 }
; Intrinsics like memcpy, memmove, and memset don't throw and are lowered into
; calls to external symbols (not global addresses) in instruction selection,
; which will be eventually lowered to library function calls.
; Because this test runs with -wasm-disable-ehpad-sort, these library calls in
; invoke.cont BB fall within try~end_try, but they shouldn't cause crashes or
; unwinding destination mismatches in CFGStackify.
; NOSORT-LABEL: test10
; NOSORT: try
; NOSORT: call foo
; NOSORT: i32.call {{.*}} memcpy
; NOSORT: i32.call {{.*}} memmove
; NOSORT: i32.call {{.*}} memset
; NOSORT: return
; NOSORT: catch
; NOSORT: rethrow
; NOSORT: end_try
define void @test10(i8* %a, i8* %b) personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
%o = alloca %class.Object, align 1
invoke void @foo()
to label %invoke.cont unwind label %ehcleanup
invoke.cont: ; preds = %entry
call void @llvm.memcpy.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
call void @llvm.memmove.p0i8.p0i8.i32(i8* %a, i8* %b, i32 100, i1 false)
call void @llvm.memset.p0i8.i32(i8* %a, i8 0, i32 100, i1 false)
%call = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o) #1
ret void
ehcleanup: ; preds = %entry
%0 = cleanuppad within none []
%call2 = call %class.Object* @_ZN6ObjectD2Ev(%class.Object* %o) #1 [ "funclet"(token %0) ]
cleanupret from %0 unwind to caller
}
declare void @foo()
declare void @bar()
declare i32 @baz()
; Function Attrs: nounwind
declare void @nothrow(i32) #0
; Function Attrs: nounwind
declare %class.Object* @_ZN6ObjectD2Ev(%class.Object* returned) #0
declare i32 @__gxx_wasm_personality_v0(...)
declare i8* @llvm.wasm.get.exception(token)
declare i32 @llvm.wasm.get.ehselector(token)
@ -678,5 +718,11 @@ declare i8* @__cxa_begin_catch(i8*)
declare void @__cxa_end_catch()
declare void @__clang_call_terminate(i8*)
declare void @_ZSt9terminatev()
; Function Attrs: nounwind
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* noalias nocapture writeonly, i8* noalias nocapture readonly, i32, i1 immarg) #0
; Function Attrs: nounwind
declare void @llvm.memmove.p0i8.p0i8.i32(i8* nocapture, i8* nocapture readonly, i32, i1 immarg) #0
; Function Attrs: nounwind
declare void @llvm.memset.p0i8.i32(i8* nocapture writeonly, i8, i32, i1 immarg) #0
attributes #0 = { nounwind }