235 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			LLVM
		
	
	
	
			
		
		
	
	
			235 lines
		
	
	
		
			8.4 KiB
		
	
	
	
		
			LLVM
		
	
	
	
| ; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
 | |
| ; RUN: llc -mtriple=i686-- -verify-machineinstrs < %s | FileCheck %s
 | |
| 
 | |
| ; A test for asm-goto output
 | |
| 
 | |
| define i32 @test1(i32 %x) {
 | |
| ; CHECK-LABEL: test1:
 | |
| ; CHECK:       # %bb.0: # %entry
 | |
| ; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %eax
 | |
| ; CHECK-NEXT:    addl $4, %eax
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    xorl %eax, %eax
 | |
| ; CHECK-NEXT:    jmp .Ltmp0
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  # %bb.1: # %normal
 | |
| ; CHECK-NEXT:    retl
 | |
| ; CHECK-NEXT:  .Ltmp0: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB0_2: # %abnormal
 | |
| ; CHECK-NEXT:    movl $1, %eax
 | |
| ; CHECK-NEXT:    retl
 | |
| entry:
 | |
|   %add = add nsw i32 %x, 4
 | |
|   %ret = callbr i32 asm "xorl $1, $0; jmp ${2:l}", "=r,r,i,~{dirflag},~{fpsr},~{flags}"(i32 %add, i8* blockaddress(@test1, %abnormal))
 | |
|           to label %normal [label %abnormal]
 | |
| 
 | |
| normal:
 | |
|   ret i32 %ret
 | |
| 
 | |
| abnormal:
 | |
|   ret i32 1
 | |
| }
 | |
| 
 | |
| define i32 @test2(i32 %out1, i32 %out2) {
 | |
| ; CHECK-LABEL: test2:
 | |
| ; CHECK:       # %bb.0: # %entry
 | |
| ; CHECK-NEXT:    pushl %edi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 8
 | |
| ; CHECK-NEXT:    pushl %esi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 12
 | |
| ; CHECK-NEXT:    .cfi_offset %esi, -12
 | |
| ; CHECK-NEXT:    .cfi_offset %edi, -8
 | |
| ; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %edi
 | |
| ; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %esi
 | |
| ; CHECK-NEXT:    movl $-1, %eax
 | |
| ; CHECK-NEXT:    cmpl %edi, %esi
 | |
| ; CHECK-NEXT:    jge .LBB1_2
 | |
| ; CHECK-NEXT:  # %bb.1: # %if.then
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    testl %esi, %esi
 | |
| ; CHECK-NEXT:    testl %edi, %esi
 | |
| ; CHECK-NEXT:    jne .Ltmp1
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:    jmp .LBB1_3
 | |
| ; CHECK-NEXT:  .LBB1_2: # %if.else
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    testl %esi, %edi
 | |
| ; CHECK-NEXT:    testl %esi, %edi
 | |
| ; CHECK-NEXT:    jne .Ltmp2
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  .LBB1_3:
 | |
| ; CHECK-NEXT:    movl %esi, %eax
 | |
| ; CHECK-NEXT:    addl %edi, %eax
 | |
| ; CHECK-NEXT:  .Ltmp2: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB1_5: # %return
 | |
| ; CHECK-NEXT:    popl %esi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 8
 | |
| ; CHECK-NEXT:    popl %edi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 4
 | |
| ; CHECK-NEXT:    retl
 | |
| ; CHECK-NEXT:  .Ltmp1: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB1_4: # %label_true
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 12
 | |
| ; CHECK-NEXT:    movl $-2, %eax
 | |
| ; CHECK-NEXT:    jmp .LBB1_5
 | |
| entry:
 | |
|   %cmp = icmp slt i32 %out1, %out2
 | |
|   br i1 %cmp, label %if.then, label %if.else
 | |
| 
 | |
| if.then:                                          ; preds = %entry
 | |
|   %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "={si},={di},r,i,i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i8* blockaddress(@test2, %label_true), i8* blockaddress(@test2, %return), i32 %out1, i32 %out2)
 | |
|           to label %if.end [label %label_true, label %return]
 | |
| 
 | |
| if.else:                                          ; preds = %entry
 | |
|   %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "={si},={di},r,r,i,i,0,1,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i32 %out2, i8* blockaddress(@test2, %label_true), i8* blockaddress(@test2, %return), i32 %out1, i32 %out2)
 | |
|           to label %if.end [label %label_true, label %return]
 | |
| 
 | |
| if.end:                                           ; preds = %if.else, %if.then
 | |
|   %.sink11 = phi { i32, i32 } [ %0, %if.then ], [ %1, %if.else ]
 | |
|   %asmresult3 = extractvalue { i32, i32 } %.sink11, 0
 | |
|   %asmresult4 = extractvalue { i32, i32 } %.sink11, 1
 | |
|   %add = add nsw i32 %asmresult4, %asmresult3
 | |
|   br label %return
 | |
| 
 | |
| label_true:                                       ; preds = %if.else, %if.then
 | |
|   br label %return
 | |
| 
 | |
| return:                                           ; preds = %if.then, %if.else, %label_true, %if.end
 | |
|   %retval.0 = phi i32 [ %add, %if.end ], [ -2, %label_true ], [ -1, %if.else ], [ -1, %if.then ]
 | |
|   ret i32 %retval.0
 | |
| }
 | |
