mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2025-02-01 13:11:39 +01:00
93803262f4
LLVM's targets need to know if stack pointer adjustments occur after the prologue. This is needed to correctly determine if the red-zone is appropriate to use or if a frame pointer is required. Normally, LLVM can figure this out very precisely by reasoning about the contents of the MachineFunction. There is an interesting corner case: inline assembly. The vast majority of inline assembly which will perform a push or pop is done so to pair up with pushf or popf as appropriate. Unfortunately, this inline assembly doesn't mark the stack pointer as clobbered because, well, it isn't. The stack pointer is decremented and then immediately incremented. Because of this, LLVM was changed in r256456 to conservatively assume that inline assembly contain a sequence of stack operations. This is unfortunate because the vast majority of inline assembly will not end up manipulating the stack pointer in any way at all. Instead, let's provide a more principled solution: an intrinsic. FWIW, other compilers (MSVC and GCC among them) also provide this functionality as an intrinsic. llvm-svn: 256685
123 lines
3.9 KiB
LLVM
123 lines
3.9 KiB
LLVM
; RUN: llc %s -o - -enable-shrink-wrap=true | FileCheck %s --check-prefix=CHECK --check-prefix=ENABLE
|
|
; RUN: llc %s -o - -enable-shrink-wrap=false | FileCheck %s --check-prefix=CHECK --check-prefix=DISABLE
|
|
|
|
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
|
|
target triple = "x86_64--windows-gnu"
|
|
|
|
; The output of this function with or without shrink-wrapping
|
|
; shouldn't change.
|
|
; Indeed, the epilogue block would have been if.else, meaning
|
|
; after the pops, we will have additional instruction (jump, mov,
|
|
; etc.) prior to the return and this is forbidden for Win64.
|
|
; CHECK-LABEL: loopInfoSaveOutsideLoop:
|
|
; CHECK: push
|
|
; CHECK-NOT: popq
|
|
; CHECK: popq
|
|
; CHECK-NOT: popq
|
|
; CHECK-NEXT: retq
|
|
define i32 @loopInfoSaveOutsideLoop(i32 %cond, i32 %N) #0 {
|
|
entry:
|
|
%tobool = icmp eq i32 %cond, 0
|
|
br i1 %tobool, label %if.else, label %for.preheader
|
|
|
|
for.preheader: ; preds = %entry
|
|
tail call void asm "nop", ""()
|
|
br label %for.body
|
|
|
|
for.body: ; preds = %for.body, %for.preheader
|
|
%i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
|
|
%sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
|
|
%call = tail call i32 asm "movl $$1, $0", "=r,~{ebx}"()
|
|
%add = add nsw i32 %call, %sum.04
|
|
%inc = add nuw nsw i32 %i.05, 1
|
|
%exitcond = icmp eq i32 %inc, 10
|
|
br i1 %exitcond, label %for.end, label %for.body
|
|
|
|
for.end: ; preds = %for.body
|
|
tail call void asm "nop", "~{ebx}"()
|
|
%shl = shl i32 %add, 3
|
|
br label %if.end
|
|
|
|
if.else: ; preds = %entry
|
|
%mul = shl nsw i32 %N, 1
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.else, %for.end
|
|
%sum.1 = phi i32 [ %shl, %for.end ], [ %mul, %if.else ]
|
|
ret i32 %sum.1
|
|
}
|
|
|
|
; When we can sink the epilogue of the function into an existing exit block,
|
|
; this is Ok for shrink-wrapping to kicks in.
|
|
; CHECK-LABEL: loopInfoSaveOutsideLoop2:
|
|
; ENABLE: testl %ecx, %ecx
|
|
; ENABLE-NEXT: je [[ELSE_LABEL:.LBB[0-9_]+]]
|
|
;
|
|
; Prologue code.
|
|
; Make sure we save the CSR used in the inline asm: rbx.
|
|
; CHECK: pushq %rbx
|
|
;
|
|
; DISABLE: testl %ecx, %ecx
|
|
; DISABLE-NEXT: je [[ELSE_LABEL:.LBB[0-9_]+]]
|
|
;
|
|
; CHECK: nop
|
|
; CHECK: xorl [[SUM:%eax]], [[SUM]]
|
|
; CHECK-NEXT: movl $10, [[IV:%e[a-z]+]]
|
|
;
|
|
; CHECK: [[LOOP_LABEL:.LBB[0-9_]+]]: # %for.body
|
|
; CHECK: movl $1, [[TMP:%e[a-z]+]]
|
|
; CHECK: addl [[TMP]], [[SUM]]
|
|
; CHECK-NEXT: decl [[IV]]
|
|
; CHECK-NEXT: jne [[LOOP_LABEL]]
|
|
; Next BB.
|
|
; CHECK: nop
|
|
; CHECK: shll $3, [[SUM]]
|
|
;
|
|
; DISABLE: jmp [[EPILOG_BB:.LBB[0-9_]+]]
|
|
;
|
|
; ENABLE-NEXT: popq %rbx
|
|
; ENABLE-NEXT: retq
|
|
;
|
|
; CHECK: [[ELSE_LABEL]]: # %if.else
|
|
; Shift second argument by one and store into returned register.
|
|
; CHECK: addl %edx, %edx
|
|
; CHECK: movl %edx, %eax
|
|
;
|
|
; DISABLE: [[EPILOG_BB]]: # %if.end
|
|
; DISABLE-NEXT: popq %rbx
|
|
;
|
|
; CHECK: retq
|
|
;
|
|
define i32 @loopInfoSaveOutsideLoop2(i32 %cond, i32 %N) #0 {
|
|
entry:
|
|
%tobool = icmp eq i32 %cond, 0
|
|
br i1 %tobool, label %if.else, label %for.preheader
|
|
|
|
for.preheader: ; preds = %entry
|
|
tail call void asm "nop", ""()
|
|
br label %for.body
|
|
|
|
for.body: ; preds = %for.body, %for.preheader
|
|
%i.05 = phi i32 [ %inc, %for.body ], [ 0, %for.preheader ]
|
|
%sum.04 = phi i32 [ %add, %for.body ], [ 0, %for.preheader ]
|
|
%call = tail call i32 asm "movl $$1, $0", "=r,~{ebx}"()
|
|
%add = add nsw i32 %call, %sum.04
|
|
%inc = add nuw nsw i32 %i.05, 1
|
|
%exitcond = icmp eq i32 %inc, 10
|
|
br i1 %exitcond, label %for.end, label %for.body
|
|
|
|
for.end: ; preds = %for.body
|
|
tail call void asm "nop", "~{ebx}"()
|
|
%shl = shl i32 %add, 3
|
|
ret i32 %shl
|
|
|
|
if.else: ; preds = %entry
|
|
%mul = shl nsw i32 %N, 1
|
|
br label %if.end
|
|
|
|
if.end: ; preds = %if.else, %for.end
|
|
ret i32 %mul
|
|
}
|
|
|
|
attributes #0 = { uwtable }
|