blob: 0060d78a5ea325d949388dfea7b2633b49ef6395 [file] [edit]
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM,CIRLLVMONLY
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefixes=LLVM,LLVMONLY
__asm__ ("foo1");
__asm__ ("foo2");
__asm__ ("foo3");
// CIR: module{{.*}} cir.module_asm = ["foo1", "foo2", "foo3"]
// LLVM: module asm
// LLVM-NEXT: "foo1"
// LLVM-NEXT: "foo2"
// LLVM-NEXT: "foo3"
// CIR: cir.func{{.*}}@empty1
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@empty1
// LLVM: call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"()
void empty1() {
__asm__ volatile("" : : : );
}
// CIR: cir.func{{.*}}@empty2
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@empty2
// LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"()
void empty2() {
__asm__ volatile("nop" : : : );
}
// CIR: cir.func{{.*}}@empty3
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!s32i>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[X]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[X]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: {"" "=*m,*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@empty3
// LLVM: %[[X:.*]] = alloca i32
// LLVM: call void asm sideeffect "", "=*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[X]], ptr elementtype(i32) %[[X]])
void empty3(int x) {
__asm__ volatile("" : "+m"(x));
}
// CIR: cir.func{{.*}}@empty4
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!s32i>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[X]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@empty4
// LLVM: %[[X:.*]] = alloca i32
// LLVM: call void asm sideeffect "", "*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[X]])
void empty4(int x) {
__asm__ volatile("" : : "m"(x));
}
// CIR: cir.func{{.*}}@empty5
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!s32i>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[X]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "=*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@empty5
// LLVM: %[[X:.*]] = alloca i32
// LLVM: call void asm sideeffect "", "=*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[X]])
void empty5(int x) {
__asm__ volatile("" : "=m"(x));
}
// CIR: cir.func{{.*}}@empty6
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[X_LOAD:.*]] = cir.load align(4) %[[X]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[X_LOAD]] : !s32i],
// CIR-NEXT: {"" "=&r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !rec_anon_struct
// LLVM: define{{.*}}@empty6
// LLVM: %[[X:.*]] = alloca i32
// LLVM: %[[X_LOAD:.*]] = load i32, ptr %[[X]]
// LLVM: call { i32, i32 } asm sideeffect "", "=&r,=&r,1,~{dirflag},~{fpsr},~{flags}"(i32 %[[X_LOAD]])
//
void empty6(int x) {
__asm__ volatile("" : "=&r"(x), "+&r"(x));
}
// CIR: cir.func{{.*}}@add1
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[X_LOAD:.*]] = cir.load align(4) %[[X]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[X_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"addl $$42, $1" "=r,r,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR-NEXT: cir.store{{.*}} %[[ASM_RES]], %[[A]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@add1
// LLVM: %[[X:.*]] = alloca i32
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i32
// LLVM: %[[A:.*]] = alloca i32
// LLVM: %[[X_LOAD:.*]] = load i32, ptr %[[X]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "addl $$42, $1", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %[[X_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[A]]
unsigned add1(unsigned int x) {
int a;
__asm__("addl $42, %[val]"
: "=r" (a)
: [val] "r" (x)
);
return a;
}
// CIR: cir.func{{.*}}@add2
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[X_LOAD:.*]] = cir.load align(4) %[[X]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[X_LOAD]] : !u32i],
// CIR-NEXT: {"addl $$42, $0" "=r,0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[ASM_RES]], %[[X]] : !u32i, !cir.ptr<!u32i>
// LLVM: define{{.*}}@add2
// LLVM: %[[X:.*]] = alloca i32
// LLVM: %[[X_LOAD:.*]] = load i32, ptr %[[X]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "addl $$42, $0", "=r,0,~{dirflag},~{fpsr},~{flags}"(i32 %[[X_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[X]]
unsigned add2(unsigned int x) {
__asm__("addl $42, %[val]"
: [val] "+r" (x)
);
return x;
}
// CIR: cir.func{{.*}}@add3
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[X_LOAD:.*]] = cir.load{{.*}} %[[X]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[X_LOAD]] : !u32i],
// CIR-NEXT: {"addl $$42, $0 \0A\09 subl $$1, $0 \0A\09 imul $$2, $0" "=r,0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: cir.store{{.*}} %[[ASM_RES]], %[[X]] : !u32i, !cir.ptr<!u32i>
// LLVM: define{{.*}}@add3
// LLVM: %[[X:.*]] = alloca i32
// LLVM: %[[X_LOAD:.*]] = load i32, ptr %[[X]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "addl $$42, $0 \0A\09 subl $$1, $0 \0A\09 imul $$2, $0", "=r,0,~{dirflag},~{fpsr},~{flags}"(i32 %[[X_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[X]]
unsigned add3(unsigned int x) { // ((42 + x) - 1) * 2
__asm__("addl $42, %[val] \n\t\
subl $1, %[val] \n\t\
imul $2, %[val]"
: [val] "+r" (x)
);
return x;
}
// CIR: cir.func{{.*}}@add4
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!cir.ptr<!s32i>>
// CIR: %[[X_LOAD:.*]] = cir.load {{.*}} %[[X]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CIR-NEXT: cir.asm(x86_att,
// CIR-NEXT: out = [%[[X_LOAD]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"addl $$42, $0" "=*m,~{dirflag},~{fpsr},~{flags}"})
// CIR-NEXT: cir.return
// LLVM: define {{.*}}add4
// LLVM: %[[X:.*]] = alloca ptr
// LLVM: %[[X_LOAD:.*]] = load ptr, ptr %[[X]]
// LLVM: call void asm "addl $$42, $0", "=*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[X_LOAD]])
void add4(int *x) {
__asm__("addl $42, %[addr]" : [addr] "=m" (*x));
}
// CIR: cir.func{{.*}}@add5
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!cir.float>
// CIR: %[[Y:.*]] = cir.alloca "y" {{.*}} init : !cir.ptr<!cir.float>
// CIR: %[[R:.*]] = cir.alloca "r" {{.*}} : !cir.ptr<!cir.float>
// CIR: %[[X_LOAD:.*]] = cir.load{{.*}} %[[X]] : !cir.ptr<!cir.float>, !cir.float
// CIR: %[[Y_LOAD:.*]] = cir.load{{.*}} %[[Y]] : !cir.ptr<!cir.float>, !cir.float
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[X_LOAD]] : !cir.float, %[[Y_LOAD]] : !cir.float],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"flds $1; flds $2; faddp" "=&{st},imr,imr,~{dirflag},~{fpsr},~{flags}"}) -> !cir.float
// CIR-NEXT: cir.store{{.*}} %[[ASM_RES]], %[[R]] : !cir.float, !cir.ptr<!cir.float>
// LLVM: define{{.*}}@add5
// LLVM: %[[X:.*]] = alloca float
// LLVM: %[[Y:.*]] = alloca float
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca float
// LLVM: %[[R:.*]] = alloca float
// LLVM: %[[X_LOAD:.*]] = load float, ptr %[[X]]
// LLVM: %[[Y_LOAD:.*]] = load float, ptr %[[Y]]
// LLVM: %[[ASM_RES:.*]] = call float asm "flds $1; flds $2; faddp", "=&{st},imr,imr,~{dirflag},~{fpsr},~{flags}"(float %[[X_LOAD]], float %[[Y_LOAD]])
// LLVM: store float %[[ASM_RES]], ptr %[[R]]
float add5(float x, float y) {
float r;
__asm__("flds %[x]; flds %[y]; faddp"
: "=&t" (r)
: [x] "g" (x), [y] "g" (y));
return r;
}
// CIR: cir.func{{.*}}@mov
// CIR: %[[A:.*]] = cir.alloca "a" align(4) : !cir.ptr<!s32i>
// CIR: %[[RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"movl $$42, $0" "=r,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR: cir.store align(4) %[[RES]], %[[A]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@mov
// LLVM: call i32 asm "movl $$42, $0", "=r,~{dirflag},~{fpsr},~{flags}"()
unsigned mov(unsigned x) {
int a;
__asm__("movl $42, %0" : "=r" (a) : );
return a;
}
// CIR: cir.func{{.*}}@t1
// CIR: %[[LEN:.*]] = cir.alloca "len" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[ASM_STRUCT:.*]] = cir.alloca "__asm_result" {{.*}} : !cir.ptr<!rec_anon_struct>
// CIR: %[[LEN_LOAD:.*]] = cir.load align(4) %[[LEN]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[LEN_LOAD:.*]] : !s32i],
// CIR-NEXT: {"" "=&r,=&r,1,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !rec_anon_struct
// CIR-NEXT: cir.store align(1) %[[ASM_RES]], %[[ASM_STRUCT]]
// CIR-NEXT: %[[GET_MEM:.*]] = cir.get_member %[[ASM_STRUCT]][0] {name = ""} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!s32i>
// CIR-NEXT: cir.load align(1) %[[GET_MEM]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[GET_MEM:.*]] = cir.get_member %[[ASM_STRUCT]][1] {name = ""} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!s32i>
// CIR-NEXT: cir.load align(1) %[[GET_MEM]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store
// CIR-NEXT: cir.store
// CIR-NEXT: cir.return
// LLVM: define{{.*}}@t1
// LLVM: %[[LEN:.*]] = alloca i32
// LLVM: %[[LEN_LOAD:.*]] = load i32, ptr %[[LEN]]
// LLVM: call { i32, i32 } asm sideeffect "", "=&r,=&r,1,~{dirflag},~{fpsr},~{flags}"(i32 %[[LEN_LOAD]])
void t1(int len) {
__asm__ volatile("" : "=&r"(len), "+&r"(len));
}
// CIR: cir.func{{.*}}@t2
// CIR: %[[T:.*]] = cir.alloca "t" {{.*}} init : !cir.ptr<!u64i>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[T]] : !cir.ptr<!u64i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[T]] : !cir.ptr<!u64i> (maybe_memory)],
// CIR-NEXT: {"" "=*m,*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t2
// LLVM: %[[T:.*]] = alloca i64
// LLVM: call void asm sideeffect "", "=*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i64) %[[T]], ptr elementtype(i64) %[[T]])
void t2(unsigned long long t) {
__asm__ volatile("" : "+m"(t));
}
// CIR: cir.func{{.*}}@t3
// CIR: %[[SRC:.*]] = cir.alloca "src" {{.*}} init : !cir.ptr<!cir.ptr<!u8i>>
// CIR-NEXT: %[[TMP:.*]] = cir.alloca "temp" {{.*}} init : !cir.ptr<!u64i>
// CIR-NEXT: cir.store
// CIR-NEXT: cir.store
// CIR-NEXT: %[[SRC_LOAD:.*]] = cir.load align(8) %[[SRC]] : !cir.ptr<!cir.ptr<!u8i>>, !cir.ptr<!u8i>
// CIR-NEXT: cir.asm(x86_att,
// CIR-NEXT: out = [%[[TMP]] : !cir.ptr<!u64i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[TMP]] : !cir.ptr<!u64i> (maybe_memory), %[[SRC_LOAD]] : !cir.ptr<!u8i>],
// CIR-NEXT: {"" "=*m,=r,*m,1,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !cir.ptr<!u8i>
// LLVM: define{{.*}}@t3
// LLVM: %[[SRC_ADDR:.*]] = alloca ptr
// LLVM: %[[TMP:.*]] = alloca i64
// LLVM: %[[SRC:.*]] = load ptr, ptr %[[SRC_ADDR]]
// LLVM: call ptr asm sideeffect "", "=*m,=r,*m,1,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i64) %[[TMP]], ptr elementtype(i64) %[[TMP]], ptr %[[SRC]])
void t3(unsigned char *src, unsigned long long temp) {
__asm__ volatile("" : "+m"(temp), "+r"(src));
}
// CIR: cir.func{{.*}}@t4
// CIR: %[[A:.*]] = cir.alloca "a" align(8) : !cir.ptr<!u64i>
// CIR: %[[B:.*]] = cir.alloca "b" align(8) : !cir.ptr<!rec_reg>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[A]] : !cir.ptr<!u64i> (maybe_memory), %[[B]] : !cir.ptr<!rec_reg> (maybe_memory)],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "*m,*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t4
// LLVM: %[[A:.*]] = alloca i64
// LLVM: %[[B:.*]] = alloca %struct.reg
// LLVM: call void asm sideeffect "", "*m,*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i64) %[[A]], ptr elementtype(%struct.reg) %[[B]])
void t4(void) {
unsigned long long a;
struct reg { unsigned long long a, b; } b;
__asm__ volatile ("":: "m"(a), "m"(b));
}
// CIR: cir.func{{.*}}@t5
// CIR: %[[I:.*]] = cir.alloca "i" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[FUNC:.*]] = cir.get_global @t5 : !cir.ptr<!cir.func<(!s32i)>>
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[FUNC]] : !cir.ptr<!cir.func<(!s32i)>>],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"nop" "=r,0,~{dirflag},~{fpsr},~{flags}"}) -> !cir.ptr<!cir.func<(!s32i)>>
// CIR: %[[P_TO_I:.*]] = cir.cast ptr_to_int %[[ASM_RES]] : !cir.ptr<!cir.func<(!s32i)>> -> !u64i
// CIR: %[[INT_CAST:.*]] = cir.cast integral %[[P_TO_I]] : !u64i -> !s32i
// CIR: cir.store align(4) %[[INT_CAST]], %[[I]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t5
// LLVM: %[[I:.*]] = alloca i32
// LLVM: %[[ASM_RES:.*]] = call ptr asm "nop", "=r,0,~{dirflag},~{fpsr},~{flags}"(ptr @t5)
// LLVM: %[[ASM_RES_CAST:.*]] = ptrtoint ptr %[[ASM_RES]] to i64
// LLVM: %[[ASM_RES_TRUNC:.*]] = trunc i64 %[[ASM_RES_CAST]] to i32
// LLVM: store i32 %[[ASM_RES_TRUNC]], ptr %[[I]]
void t5(int i) {
asm("nop" : "=r"(i) : "0"(t5));
}
// CIR: cir.func{{.*}}@t6
// CIR: %[[FUNC:.*]] = cir.get_global @t6 : !cir.ptr<!cir.func<()>>
// CIR: cir.asm(x86_att,
// LLVM: define{{.*}}@t6
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[FUNC]] : !cir.ptr<!cir.func<()>>],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "i,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: call void asm sideeffect "", "i,~{dirflag},~{fpsr},~{flags}"(ptr @t6)
void t6(void) {
__asm__ volatile("" : : "i" (t6));
}
// CIR: cir.func{{.*}}@t7
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[A_LOAD:.*]] = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[FOUR]] : !s32i],
// CIR-NEXT: in_out = [%[[A_LOAD]] : !s32i],
// CIR-NEXT: {"T7 NAMED: $1" "=r,i,0,~{dirflag},~{fpsr},~{flags}"}) side_effects -> !s32i
// CIR: cir.store align(4) %[[ASM_RES]], %[[A]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t7
// LLVM: %[[A:.*]] = alloca i32
// LLVM: %[[A_LOAD:.*]] = load i32, ptr %[[A]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm sideeffect "T7 NAMED: $1", "=r,i,0,~{dirflag},~{fpsr},~{flags}"(i32 4, i32 %[[A_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[A]]
void t7(int a) {
__asm__ volatile("T7 NAMED: %[input]" : "+r"(a): [input] "i" (4));
}
// CIR: cir.func{{.*}}@t8
// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i
// CIR-NEXT: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[FOUR]] : !s32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"T8 NAMED MODIFIER: ${0:c}" "i,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t8
// LLVM: call void asm sideeffect "T8 NAMED MODIFIER: ${0:c}", "i,~{dirflag},~{fpsr},~{flags}"(i32 4)
void t8(void) {
__asm__ volatile("T8 NAMED MODIFIER: %c[input]" :: [input] "i" (4));
}
// CIR: cir.func{{.*}}@t9
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[A_LOAD:.*]] = cir.load align(4) %[[A]] : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[A_LOAD]] : !u32i],
// CIR-NEXT: {"bswap $0 $1" "=r,0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// LLVM: define{{.*}}@t9
// LLVM: %[[A_ADDR:.*]] = alloca i32
// LLVM: %[[A:.*]] = load i32, ptr %[[A_ADDR]]
// LLVM: call i32 asm "bswap $0 $1", "=r,0,~{dirflag},~{fpsr},~{flags}"(i32 %[[A]])
unsigned t9(unsigned int a) {
asm("bswap %0 %1" : "+r" (a));
return a;
}
// CIR: cir.func{{.*}}@t10
// CIR: %[[R:.*]] = cir.alloca "r" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[R_LOAD:.*]] = cir.load align(4) %[[R]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[ZERO1:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[ZERO2:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[ZERO3:.*]] = cir.const #cir.int<0> : !s32i
// CIR: %[[ZERO_3_CAST:.*]] = cir.cast int_to_float %[[ZERO3]] : !s32i -> !cir.double
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[ZERO1]] : !s32i, %[[ZERO2]] : !s32i, %[[ZERO_3_CAST]] : !cir.double],
// CIR-NEXT: in_out = [%[[R_LOAD]] : !s32i],
// CIR-NEXT: {"PR3908 $1 $3 $2 $0" "=r,mx,mr,x,0,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[R]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t10
// LLVM: %[[R:.*]] = alloca i32
// LLVM: %[[R_LOAD:.*]] = load i32, ptr %[[R]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "PR3908 $1 $3 $2 $0", "=r,mx,mr,x,0,~{dirflag},~{fpsr},~{flags}"(i32 0, i32 0, double 0{{.*}}, i32 %[[R_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[R]]
void t10(int r) {
__asm__("PR3908 %[lf] %[xx] %[li] %[r]" : [r] "+r" (r) : [lf] "mx" (0), [li] "mr" (0), [xx] "x" ((double)(0)));
}
// CIR: cir.func{{.*}}@t11
// CIR: %[[INPUT:.*]] = cir.alloca "input" {{.*}} init : !cir.ptr<!s8i>
// CIR: %[[OUTPUT:.*]] = cir.alloca "output" {{.*}} : !cir.ptr<!u32i>
// CIR: %[[INPUT_LOAD:.*]] = cir.load align(1) %[[INPUT]] : !cir.ptr<!s8i>, !s8i
// CIR: %[[INPUT_CAST:.*]] = cir.cast integral %[[INPUT_LOAD]] : !s8i -> !u32i
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[INPUT_CAST]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"xyz" "={ax},0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[OUTPUT]] : !u32i, !cir.ptr<!u32i>
// LLVM: define{{.*}}@t11
// LLVM: %[[INPUT:.*]] = alloca i8
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i32
// LLVM: %[[OUTPUT:.*]] = alloca i32
// LLVM: %[[INPUT_LOAD:.*]] = load i8, ptr %[[INPUT]]
// The two IR forms disagree as to whether this should be a zero or sign extend.
// It looks like this should be a 'sign' extend (sign->unsigned cast typically
// results in a sext), so this might be a bug in classic codegen.
// CIRLLVMONLY: %[[INPUT_EXT:.*]] = sext i8 %[[INPUT_LOAD]] to i32
// LLVMONLY: %[[INPUT_EXT:.*]] = zext i8 %[[INPUT_LOAD]] to i32
// LLVM: %[[ASM_RES:.*]] = call i32 asm "xyz", "={ax},0,~{dirflag},~{fpsr},~{flags}"(i32 %[[INPUT_EXT]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[OUTPUT]]
unsigned t11(signed char input) {
unsigned output;
__asm__("xyz"
: "=a" (output)
: "0" (input));
return output;
}
// CIR: cir.func{{.*}}@t12
// CIR: %[[INPUT:.*]] = cir.alloca "input" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[OUTPUT:.*]] = cir.alloca "output" {{.*}} : !cir.ptr<!u8i>
// CIR: %[[INPUT_LOAD:.*]] = cir.load align(4) %[[INPUT]] : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[INPUT_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"xyz" "={ax},0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: %[[ASM_RES_INT:.*]] = cir.cast integral %[[ASM_RES]] : !u32i -> !u8i
// CIR-NEXT: cir.store align(1) %[[ASM_RES_INT]], %[[OUTPUT]] : !u8i, !cir.ptr<!u8i>
// LLVM: define{{.*}}@t12
// LLVM: %[[INPUT:.*]] = alloca i32
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i8
// LLVM: %[[OUTPUT:.*]] = alloca i8
// LLVM: %[[INPUT_LOAD:.*]] = load i32, ptr %[[INPUT]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "xyz", "={ax},0,~{dirflag},~{fpsr},~{flags}"(i32 %[[INPUT_LOAD]])
// LLVM: %[[ASM_RES_TRUNC:.*]] = trunc i32 %[[ASM_RES]] to i8
// LLVM: store i8 %[[ASM_RES_TRUNC]], ptr %[[OUTPUT]]
unsigned char t12(unsigned input) {
unsigned char output;
__asm__("xyz"
: "=a" (output)
: "0" (input));
return output;
}
// CIR: cir.func{{.*}}@t13
// CIR: %[[INPUT:.*]] = cir.alloca "input" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[OUTPUT:.*]] = cir.alloca "output" {{.*}} : !cir.ptr<!u8i>
// CIR: %[[INPUT_LOAD:.*]] = cir.load align(4) %[[INPUT]] : !cir.ptr<!u32i>, !u32i
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[INPUT_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"xyz $1" "={ax},0,~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: %[[ASM_RES_INT:.*]] = cir.cast integral %[[ASM_RES]] : !u32i -> !u8i
// CIR-NEXT: cir.store align(1) %[[ASM_RES_INT]], %[[OUTPUT]] : !u8i, !cir.ptr<!u8i>
// LLVM: define{{.*}}@t13
// LLVM: %[[INPUT:.*]] = alloca i32
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i8
// LLVM: %[[OUTPUT:.*]] = alloca i8
// LLVM: %[[INPUT_LOAD:.*]] = load i32, ptr %[[INPUT]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "xyz $1", "={ax},0,~{dirflag},~{fpsr},~{flags}"(i32 %[[INPUT_LOAD]])
// LLVM: %[[ASM_RES_TRUNC:.*]] = trunc i32 %[[ASM_RES]] to i8
// LLVM: store i8 %[[ASM_RES_TRUNC]], ptr %[[OUTPUT]]
unsigned char t13(unsigned input) {
unsigned char output;
__asm__("xyz %1"
: "=a" (output)
: "0" (input));
return output;
}
// bitfield destination of an asm.
struct S {
int a : 4;
};
// CIR: cir.func{{.*}}@t14
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"abc $0" "=r,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// LLVM: define{{.*}}@t14
// LLVM: call i32 asm "abc $0", "=r,~{dirflag},~{fpsr},~{flags}"()
void t14(struct S *P) {
__asm__("abc %0" : "=r"(P->a) );
}
struct large {
int x[1000];
};
// CIR: cir.func{{.*}}@t15
// CIR: %[[X:.*]] = cir.alloca "x" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[LARGE:.*]] = cir.alloca "P" {{.*}} init : !cir.ptr<!cir.ptr<!rec_large>>
// CIR: %[[LARGE_LOAD:.*]] = cir.load deref align(8) %1 : !cir.ptr<!cir.ptr<!rec_large>>, !cir.ptr<!rec_large>
// CIR: %[[X_LOAD:.*]] = cir.load align(4) %0 : !cir.ptr<!s32i>, !s32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[LARGE_LOAD]] : !cir.ptr<!rec_large> (maybe_memory), %[[X_LOAD]] : !s32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"xyz " "=r,*m,0,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[X]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t15
// LLVM: %[[X:.*]] = alloca i32
// LLVM: %[[LARGE:.*]] = alloca ptr
// LLVM: %[[LARGE_LOAD:.*]] = load ptr, ptr %[[LARGE]]
// LLVM: %[[X_LOAD:.*]] = load i32, ptr %[[X]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "xyz ", "=r,*m,0,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(%struct.large) %[[LARGE_LOAD]], i32 %[[X_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[X]]
unsigned long t15(int x, struct large *P) {
__asm__("xyz "
: "=r" (x)
: "m" (*P), "0" (x));
return x;
}
// CIR: cir.func{{.*}}@t16
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[B:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[B_LOAD:.*]] = cir.load align(4) %[[B]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[B_LOAD]] : !s32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"nop;" "=%{cx},r,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[A]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t16
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i32
// LLVM: %[[A:.*]] = alloca i32
// LLVM: %[[B:.*]] = alloca i32
// LLVM: %[[B_LOAD:.*]] = load i32, ptr %[[B]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "nop;", "=%{cx},r,~{dirflag},~{fpsr},~{flags}"(i32 %[[B_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[A]]
int t16(void) {
int a,b;
asm ( "nop;"
:"=%c" (a)
: "r" (b)
);
return 0;
}
// CIR: cir.func{{.*}}@t17
// CIR: %[[I:.*]] = cir.alloca "i" {{.*}} : !cir.ptr<!s32i>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[I]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"nop" "=*m,~{dirflag},~{fpsr},~{flags}"})
// LLVM: define{{.*}}@t17
// LLVM: %[[I:.*]] = alloca i32
// LLVM: call void asm "nop", "=*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[I]])
void t17(void) {
int i;
__asm__ ( "nop": "=m"(i));
}
// CIR: cir.func{{.*}}@t18
// CIR: %[[DATA:.*]] = cir.alloca "data" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[B:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[ASM_RES_VAR:.*]] = cir.alloca "__asm_result" {{.*}} : !cir.ptr<!rec_anon_struct>
// CIR: %[[DATA_LOAD:.*]] = cir.load align(4) %[[DATA]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[DATA_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"xyz" "={ax},={dx},{ax},~{dirflag},~{fpsr},~{flags}"}) -> !rec_anon_struct
// CIR-NEXT: cir.store align(1) %[[ASM_RES]], %[[ASM_RES_VAR]] : !rec_anon_struct, !cir.ptr<!rec_anon_struct>
// CIR-NEXT: %[[GM_FIRST:.*]] = cir.get_member %[[ASM_RES_VAR]][0] {name = ""} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!s32i>
// CIR-NEXT: %[[GM_FIRST_LOAD:.*]] = cir.load align(1) %[[GM_FIRST]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: %[[GM_SEC:.*]] = cir.get_member %[[ASM_RES_VAR]][1] {name = ""} : !cir.ptr<!rec_anon_struct> -> !cir.ptr<!s32i>
// CIR-NEXT: %[[GM_SEC_LOAD:.*]] = cir.load align(1) %[[GM_SEC]] : !cir.ptr<!s32i>, !s32i
// CIR-NEXT: cir.store align(4) %[[GM_FIRST_LOAD]], %[[A]] : !s32i, !cir.ptr<!s32i>
// CIR-NEXT: cir.store align(4) %[[GM_SEC_LOAD]], %[[B]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t18
// LLVM: %[[DATA:.*]] = alloca i32
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i32
// LLVM: %[[A:.*]] = alloca i32
// LLVM: %[[B:.*]] = alloca i32
//
// Classic codegen doesn't alloca a slot for this, and uses extractvalue instead.
// CIRLLVMONLY: %[[ASM_RES_VAR:.*]] = alloca { i32, i32 }
// LLVM: %[[DATA_LOAD:.*]] = load i32, ptr %[[DATA]]
// LLVM: %[[ASM_RES:.*]] = call { i32, i32 } asm "xyz", "={ax},={dx},{ax},~{dirflag},~{fpsr},~{flags}"(i32 %[[DATA_LOAD]])
//
// Because we go through get_member, the codegen here is slightly different.
// CIRLLVMONLY: store { i32, i32 } %[[ASM_RES]], ptr %[[ASM_RES_VAR]]
// CIRLLVMONLY: %[[GEP_FIRST:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[ASM_RES_VAR]], i32 0, i32 0
// CIRLLVMONLY: %[[GEP_FIRST_LOAD:.*]] = load i32, ptr %[[GEP_FIRST]]
// CIRLLVMONLY: %[[GEP_SECOND:.*]] = getelementptr inbounds nuw { i32, i32 }, ptr %[[ASM_RES_VAR]], i32 0, i32 1
// CIRLLVMONLY: %[[GEP_SECOND_LOAD:.*]] = load i32, ptr %[[GEP_SECOND]]
//
// LLVMONLY: %[[GEP_FIRST_LOAD:.*]] = extractvalue { i32, i32 } %[[ASM_RES]], 0
// LLVMONLY: %[[GEP_SECOND_LOAD:.*]] = extractvalue { i32, i32 } %[[ASM_RES]], 1
//
// LLVM: store i32 %[[GEP_FIRST_LOAD]], ptr %[[A]]
// LLVM: store i32 %[[GEP_SECOND_LOAD]], ptr %[[B]]
int t18(unsigned data) {
int a, b;
asm("xyz" :"=a"(a), "=d"(b) : "a"(data));
return a + b;
}
// CIR: cir.func{{.*}}@t19
// CIR: %[[DATA:.*]] = cir.alloca "data" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[A:.*]] = cir.alloca "a" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[B:.*]] = cir.alloca "b" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[DATA_LOAD:.*]] = cir.load align(4) %[[DATA]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[DATA_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"x$(abc$|def$|ghi$)z" "=r,r,~{dirflag},~{fpsr},~{flags}"}) -> !s32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[A]] : !s32i, !cir.ptr<!s32i>
// LLVM: define{{.*}}@t19
// LLVM: %[[DATA:.*]] = alloca i32
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca i32
// LLVM: %[[A:.*]] = alloca i32
// LLVM: %[[B:.*]] = alloca i32
// LLVM: %[[DATA_LOAD:.*]] = load i32, ptr %[[DATA]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "x$(abc$|def$|ghi$)z", "=r,r,~{dirflag},~{fpsr},~{flags}"(i32 %[[DATA_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[A]]
int t19(unsigned data) {
int a, b;
asm("x{abc|def|ghi}z" :"=r"(a): "r"(data));
return a + b;
}
// skip t20 and t21: long double is not supported
// CIR: cir.func{{.*}}@t22
// CIR: %[[LA:.*]] = cir.alloca "la" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[LB:.*]] = cir.alloca "lb" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[BIGRES:.*]] = cir.alloca "bigres" {{.*}} : !cir.ptr<!u32i>
// CIR: %[[LA_LOAD:.*]] = cir.load align(4) %[[LA]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[LB_LOAD:.*]] = cir.load align(4) %[[LB]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[LA_LOAD]] : !u32i, %[[LB_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"0:\0A1:\0A" "=l{ax},0,{cx},~{edx},~{cc},~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: cir.store align(4) %[[ASM_RES]], %[[BIGRES]] : !u32i, !cir.ptr<!u32i>
// LLVM: define{{.*}}@t22
// LLVM: %[[LA:.*]] = alloca i32
// LLVM: %[[LB:.*]] = alloca i32
// LLVM: %[[BIGRES:.*]] = alloca i32
// LLVM: %[[LA_LOAD:.*]] = load i32, ptr %[[LA]]
// LLVM: %[[LB_LOAD:.*]] = load i32, ptr %[[LB]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "0:\0A1:\0A", "=l{ax},0,{cx},~{edx},~{cc},~{dirflag},~{fpsr},~{flags}"(i32 %[[LA_LOAD]], i32 %[[LB_LOAD]])
// LLVM: store i32 %[[ASM_RES]], ptr %[[BIGRES]]
// accept 'l' constraint
unsigned char t22(unsigned char a, unsigned char b) {
unsigned int la = a;
unsigned int lb = b;
unsigned int bigres;
unsigned char res;
__asm__ ("0:\n1:\n" : [bigres] "=la"(bigres) : [la] "0"(la), [lb] "c"(lb) :
"edx", "cc");
res = bigres;
return res;
}
// CIR: cir.func{{.*}}@t23
// CIR: %[[LA:.*]] = cir.alloca "la" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[LB:.*]] = cir.alloca "lb" {{.*}} init : !cir.ptr<!u32i>
// CIR: %[[RES:.*]] = cir.alloca "res" {{.*}} : !cir.ptr<!u8i>
// CIR: %[[LA_LOAD:.*]] = cir.load align(4) %[[LA]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[LB_LOAD:.*]] = cir.load align(4) %[[LB]] : !cir.ptr<!u32i>, !u32i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[LA_LOAD]] : !u32i, %[[LB_LOAD]] : !u32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"0:\0A1:\0A" "=l{ax},0,{cx},~{edx},~{cc},~{dirflag},~{fpsr},~{flags}"}) -> !u32i
// CIR-NEXT: %[[ASM_RES_CAST:.*]] = cir.cast integral %[[ASM_RES]] : !u32i -> !u8i
// CIR-NEXT: cir.store align(1) %[[ASM_RES_CAST]], %[[RES]] : !u8i, !cir.ptr<!u8i>
// LLVM: define{{.*}}@t23
// LLVM: %[[LA:.*]] = alloca i32
// LLVM: %[[LB:.*]] = alloca i32
// LLVM: %[[RES:.*]] = alloca i8
// LLVM: %[[LA_LOAD:.*]] = load i32, ptr %[[LA]]
// LLVM: %[[LB_LOAD:.*]] = load i32, ptr %[[LB]]
// LLVM: %[[ASM_RES:.*]] = call i32 asm "0:\0A1:\0A", "=l{ax},0,{cx},~{edx},~{cc},~{dirflag},~{fpsr},~{flags}"(i32 %[[LA_LOAD]], i32 %[[LB_LOAD]])
// LLVM: %[[ASM_RES_TRUNC:.*]] = trunc i32 %[[ASM_RES]] to i8
// LLVM: store i8 %[[ASM_RES_TRUNC]], ptr %[[RES]]
// accept 'l' constraint
unsigned char t23(unsigned char a, unsigned char b) {
unsigned int la = a;
unsigned int lb = b;
unsigned char res;
__asm__ ("0:\n1:\n" : [res] "=la"(res) : [la] "0"(la), [lb] "c"(lb) :
"edx", "cc");
return res;
}
// CIR: cir.func{{.*}}@t24
// CIR: %[[C:.*]] = cir.alloca "c" {{.*}} init : !cir.ptr<!s8i>
// CIR: %[[ADDR:.*]] = cir.alloca "addr" {{.*}} : !cir.ptr<!cir.ptr<!void>>
// CIR: %[[C_LOAD:.*]] = cir.load align(1) %[[C]] : !cir.ptr<!s8i>, !s8i
// CIR: %[[C_LOAD_CAST:.*]] = cir.cast integral %[[C_LOAD]] : !s8i -> !u64i
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[C_LOAD_CAST]] : !u64i]
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"foobar" "={ax},0,~{dirflag},~{fpsr},~{flags}"}) -> !cir.ptr<!void>
// CIR-NEXT: cir.store align(8) %[[ASM_RES]], %[[ADDR]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// LLVM: define{{.*}}@t24
// LLVM: %[[C:.*]] = alloca i8
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca ptr
// LLVM: %[[ADDR:.*]] = alloca ptr
// LLVM: %[[C_LOAD:.*]] = load i8, ptr %[[C]]
// The two IR forms disagree as to whether this should be a zero or sign extend.
// It looks like this should be a 'sign' extend (sign->unsigned cast typically
// results in a sext), so this might be a bug in classic codegen.
// CIRLLVMONLY: %[[C_LOAD_EXT:.*]] = sext i8 %[[C_LOAD]] to i64
// LLVMONLY: %[[C_LOAD_EXT:.*]] = zext i8 %[[C_LOAD]] to i64
// LLVM: %[[ASM_RES:.*]] = call ptr asm "foobar", "={ax},0,~{dirflag},~{fpsr},~{flags}"(i64 %[[C_LOAD_EXT]])
// LLVM: store ptr %[[ASM_RES]], ptr %[[ADDR]]
void *t24(char c) {
void *addr;
__asm__ ("foobar" : "=a" (addr) : "0" (c));
return addr;
}
// CIR: cir.func{{.*}}@t25
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"finit" "~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{fpsr},~{fpcr},~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t25
// LLVM: call void asm sideeffect "finit", "~{st},~{st(1)},~{st(2)},~{st(3)},~{st(4)},~{st(5)},~{st(6)},~{st(7)},~{fpsr},~{fpcr},~{dirflag},~{fpsr},~{flags}"()
void t25(void)
{
__asm__ __volatile__( \
"finit" \
: \
: \
:"st","st(1)","st(2)","st(3)", \
"st(4)","st(5)","st(6)","st(7)", \
"fpsr","fpcr" \
);
}
//t26 skipped - no vector type support
// CIR: cir.func{{.*}}@t27
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"nop" "~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t27
// LLVM: call void asm sideeffect "nop", "~{dirflag},~{fpsr},~{flags}"()
void t27(void) {
asm volatile("nop");
}
// CIR: cir.func{{.*}}@t28
// CIR: %[[ONE:.*]] = cir.const #cir.int<1> : !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[ONE]] : !s32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"/* $0 */" "i|r,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t28
// LLVM: call void asm sideeffect "/* $0 */", "i|r,~{dirflag},~{fpsr},~{flags}"(i32 1)
// Check handling of '*' and '#' constraint modifiers.
void t28(void)
{
asm volatile ("/* %0 */" : : "i#*X,*r" (1));
}
static unsigned t29_var[1];
// CIR: cir.func{{.*}}@t29
// CIR: %[[ARR:.*]] = cir.get_global @t29_var : !cir.ptr<!cir.array<!u32i x 1>>
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[ARR]] : !cir.ptr<!cir.array<!u32i x 1>> (maybe_memory)],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"movl %eax, $0" "*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t29
// LLVM: call void asm sideeffect "movl %eax, $0", "*m,~{dirflag},~{fpsr},~{flags}"(ptr elementtype([1 x i32]) @t29_var)
void t29(void) {
asm volatile("movl %%eax, %0"
:
: "m"(t29_var));
}
// CIR: cir.func{{.*}}@t30
// CIR: %[[LEN:.*]] = cir.alloca "len" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[LEN_LOAD:.*]] = cir.load align(4) %[[LEN]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[LEN]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[LEN_LOAD]] : !s32i],
// CIR-NEXT: {"" "=*&rm,0,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t30
// LLVM: %[[LEN_ADDR:.*]] = alloca i32
// LLVM: %[[LEN:.*]] = load i32, ptr %[[LEN_ADDR]]
// LLVM: call void asm sideeffect "", "=*&rm,0,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[LEN_ADDR]], i32 %[[LEN]])
void t30(int len) {
__asm__ volatile(""
: "+&&rm"(len));
}
// CIR: cir.func{{.*}}@t31
// CIR: %[[LEN:.*]] = cir.alloca "len" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[LEN_LOAD:.*]] = cir.load align(4) %[[LEN]] : !cir.ptr<!s32i>, !s32i
// CIR: %[[LEN_LOAD2:.*]] = cir.load align(4) %[[LEN]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [%[[LEN]] : !cir.ptr<!s32i> (maybe_memory), %[[LEN]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in = [],
// CIR-NEXT: in_out = [%[[LEN_LOAD]] : !s32i, %[[LEN_LOAD2]] : !s32i],
// CIR-NEXT: {"" "=*%rm,=*rm,0,1,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t31
// LLVM: %[[LEN_ADDR:.*]] = alloca i32
// LLVM: %[[LEN1:.*]] = load i32, ptr %[[LEN_ADDR]]
// LLVM: %[[LEN2:.*]] = load i32, ptr %[[LEN_ADDR]]
// LLVM: call void asm sideeffect "", "=*%rm,=*rm,0,1,~{dirflag},~{fpsr},~{flags}"(ptr elementtype(i32) %[[LEN_ADDR]], ptr elementtype(i32) %[[LEN_ADDR]], i32 %[[LEN1]], i32 %[[LEN2]])
void t31(int len) {
__asm__ volatile(""
: "+%%rm"(len), "+rm"(len));
}
//t32 skipped: no goto
// CIR: cir.func{{.*}}@t33
// CIR: %[[PTR:.*]] = cir.alloca "ptr" {{.*}} init : !cir.ptr<!cir.ptr<!void>>
// CIR: %[[RET:.*]] = cir.alloca "ret" {{.*}} : !cir.ptr<!cir.ptr<!void>>
// CIR: %[[PTR_LOAD:.*]] = cir.load align(8) %0 : !cir.ptr<!cir.ptr<!void>>, !cir.ptr<!void>
// CIR: %[[ASM_RES:.*]] = cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[PTR_LOAD]] : !cir.ptr<!void>],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"lea $1, $0" "=r,p,~{dirflag},~{fpsr},~{flags}"}) -> !cir.ptr<!void>
// CIR-NEXT: cir.store align(8) %[[ASM_RES]], %[[RET]] : !cir.ptr<!void>, !cir.ptr<!cir.ptr<!void>>
// LLVM: define{{.*}}@t33
// LLVM: %[[PTR:.*]] = alloca ptr
// Classic codegen doesn't alloca for a return slot.
// CIRLLVMONLY: alloca ptr
// LLVM: %[[RET:.*]] = alloca ptr
// LLVM: %[[PTR_LOAD:.*]] = load ptr, ptr %[[PTR]]
// LLVM: %[[ASM_RES:.*]] = call ptr asm "lea $1, $0", "=r,p,~{dirflag},~{fpsr},~{flags}"(ptr %[[PTR_LOAD]])
// LLVM: store ptr %[[ASM_RES]], ptr %[[RET]]
void *t33(void *ptr)
{
void *ret;
asm ("lea %1, %0" : "=r" (ret) : "p" (ptr));
return ret;
}
// CIR: %[[FOUR:.*]] = cir.const #cir.int<4> : !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[FOUR]] : !s32i],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"T34 CC NAMED MODIFIER: ${0:c}" "i,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t34
// LLVM: call void asm sideeffect "T34 CC NAMED MODIFIER: ${0:c}", "i,~{dirflag},~{fpsr},~{flags}"(i32 4)
void t34(void) {
__asm__ volatile("T34 CC NAMED MODIFIER: %cc[input]" :: [input] "i" (4));
}
// Register input (null element type) before a memory input: keep elementtype.
// CIR: cir.func{{.*}}@t35
// CIR: %[[I:.*]] = cir.alloca "i" {{.*}} init : !cir.ptr<!s32i>
// CIR: %[[G:.*]] = cir.alloca "g" {{.*}} : !cir.ptr<!s32i>
// CIR: %[[I_LOAD:.*]] = cir.load {{.*}} %[[I]] : !cir.ptr<!s32i>, !s32i
// CIR: cir.asm(x86_att,
// CIR-NEXT: out = [],
// CIR-NEXT: in = [%[[I_LOAD]] : !s32i, %[[G]] : !cir.ptr<!s32i> (maybe_memory)],
// CIR-NEXT: in_out = [],
// CIR-NEXT: {"" "r,*m,~{dirflag},~{fpsr},~{flags}"}) side_effects
// LLVM: define{{.*}}@t35
// LLVM: %[[I:.*]] = alloca i32
// LLVM: %[[G:.*]] = alloca i32
// LLVM: %[[I_LOAD:.*]] = load i32, ptr %[[I]]
// LLVM: call void asm sideeffect "", "r,*m,~{dirflag},~{fpsr},~{flags}"(i32 %[[I_LOAD]], ptr elementtype(i32) %[[G]])
void t35(int i) {
int g;
__asm__ volatile("" :: "r"(i), "m"(g));
}