| 
 | |
| define i32 @test3(i1 %cmp) {
 | |
| ; CHECK-LABEL: test3:
 | |
| ; CHECK:       # %bb.0: # %entry
 | |
| ; CHECK-NEXT:    pushl %edi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 8
 | |
| ; CHECK-NEXT:    pushl %esi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 12
 | |
| ; CHECK-NEXT:    .cfi_offset %esi, -12
 | |
| ; CHECK-NEXT:    .cfi_offset %edi, -8
 | |
| ; CHECK-NEXT:    testb $1, {{[0-9]+}}(%esp)
 | |
| ; CHECK-NEXT:    je .LBB2_3
 | |
| ; CHECK-NEXT:  # %bb.1: # %true
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    .short %esi
 | |
| ; CHECK-NEXT:    .short %edi
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  # %bb.2:
 | |
| ; CHECK-NEXT:    movl %edi, %eax
 | |
| ; CHECK-NEXT:    jmp .LBB2_5
 | |
| ; CHECK-NEXT:  .LBB2_3: # %false
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    .short %eax
 | |
| ; CHECK-NEXT:    .short %edx
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  # %bb.4:
 | |
| ; CHECK-NEXT:    movl %edx, %eax
 | |
| ; CHECK-NEXT:  .LBB2_5: # %asm.fallthrough
 | |
| ; CHECK-NEXT:    popl %esi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 8
 | |
| ; CHECK-NEXT:    popl %edi
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 4
 | |
| ; CHECK-NEXT:    retl
 | |
| ; CHECK-NEXT:  .Ltmp3: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB2_6: # %indirect
 | |
| ; CHECK-NEXT:    .cfi_def_cfa_offset 12
 | |
| ; CHECK-NEXT:    movl $42, %eax
 | |
| ; CHECK-NEXT:    jmp .LBB2_5
 | |
| entry:
 | |
|   br i1 %cmp, label %true, label %false
 | |
| 
 | |
| true:
 | |
|   %0 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={si},={di},i" (i8* blockaddress(@test3, %indirect)) to label %asm.fallthrough [label %indirect]
 | |
| 
 | |
| false:
 | |
|   %1 = callbr { i32, i32 } asm sideeffect ".word $0, $1", "={ax},={dx},i" (i8* blockaddress(@test3, %indirect)) to label %asm.fallthrough [label %indirect]
 | |
| 
 | |
| asm.fallthrough:
 | |
|   %vals = phi { i32, i32 } [ %0, %true ], [ %1, %false ]
 | |
|   %v = extractvalue { i32, i32 } %vals, 1
 | |
|   ret i32 %v
 | |
| 
 | |
| indirect:
 | |
|   ret i32 42
 | |
| }
 | |
| 
 | |
| ; Test 4 - asm-goto with output constraints.
 | |
