mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 05:01:59 +01:00
cce58dcf18
Summary: Unlike normal traps, debug traps are allowed to return and can have additional instructions in the same basic block. Without explicit backend support for debug traps, they are lowered in ISel as normal traps. Since normal traps are lowered in the WebAssembly backend to the UNREACHABLE instruction, which is a terminator, using debug traps could lead to invalid MBBs when there are additional instructions after the trap. This patch fixes the issue by lowering debug traps to a new version of the UNREACHABLE instruction, DEBUG_UNREACHABLE, that is not a terminator. An alternative approach would have been to make UNREACHABLE not a terminator, but that breaks a large number of tests. In particular, it would require removing the traps inserted after noreturn calls to @llvm.wasm.throw because otherwise the terminator throw would be followed by a non-terminator UNREACHABLE and we would be back to having invalid MBBs. Overall the approach in this patch seems simpler. Reviewers: aheejin, dschuff Subscribers: sbc100, jgravelle-google, hiraditya, sunfish, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D81055
61 lines
1.5 KiB
LLVM
61 lines
1.5 KiB
LLVM
; RUN: llc < %s -asm-verbose=false -verify-machineinstrs | FileCheck %s
|
|
|
|
; Test lowering of __builtin_debugtrap in cases where lowering it via
|
|
; the normal UNREACHABLE instruction would yield invalid
|
|
; MachineFunctions.
|
|
|
|
target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
|
|
target triple = "wasm32"
|
|
|
|
declare void @llvm.debugtrap()
|
|
|
|
; CHECK-LABEL: foo:
|
|
; CHECK-NEXT: .functype foo (i32) -> ()
|
|
; CHECK-NEXT: .LBB0_1:
|
|
; CHECK-NEXT: loop
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK-NEXT: i32.const 0
|
|
; CHECK-NEXT: br_if 0
|
|
; CHECK-NEXT: end_loop
|
|
; CHECK-NEXT: end_function
|
|
define void @foo(i32 %g) {
|
|
entry:
|
|
br label %for.body
|
|
|
|
for.body:
|
|
call void @llvm.debugtrap()
|
|
%exitcond = icmp eq i32 undef, %g
|
|
br i1 %exitcond, label %for.cond.cleanup, label %for.body
|
|
|
|
for.cond.cleanup:
|
|
ret void
|
|
}
|
|
|
|
; CHECK-LABEL: middle_of_block:
|
|
; CHECK-NEXT: .functype middle_of_block (i32, i32) -> (i32)
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK-NEXT: local.get 0
|
|
; CHECK-NEXT: local.get 1
|
|
; CHECK-NEXT: i32.add
|
|
; CHECK-NEXT: end_function
|
|
define i32 @middle_of_block(i32 %x, i32 %y) {
|
|
%r = add i32 %x, %y
|
|
call void @llvm.debugtrap()
|
|
ret i32 %r
|
|
}
|
|
|
|
; CHECK-LABEL: really_middle_of_block:
|
|
; CHECK-NEXT: .functype really_middle_of_block () -> (i32)
|
|
; CHECK-NEXT: call bar
|
|
; CHECK-NEXT: drop
|
|
; CHECK-NEXT: unreachable
|
|
; CHECK-NEXT: call bar
|
|
; CHECK-NEXT: end_function
|
|
declare i32 @bar()
|
|
define i32 @really_middle_of_block() {
|
|
%x = call i32 @bar()
|
|
call void @llvm.debugtrap()
|
|
%r = call i32 @bar()
|
|
ret i32 %r
|
|
}
|