1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131
|
// REQUIRES: x86-registered-target
// RUN: %clang_cc1 -no-opaque-pointers -triple x86_64-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s
// RUN: %clang_cc1 -no-opaque-pointers -triple i386-pc-linux-gnu -O0 -emit-llvm %s -o - | FileCheck %s
int test1(int cond) {
// CHECK-LABEL: define{{.*}} i32 @test1(
// CHECK: callbr void asm sideeffect
// CHECK: to label %asm.fallthrough [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough:
asm volatile goto("testl %0, %0; jne %l1;" :: "r"(cond)::label_true, loop);
asm volatile goto("testl %0, %0; jne %l2;" :: "r"(cond)::label_true, loop);
// CHECK: callbr void asm sideeffect
// CHECK: to label %asm.fallthrough1 [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough1:
return 0;
loop:
return 0;
label_true:
return 1;
}
int test2(int cond) {
// CHECK-LABEL: define{{.*}} i32 @test2(
// CHECK: callbr i32 asm sideeffect
// CHECK: to label %asm.fallthrough [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough:
asm volatile goto("testl %0, %0; jne %l2;" : "=r"(cond) : "r"(cond) :: label_true, loop);
asm volatile goto("testl %0, %0; jne %l3;" : "=r"(cond) : "r"(cond) :: label_true, loop);
// CHECK: callbr i32 asm sideeffect
// CHECK: to label %asm.fallthrough1 [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough1:
return 0;
loop:
return 0;
label_true:
return 1;
}
int test3(int out1, int out2) {
// CHECK-LABEL: define{{.*}} i32 @test3(
// CHECK: callbr { i32, i32 } asm sideeffect
// CHECK: to label %asm.fallthrough [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough:
asm volatile goto("testl %0, %0; jne %l3;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop);
asm volatile goto("testl %0, %0; jne %l4;" : "=r"(out1), "=r"(out2) : "r"(out1) :: label_true, loop);
// CHECK: callbr { i32, i32 } asm sideeffect
// CHECK: to label %asm.fallthrough2 [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough2:
return 0;
loop:
return 0;
label_true:
return 1;
}
int test4(int out1, int out2) {
// CHECK-LABEL: define{{.*}} i32 @test4(
// CHECK: callbr { i32, i32 } asm sideeffect "jne ${5:l}", "={si},={di},r,0,1,!i,!i
// CHECK: to label %asm.fallthrough [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough:
if (out1 < out2)
asm volatile goto("jne %l5" : "+S"(out1), "+D"(out2) : "r"(out1) :: label_true, loop);
else
asm volatile goto("jne %l7" : "+S"(out1), "+D"(out2) : "r"(out1), "r"(out2) :: label_true, loop);
// CHECK: callbr { i32, i32 } asm sideeffect "jne ${7:l}", "={si},={di},r,r,0,1,!i,!i
// CHECK: to label %asm.fallthrough2 [label %label_true, label %loop]
// CHECK-LABEL: asm.fallthrough2:
return out1 + out2;
loop:
return -1;
label_true:
return -2;
}
int test5(int addr, int size, int limit) {
// CHECK-LABEL: define{{.*}} i32 @test5(
// CHECK: callbr i32 asm "add $1,$0 ; jc ${4:l} ; cmp $2,$0 ; ja ${4:l} ; ", "=r,imr,imr,0,!i
// CHECK: to label %asm.fallthrough [label %t_err]
// CHECK-LABEL: asm.fallthrough:
asm goto(
"add %1,%0 ; "
"jc %l[t_err] ; "
"cmp %2,%0 ; "
"ja %l[t_err] ; "
: "+r" (addr)
: "g" (size), "g" (limit)
: : t_err);
return 0;
t_err:
return 1;
}
int test6(int out1) {
// CHECK-LABEL: define{{.*}} i32 @test6(
// CHECK: callbr i32 asm sideeffect "testl $0, $0; testl $1, $1; jne ${3:l}", "={si},r,0,!i,!i,{{.*}}
// CHECK: to label %asm.fallthrough [label %label_true, label %landing]
// CHECK-LABEL: asm.fallthrough:
// CHECK-LABEL: landing:
int out2 = 42;
asm volatile goto("testl %0, %0; testl %1, %1; jne %l3" : "+S"(out2) : "r"(out1) :: label_true, landing);
landing:
return out1 + out2;
label_true:
return -2;
}
// test7 - For the output templates in the asm string (%0, %l2), GCC places
// hidden inputs tied to outputs ("+r" constraint) BEFORE labels. Test that foo
// is $2 (or rather ${2:l} because of the l output template) in the emitted asm
// string, not $1.
void *test7(void) {
// CHECK-LABEL: define{{.*}} i8* @test7(
// CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(i8* %0)
// CHECK-NEXT: to label %asm.fallthrough [label %foo]
void *p = &&foo;
asm goto ("# %0\n\t# %l2":"+r"(p):::foo);
foo:
return p;
}
// test8 - the same as test7, but this time we use symbolic names rather than
// numbered outputs.
void *test8(void) {
// CHECK-LABEL: define{{.*}} i8* @test8(
// CHECK: %1 = callbr i8* asm "# $0\0A\09# ${2:l}", "=r,0,!i,~{dirflag},~{fpsr},~{flags}"(i8* %0)
// CHECK-NEXT: to label %asm.fallthrough [label %foo]
void *p = &&foo;
asm goto ("# %0\n\t# %l[foo]":"+r"(p):::foo);
foo:
return p;
}
|