| define i32 @test4(i32 %out1, i32 %out2) {
 | |
| ; CHECK-LABEL: test4:
 | |
| ; CHECK:       # %bb.0: # %entry
 | |
| ; CHECK-NEXT:    movl $-1, %eax
 | |
| ; CHECK-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    testl %ecx, %ecx
 | |
| ; CHECK-NEXT:    testl %edx, %ecx
 | |
| ; CHECK-NEXT:    jne .Ltmp4
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  # %bb.1: # %asm.fallthrough
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    testl %ecx, %edx
 | |
| ; CHECK-NEXT:    testl %ecx, %edx
 | |
| ; CHECK-NEXT:    jne .Ltmp5
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  # %bb.2: # %asm.fallthrough2
 | |
| ; CHECK-NEXT:    addl %edx, %ecx
 | |
| ; CHECK-NEXT:    movl %ecx, %eax
 | |
| ; CHECK-NEXT:    retl
 | |
| ; CHECK-NEXT:  .Ltmp4: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB3_3: # %label_true
 | |
| ; CHECK-NEXT:    movl $-2, %eax
 | |
| ; CHECK-NEXT:  .Ltmp5: # Block address taken
 | |
| ; CHECK-NEXT:  .LBB3_4: # %return
 | |
| ; CHECK-NEXT:    retl
 | |
| entry:
 | |
|   %0 = callbr { i32, i32 } asm sideeffect "testl $0, $0; testl $1, $2; jne ${3:l}", "=r,=r,r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %out1, i8* blockaddress(@test4, %label_true), i8* blockaddress(@test4, %return))
 | |
|           to label %asm.fallthrough [label %label_true, label %return]
 | |
| 
 | |
| asm.fallthrough:                                  ; preds = %entry
 | |
|   %asmresult = extractvalue { i32, i32 } %0, 0
 | |
|   %asmresult1 = extractvalue { i32, i32 } %0, 1
 | |
|   %1 = callbr { i32, i32 } asm sideeffect "testl $0, $1; testl $2, $3; jne ${5:l}", "=r,=r,r,r,i,i,~{dirflag},~{fpsr},~{flags}"(i32 %asmresult, i32 %asmresult1, i8* blockaddress(@test4, %label_true), i8* blockaddress(@test4, %return))
 | |
|           to label %asm.fallthrough2 [label %label_true, label %return]
 | |
| 
 | |
| asm.fallthrough2:                                 ; preds = %asm.fallthrough
 | |
|   %asmresult3 = extractvalue { i32, i32 } %1, 0
 | |
|   %asmresult4 = extractvalue { i32, i32 } %1, 1
 | |
|   %add = add nsw i32 %asmresult3, %asmresult4
 | |
|   br label %return
 | |
| 
 | |
| label_true:                                       ; preds = %asm.fallthrough, %entry
 | |
|   br label %return
 | |
| 
 | |
| return:                                           ; preds = %entry, %asm.fallthrough, %label_true, %asm.fallthrough2
 | |
|   %retval.0 = phi i32 [ %add, %asm.fallthrough2 ], [ -2, %label_true ], [ -1, %asm.fallthrough ], [ -1, %entry ]
 | |
|   ret i32 %retval.0
 | |
| }
 | |
| 
 | |
| ; Test5 - test that we don't rely on a positional constraint. ie. +r in
 | |
| ; GCCAsmStmt being turned into "={esp},0" since after D87279 they're turned
 | |
| ; into "={esp},{esp}". This previously caused an ICE; this test is more so
 | |
| ; about avoiding another ICE than what the actual output is.
 | |
| define dso_local void @test5() {
 | |
| ; CHECK-LABEL: test5:
 | |
| ; CHECK:       # %bb.0:
 | |
| ; CHECK-NEXT:    #APP
 | |
| ; CHECK-NEXT:    #NO_APP
 | |
| ; CHECK-NEXT:  .Ltmp6: # Block address taken
 | |
| ; CHECK-NEXT:  # %bb.1:
 | |
| ; CHECK-NEXT:    retl
 | |
|   %1 = call i32 @llvm.read_register.i32(metadata !3)
 | |
|   %2 = callbr i32 asm "", "={esp},X,{esp},~{dirflag},~{fpsr},~{flags}"(i8* blockaddress(@test5, %4), i32 %1)
 | |
|           to label %3 [label %4]
 | |
| 
 | |
| 3:
 | |
|   call void @llvm.write_register.i32(metadata !3, i32 %2)
 | |
|   br label %4
 | |
| 
 | |
| 4:
 | |
|   ret void
 | |
| }
 | |
| 
 | |
| declare i32 @llvm.read_register.i32(metadata)
 | |
| declare void @llvm.write_register.i32(metadata, i32)
 | |
| !3 = !{!"esp"}
 |