From f026b9a31cd3d3f980a14bc612a698312570e3fd Mon Sep 17 00:00:00 2001 From: monojenkins Date: Thu, 16 Jul 2020 13:08:51 -0400 Subject: [PATCH] [mono] fix bound checks for Spans in LLVM-jit mode (add extra SROA pass) (#20054) I noticed that the following code leaves bound checks when compiled using LLVM-JIT: ```csharp static void Test(Span span) { for (int i = 0; i < span.Length; i++) x[i] = 0; } ``` #### Current codegen: ```asm Test: 0000000000000000 pushq %rax 0000000000000001 testl %esi, %esi 0000000000000003 jle 0x3f 0000000000000005 xorl %eax, %eax 0000000000000007 movl %esi, %ecx 0000000000000009 cmpq %rcx, %rax 000000000000000c jae 0x2c 000000000000000e nop 0000000000000010 movl $0x0, (%rdi) 0000000000000016 incq %rax 0000000000000019 movslq %esi, %rcx 000000000000001c cmpq %rcx, %rax 000000000000001f jge 0x3f 0000000000000021 addq $0x4, %rdi 0000000000000025 movl %esi, %ecx 0000000000000027 cmpq %rcx, %rax 000000000000002a jb 0x10 000000000000002c movabsq $0x7fc330531710, %rax 0000000000000036 movl $0x106, %edi 000000000000003b callq *(%rax) ;; <---- bound check 000000000000003d ud2 000000000000003f popq %rax 0000000000000040 retq ``` looks like an additional -sroa pass after lower-expect and instcombine fixes it: #### New codegen: ```asm Test: 0000000000000000 testl %esi, %esi 0000000000000002 jle 0x1f 0000000000000004 movl %esi, %eax 0000000000000006 nopw %cs:(%rax,%rax) 0000000000000010 movl $0x0, (%rdi) 0000000000000016 addq $0x4, %rdi 000000000000001a decq %rax 000000000000001d jne 0x10 000000000000001f retq ``` Here is the original LLVM IR before optimizations: https://godbolt.org/z/PLfR6x Co-authored-by: EgorBo --- mono/mini/llvm-jit.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mono/mini/llvm-jit.cpp b/mono/mini/llvm-jit.cpp index bd31c13dd31..1e896419f0b 100644 --- a/mono/mini/llvm-jit.cpp +++ b/mono/mini/llvm-jit.cpp @@ -457,7 +457,7 @@ init_passes_and_options () // FIXME: find optimal mono specific order of passes // see https://llvm.org/docs/Frontend/PerformanceTips.html#pass-ordering // the following order is based on a stripped version of "OPT -O2" - const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks -sroa -instcombine" NO_CALL_FRAME_OPT; + const char *default_opts = " -simplifycfg -sroa -lower-expect -instcombine -sroa -jump-threading -loop-rotate -licm -simplifycfg -lcssa -loop-idiom -indvars -loop-deletion -gvn -memcpyopt -sccp -bdce -instcombine -dse -simplifycfg -enable-implicit-null-checks -sroa -instcombine" NO_CALL_FRAME_OPT; const char *opts = g_getenv ("MONO_LLVM_OPT"); if (opts == NULL) opts = default_opts; -- 2.11.4.GIT