1*9880d681SAndroid Build Coastguard Worker; RUN: llc -mtriple=armv7-none-eabi -mattr=+neon < %s -o - | FileCheck %s 2*9880d681SAndroid Build Coastguard Worker 3*9880d681SAndroid Build Coastguard Worker; The following functions test the use case where an X constraint is used to 4*9880d681SAndroid Build Coastguard Worker; add a dependency between an assembly instruction (vmsr in this case) and 5*9880d681SAndroid Build Coastguard Worker; another instruction. In each function, we use a different type for the 6*9880d681SAndroid Build Coastguard Worker; X constraint argument. 7*9880d681SAndroid Build Coastguard Worker; 8*9880d681SAndroid Build Coastguard Worker; We can something similar from the following C code: 9*9880d681SAndroid Build Coastguard Worker; double f1(double f, int pscr_value) { 10*9880d681SAndroid Build Coastguard Worker; asm volatile("vmsr fpscr,%0" : "=X" ((f)): "r" (pscr_value)); 11*9880d681SAndroid Build Coastguard Worker; return f+f; 12*9880d681SAndroid Build Coastguard Worker; } 13*9880d681SAndroid Build Coastguard Worker 14*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f1 15*9880d681SAndroid Build Coastguard Worker; CHECK: vmsr fpscr 16*9880d681SAndroid Build Coastguard Worker; CHECK: vadd.f64 17*9880d681SAndroid Build Coastguard Worker 18*9880d681SAndroid Build Coastguard Workerdefine arm_aapcs_vfpcc double @f1(double %f, i32 %pscr_value) { 19*9880d681SAndroid Build Coastguard Workerentry: 20*9880d681SAndroid Build Coastguard Worker %f.addr = alloca double, align 8 21*9880d681SAndroid Build Coastguard Worker store double %f, double* %f.addr, align 8 22*9880d681SAndroid Build Coastguard Worker call void asm sideeffect "vmsr fpscr,$1", "=*X,r"(double* nonnull %f.addr, i32 %pscr_value) nounwind 23*9880d681SAndroid Build Coastguard Worker %0 = load double, double* %f.addr, align 8 24*9880d681SAndroid Build Coastguard Worker %add = fadd double %0, %0 25*9880d681SAndroid Build Coastguard Worker ret double %add 26*9880d681SAndroid Build Coastguard Worker} 27*9880d681SAndroid Build Coastguard Worker 28*9880d681SAndroid Build Coastguard Worker; int f2(int f, int pscr_value) { 29*9880d681SAndroid Build Coastguard Worker; asm volatile("vmsr fpscr,%0" : "=X" ((f)): "r" (pscr_value)); 30*9880d681SAndroid Build Coastguard Worker; return f+f; 31*9880d681SAndroid Build Coastguard Worker; } 32*9880d681SAndroid Build Coastguard Worker 33*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f2 34*9880d681SAndroid Build Coastguard Worker; CHECK: vmsr fpscr 35*9880d681SAndroid Build Coastguard Worker; CHECK: mul 36*9880d681SAndroid Build Coastguard Workerdefine arm_aapcs_vfpcc i32 @f2(i32 %f, i32 %pscr_value) { 37*9880d681SAndroid Build Coastguard Workerentry: 38*9880d681SAndroid Build Coastguard Worker %f.addr = alloca i32, align 4 39*9880d681SAndroid Build Coastguard Worker store i32 %f, i32* %f.addr, align 4 40*9880d681SAndroid Build Coastguard Worker call void asm sideeffect "vmsr fpscr,$1", "=*X,r"(i32* nonnull %f.addr, i32 %pscr_value) nounwind 41*9880d681SAndroid Build Coastguard Worker %0 = load i32, i32* %f.addr, align 4 42*9880d681SAndroid Build Coastguard Worker %mul = mul i32 %0, %0 43*9880d681SAndroid Build Coastguard Worker ret i32 %mul 44*9880d681SAndroid Build Coastguard Worker} 45*9880d681SAndroid Build Coastguard Worker 46*9880d681SAndroid Build Coastguard Worker 47*9880d681SAndroid Build Coastguard Worker; int f3(int f, int pscr_value) { 48*9880d681SAndroid Build Coastguard Worker; asm volatile("vmsr fpscr,%0" : "=X" ((f)): "r" (pscr_value)); 49*9880d681SAndroid Build Coastguard Worker; return f+f; 50*9880d681SAndroid Build Coastguard Worker; } 51*9880d681SAndroid Build Coastguard Worker 52*9880d681SAndroid Build Coastguard Worker; typedef signed char int8_t; 53*9880d681SAndroid Build Coastguard Worker; typedef __attribute__((neon_vector_type(8))) int8_t int8x8_t; 54*9880d681SAndroid Build Coastguard Worker; void f3 (void) 55*9880d681SAndroid Build Coastguard Worker; { 56*9880d681SAndroid Build Coastguard Worker; int8x8_t vector_res_int8x8; 57*9880d681SAndroid Build Coastguard Worker; unsigned int fpscr; 58*9880d681SAndroid Build Coastguard Worker; asm volatile ("vmsr fpscr,%1" : "=X" ((vector_res_int8x8)) : "r" (fpscr)); 59*9880d681SAndroid Build Coastguard Worker; return vector_res_int8x8 * vector_res_int8x8; 60*9880d681SAndroid Build Coastguard Worker; } 61*9880d681SAndroid Build Coastguard Worker 62*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f3 63*9880d681SAndroid Build Coastguard Worker; CHECK: vmsr fpscr 64*9880d681SAndroid Build Coastguard Worker; CHECK: vmul.i8 65*9880d681SAndroid Build Coastguard Workerdefine arm_aapcs_vfpcc <8 x i8> @f3() { 66*9880d681SAndroid Build Coastguard Workerentry: 67*9880d681SAndroid Build Coastguard Worker %vector_res_int8x8 = alloca <8 x i8>, align 8 68*9880d681SAndroid Build Coastguard Worker %0 = getelementptr inbounds <8 x i8>, <8 x i8>* %vector_res_int8x8, i32 0, i32 0 69*9880d681SAndroid Build Coastguard Worker call void asm sideeffect "vmsr fpscr,$1", "=*X,r"(<8 x i8>* nonnull %vector_res_int8x8, i32 undef) nounwind 70*9880d681SAndroid Build Coastguard Worker %1 = load <8 x i8>, <8 x i8>* %vector_res_int8x8, align 8 71*9880d681SAndroid Build Coastguard Worker %mul = mul <8 x i8> %1, %1 72*9880d681SAndroid Build Coastguard Worker ret <8 x i8> %mul 73*9880d681SAndroid Build Coastguard Worker} 74*9880d681SAndroid Build Coastguard Worker 75*9880d681SAndroid Build Coastguard Worker; We can emit integer constants. 76*9880d681SAndroid Build Coastguard Worker; We can get this from: 77*9880d681SAndroid Build Coastguard Worker; void f() { 78*9880d681SAndroid Build Coastguard Worker; int x = 2; 79*9880d681SAndroid Build Coastguard Worker; asm volatile ("add r0, r0, %0" : : "X" (x)); 80*9880d681SAndroid Build Coastguard Worker; } 81*9880d681SAndroid Build Coastguard Worker; 82*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f4 83*9880d681SAndroid Build Coastguard Worker; CHECK: add r0, r0, #2 84*9880d681SAndroid Build Coastguard Workerdefine void @f4() { 85*9880d681SAndroid Build Coastguard Workerentry: 86*9880d681SAndroid Build Coastguard Worker tail call void asm sideeffect "add r0, r0, $0", "X"(i32 2) 87*9880d681SAndroid Build Coastguard Worker ret void 88*9880d681SAndroid Build Coastguard Worker} 89*9880d681SAndroid Build Coastguard Worker 90*9880d681SAndroid Build Coastguard Worker; We can emit function labels. This is equivalent to the following C code: 91*9880d681SAndroid Build Coastguard Worker; void f(void) { 92*9880d681SAndroid Build Coastguard Worker; void (*x)(void) = &foo; 93*9880d681SAndroid Build Coastguard Worker; asm volatile ("bl %0" : : "X" (x)); 94*9880d681SAndroid Build Coastguard Worker; } 95*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f5 96*9880d681SAndroid Build Coastguard Worker; CHECK: bl f4 97*9880d681SAndroid Build Coastguard Workerdefine void @f5() { 98*9880d681SAndroid Build Coastguard Workerentry: 99*9880d681SAndroid Build Coastguard Worker tail call void asm sideeffect "bl $0", "X"(void ()* nonnull @f4) 100*9880d681SAndroid Build Coastguard Worker ret void 101*9880d681SAndroid Build Coastguard Worker} 102*9880d681SAndroid Build Coastguard Worker 103*9880d681SAndroid Build Coastguard Workerdeclare void @foo(...) 104*9880d681SAndroid Build Coastguard Worker 105*9880d681SAndroid Build Coastguard Worker; This tests the behavior of the X constraint when used on functions pointers, 106*9880d681SAndroid Build Coastguard Worker; or functions with a cast. In the first asm call we figure out that this 107*9880d681SAndroid Build Coastguard Worker; is a function pointer and emit the label. However, in the second asm call 108*9880d681SAndroid Build Coastguard Worker; we can't see through the bitcast and we end up having to lower this constraint 109*9880d681SAndroid Build Coastguard Worker; to something else. This is not ideal, but it is a correct behaviour according 110*9880d681SAndroid Build Coastguard Worker; to the definition of the X constraint. 111*9880d681SAndroid Build Coastguard Worker; 112*9880d681SAndroid Build Coastguard Worker; In this case (and other cases where we could have emitted something else), 113*9880d681SAndroid Build Coastguard Worker; what we're doing with the X constraint is not particularly useful either, 114*9880d681SAndroid Build Coastguard Worker; since the user could have used "r" in this situation for the same effect. 115*9880d681SAndroid Build Coastguard Worker 116*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f6 117*9880d681SAndroid Build Coastguard Worker; CHECK: bl foo 118*9880d681SAndroid Build Coastguard Worker; CHECK: bl r 119*9880d681SAndroid Build Coastguard Worker 120*9880d681SAndroid Build Coastguard Workerdefine void @f6() nounwind { 121*9880d681SAndroid Build Coastguard Workerentry: 122*9880d681SAndroid Build Coastguard Worker tail call void asm sideeffect "bl $0", "X"(void (...)* @foo) nounwind 123*9880d681SAndroid Build Coastguard Worker tail call void asm sideeffect "bl $0", "X"(void (...)* bitcast (void ()* @f4 to void (...)*)) nounwind 124*9880d681SAndroid Build Coastguard Worker ret void 125*9880d681SAndroid Build Coastguard Worker} 126*9880d681SAndroid Build Coastguard Worker 127*9880d681SAndroid Build Coastguard Worker; The following IR can be generated from C code with a function like: 128*9880d681SAndroid Build Coastguard Worker; void a() { 129*9880d681SAndroid Build Coastguard Worker; void* a = &&A; 130*9880d681SAndroid Build Coastguard Worker; asm volatile ("bl %0" : : "X" (a)); 131*9880d681SAndroid Build Coastguard Worker; A: 132*9880d681SAndroid Build Coastguard Worker; return; 133*9880d681SAndroid Build Coastguard Worker; } 134*9880d681SAndroid Build Coastguard Worker; 135*9880d681SAndroid Build Coastguard Worker; Ideally this would give the block address of bb, but it requires us to see 136*9880d681SAndroid Build Coastguard Worker; through blockaddress, which we can't do at the moment. This might break some 137*9880d681SAndroid Build Coastguard Worker; existing use cases where a user would expect to get a block label and instead 138*9880d681SAndroid Build Coastguard Worker; gets the block address in a register. However, note that according to the 139*9880d681SAndroid Build Coastguard Worker; "no constraints" definition this behaviour is correct (although not very nice). 140*9880d681SAndroid Build Coastguard Worker 141*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f7 142*9880d681SAndroid Build Coastguard Worker; CHECK: bl 143*9880d681SAndroid Build Coastguard Workerdefine void @f7() { 144*9880d681SAndroid Build Coastguard Worker call void asm sideeffect "bl $0", "X"( i8* blockaddress(@f7, %bb) ) 145*9880d681SAndroid Build Coastguard Worker br label %bb 146*9880d681SAndroid Build Coastguard Workerbb: 147*9880d681SAndroid Build Coastguard Worker ret void 148*9880d681SAndroid Build Coastguard Worker} 149*9880d681SAndroid Build Coastguard Worker 150*9880d681SAndroid Build Coastguard Worker; If we use a constraint "=*X", we should get a store back to *%x (in r0). 151*9880d681SAndroid Build Coastguard Worker; CHECK-LABEL: f8 152*9880d681SAndroid Build Coastguard Worker; CHECK: str r{{.*}}, [r0] 153*9880d681SAndroid Build Coastguard Workerdefine void @f8(i32 *%x) { 154*9880d681SAndroid Build Coastguard Workerentry: 155*9880d681SAndroid Build Coastguard Worker tail call void asm sideeffect "add $0, r0, r0", "=*X"(i32 *%x) 156*9880d681SAndroid Build Coastguard Worker ret void 157*9880d681SAndroid Build Coastguard Worker} 158