
Re-write the sema and codegen for the atomic_test_and_set and atomic_clear builtin functions to go via AtomicExpr, like the other atomic builtins do. This simplifies the code, because AtomicExpr already handles things like generating code for to dynamically select the memory ordering, which was duplicated for these builtins. This also fixes a few crash bugs, one when passing an integer to the pointer argument, and one when using an array. This also adds diagnostics for the memory orderings which are not valid for atomic_clear according to https://gcc.gnu.org/onlinedocs/gcc/_005f_005fatomic-Builtins.html, which were missing before. Fixes https://github.com/llvm/llvm-project/issues/111293. This is a re-land of #120449, modified to allow any non-const pointer type for the first argument.
346 lines
16 KiB
C
346 lines
16 KiB
C
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --version 5
|
|
// RUN: %clang_cc1 %s -emit-llvm -o - -triple=aarch64-none-elf | FileCheck %s
|
|
// REQUIRES: aarch64-registered-target
|
|
|
|
#include <stdatomic.h>
|
|
|
|
// CHECK-LABEL: define dso_local void @clear_relaxed(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0:[0-9]+]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_relaxed(char *ptr) {
|
|
__atomic_clear(ptr, memory_order_relaxed);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @clear_seq_cst(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] seq_cst, align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_seq_cst(char *ptr) {
|
|
__atomic_clear(ptr, memory_order_seq_cst);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @clear_release(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] release, align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_release(char *ptr) {
|
|
__atomic_clear(ptr, memory_order_release);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @clear_dynamic(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[ORDER:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ORDER_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store i32 [[ORDER]], ptr [[ORDER_ADDR]], align 4
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ORDER_ADDR]], align 4
|
|
// CHECK-NEXT: switch i32 [[TMP1]], label %[[MONOTONIC:.*]] [
|
|
// CHECK-NEXT: i32 3, label %[[RELEASE:.*]]
|
|
// CHECK-NEXT: i32 5, label %[[SEQCST:.*]]
|
|
// CHECK-NEXT: ]
|
|
// CHECK: [[MONOTONIC]]:
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE:.*]]
|
|
// CHECK: [[RELEASE]]:
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] release, align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[SEQCST]]:
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] seq_cst, align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[ATOMIC_CONTINUE]]:
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_dynamic(char *ptr, int order) {
|
|
__atomic_clear(ptr, order);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_relaxed(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_relaxed(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_relaxed);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_consume(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_consume(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_consume);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_acquire(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_acquire(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_acquire);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_release(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 release, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_release(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_release);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_acq_rel(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acq_rel, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_acq_rel(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_acq_rel);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_seq_cst(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 seq_cst, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_seq_cst(char *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_seq_cst);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_dynamic(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]], i32 noundef [[ORDER:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ORDER_ADDR:%.*]] = alloca i32, align 4
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store i32 [[ORDER]], ptr [[ORDER_ADDR]], align 4
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i32, ptr [[ORDER_ADDR]], align 4
|
|
// CHECK-NEXT: switch i32 [[TMP1]], label %[[MONOTONIC:.*]] [
|
|
// CHECK-NEXT: i32 1, label %[[ACQUIRE:.*]]
|
|
// CHECK-NEXT: i32 2, label %[[ACQUIRE]]
|
|
// CHECK-NEXT: i32 3, label %[[RELEASE:.*]]
|
|
// CHECK-NEXT: i32 4, label %[[ACQREL:.*]]
|
|
// CHECK-NEXT: i32 5, label %[[SEQCST:.*]]
|
|
// CHECK-NEXT: ]
|
|
// CHECK: [[MONOTONIC]]:
|
|
// CHECK-NEXT: [[TMP2:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP2]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE:.*]]
|
|
// CHECK: [[ACQUIRE]]:
|
|
// CHECK-NEXT: [[TMP3:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acquire, align 1
|
|
// CHECK-NEXT: [[TOBOOL1:%.*]] = icmp ne i8 [[TMP3]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL1]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[RELEASE]]:
|
|
// CHECK-NEXT: [[TMP4:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 release, align 1
|
|
// CHECK-NEXT: [[TOBOOL2:%.*]] = icmp ne i8 [[TMP4]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL2]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[ACQREL]]:
|
|
// CHECK-NEXT: [[TMP5:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 acq_rel, align 1
|
|
// CHECK-NEXT: [[TOBOOL3:%.*]] = icmp ne i8 [[TMP5]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL3]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[SEQCST]]:
|
|
// CHECK-NEXT: [[TMP6:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 seq_cst, align 1
|
|
// CHECK-NEXT: [[TOBOOL4:%.*]] = icmp ne i8 [[TMP6]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL4]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: br label %[[ATOMIC_CONTINUE]]
|
|
// CHECK: [[ATOMIC_CONTINUE]]:
|
|
// CHECK-NEXT: [[TMP7:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP7]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_dynamic(char *ptr, int order) {
|
|
__atomic_test_and_set(ptr, order);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_array(
|
|
// CHECK-SAME: ) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[X:%.*]] = alloca [10 x i32], align 4
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: [[ARRAYDECAY:%.*]] = getelementptr inbounds [10 x i32], ptr [[X]], i64 0, i64 0
|
|
// CHECK-NEXT: [[TMP0:%.*]] = atomicrmw volatile xchg ptr [[ARRAYDECAY]], i8 1 seq_cst, align 4
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP0]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP1:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP1]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_array() {
|
|
volatile int x[10];
|
|
__atomic_test_and_set(x, memory_order_seq_cst);
|
|
}
|
|
|
|
// These intrinsics accept any pointer type, including void and incomplete
|
|
// structs, and always access the first byte regardless of the actual type
|
|
// size.
|
|
|
|
struct incomplete;
|
|
|
|
// CHECK-LABEL: define dso_local void @clear_int(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 4
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_int(int *ptr) {
|
|
__atomic_clear(ptr, memory_order_relaxed);
|
|
}
|
|
// CHECK-LABEL: define dso_local void @clear_void(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_void(void *ptr) {
|
|
__atomic_clear(ptr, memory_order_relaxed);
|
|
}
|
|
// CHECK-LABEL: define dso_local void @clear_incomplete(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: store atomic i8 0, ptr [[TMP0]] monotonic, align 1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void clear_incomplete(struct incomplete *ptr) {
|
|
__atomic_clear(ptr, memory_order_relaxed);
|
|
}
|
|
|
|
// CHECK-LABEL: define dso_local void @test_and_set_int(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 4
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_int(int *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_relaxed);
|
|
}
|
|
// CHECK-LABEL: define dso_local void @test_and_set_void(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_void(void *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_relaxed);
|
|
}
|
|
// CHECK-LABEL: define dso_local void @test_and_set_incomplete(
|
|
// CHECK-SAME: ptr noundef [[PTR:%.*]]) #[[ATTR0]] {
|
|
// CHECK-NEXT: [[ENTRY:.*:]]
|
|
// CHECK-NEXT: [[PTR_ADDR:%.*]] = alloca ptr, align 8
|
|
// CHECK-NEXT: [[ATOMIC_TEMP:%.*]] = alloca i8, align 1
|
|
// CHECK-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[PTR_ADDR]], align 8
|
|
// CHECK-NEXT: [[TMP1:%.*]] = atomicrmw xchg ptr [[TMP0]], i8 1 monotonic, align 1
|
|
// CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i8 [[TMP1]], 0
|
|
// CHECK-NEXT: store i1 [[TOBOOL]], ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[TMP2:%.*]] = load i8, ptr [[ATOMIC_TEMP]], align 1
|
|
// CHECK-NEXT: [[LOADEDV:%.*]] = trunc i8 [[TMP2]] to i1
|
|
// CHECK-NEXT: ret void
|
|
//
|
|
void test_and_set_incomplete(struct incomplete *ptr) {
|
|
__atomic_test_and_set(ptr, memory_order_relaxed);
|
|
}
|