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:
parent
aa1651acf6
commit
737d120caf
@ -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;
|
||||
|
@ -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 }
|
||||
|
Loading…
Reference in New Issue
Block a user