// RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -DSTRUCT -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-STRUCT // RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -USTRUCT -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-NOSTRUCT // RUN: not %clang_cc1 -triple=x86_64-unknown-linux-gnu -DIMPOSSIBLE_ODD -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-IMPOSSIBLE_ODD // RUN: not %clang_cc1 -triple=x86_64-unknown-linux-gnu -DIMPOSSIBLE_BIG -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-IMPOSSIBLE_BIG // RUN: %clang_cc1 -triple=x86_64-unknown-linux-gnu -DPOSSIBLE_X -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-X // RUN: not %clang_cc1 -triple=x86_64-unknown-linux-gnu -DIMPOSSIBLE_X -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-IMPOSSIBLE_X // RUN: not %clang_cc1 -triple=x86_64-unknown-linux-gnu -DIMPOSSIBLE_9BYTES -emit-llvm %s -o - 2>&1 | FileCheck %s --check-prefix=CHECK-IMPOSSIBLE_9BYTES // Make sure Clang doesn't treat |lockval| as asm input. void _raw_spin_lock(void) { #ifdef STRUCT struct { unsigned short owner, next; } lockval; lockval.owner = 1; lockval.next = 2; #else int lockval; lockval = 3; #endif asm("nop" : "=r"(lockval)); } // CHECK-LABEL: _raw_spin_lock // CHECK-LABEL: entry: // CHECK-STRUCT: %lockval = alloca %struct.anon, align 2 // CHECK-STRUCT: store i16 1 // CHECK-STRUCT: store i16 2 // CHECK-STRUCT: [[RES:%[0-9]+]] = call i32 asm "nop", "=r,~{dirflag},~{fpsr},~{flags}"() // CHECK-STRUCT: [[CAST:%[0-9]+]] = bitcast %struct.anon* %lockval to i32* // CHECK-STRUCT: store i32 [[RES]], i32* [[CAST]], align 2 // CHECK-NOSTRUCT: %lockval = alloca i32, align 4 // CHECK-NOSTRUCT: store i32 3 // CHECK-NOSTRUCT: [[RES:%[0-9]+]] = call i32 asm "nop", "=r,~{dirflag},~{fpsr},~{flags}"() // CHECK-NOSTRUCT: store i32 [[RES]], i32* %lockval, align 4 // Check Clang correctly handles a structure with padding. void unusual_struct(void) { struct { unsigned short first; unsigned char second; } str; asm("nop" : "=r"(str)); } // Check Clang reports an error if attempting to return a structure for which // no direct conversion to a register is possible. void odd_struct(void) { #ifdef IMPOSSIBLE_ODD struct __attribute__((__packed__)) { unsigned short first; unsigned char second; } str; asm("nop" : "=r"(str)); #endif } // CHECK-IMPOSSIBLE_ODD: impossible constraint in asm: can't store value into a register // Check Clang reports an error if attempting to return a big structure via a register. void big_struct(void) { #ifdef IMPOSSIBLE_BIG struct { long long int v1, v2, v3, v4; } str; asm("nop" : "=r"(str)); #endif } // CHECK-IMPOSSIBLE_BIG: impossible constraint in asm: can't store value into a register // Clang is able to emit LLVM IR for an 16-byte structure. void x_constraint_fit() { #ifdef POSSIBLE_X struct S { unsigned x[4]; } z; asm volatile("nop" : "=x"(z)); #endif } // CHECK-LABEL: x_constraint_fit // CHECK-X: %z = alloca %struct.S, align 4 // CHECK-X: [[RES:%[0-9]+]] = call i128 asm sideeffect "nop", "=x,~{dirflag},~{fpsr},~{flags}"() // CHECK-X: [[CAST:%[0-9]+]] = bitcast %struct.S* %z to i128* // CHECK-X: store i128 [[RES]], i128* [[CAST]], align 4 // CHECK-X: ret // Clang is unable to emit LLVM IR for a 32-byte structure. void x_constraint_nofit() { #ifdef IMPOSSIBLE_X struct S { unsigned x[8]; } z; asm volatile("nop" : "=x"(z)); #endif } // CHECK-IMPOSSIBLE_X: invalid output size for constraint // http://crbug.com/999160 // Clang used to report the following message: // "impossible constraint in asm: can't store struct into a register" // for the assembly directive below, although there's no struct. void crbug_999160_regtest() { #ifdef IMPOSSIBLE_9BYTES char buf[9]; asm("" : "=r"(buf)); #endif } // CHECK-IMPOSSIBLE_9BYTES: impossible constraint in asm: can't store value into a register