blob: dfe74a9e77c9cb4f21677898670ecff450a783bb [file] [log] [blame]
// RUN: %clang_cc1 -std=c++17 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s
// Test __atomic_* built-ins that have a memory order parameter with a runtime
// value. This requires generating a switch statement, so the amount of
// generated code is surprisingly large.
//
// Only a representative sample of atomic operations are tested: one read-only
// operation (atomic_load), one write-only operation (atomic_store), one
// read-write operation (atomic_exchange), and the most complex operation
// (atomic_compare_exchange).
int runtime_load(int *ptr, int order) {
return __atomic_load_n(ptr, order);
}
// CHECK: %[[ptr:.*]] = cir.load %[[ptr_var:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[order:.*]] = cir.load %[[order_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.switch (%[[order]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[T8:.*]] = cir.load atomic(relaxed) %[[ptr]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[T8]], %[[temp_var:.*]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[T8:.*]] = cir.load atomic(acquire) %[[ptr]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[T8]], %[[temp_var]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[T8:.*]] = cir.load atomic(seq_cst) %[[ptr]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[T8]], %[[temp_var]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
void atomic_store_n(int* ptr, int val, int order) {
__atomic_store_n(ptr, val, order);
}
// CHECK: %[[ptr:.*]] = cir.load %[[ptr_var:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[order:.*]] = cir.load %[[order_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[val:.*]] = cir.load %[[val_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[val]], %[[temp_var:.*]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.switch (%[[order]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[T7:.*]] = cir.load %[[temp_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store atomic(relaxed) %[[T7]], %[[ptr]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 3) {
// CHECK: %[[T7:.*]] = cir.load %[[temp_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store atomic(release) %[[T7]], %[[ptr]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[T7:.*]] = cir.load %[[temp_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store atomic(seq_cst) %[[T7]], %[[ptr]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
int atomic_exchange_n(int* ptr, int val, int order) {
return __atomic_exchange_n(ptr, val, order);
}
// CHECK: %[[ptr:.*]] = cir.load %[[ptr_var:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[order:.*]] = cir.load %[[order_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[val:.*]] = cir.load %[[val_var:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[val]], %[[temp_var:.*]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.switch (%[[order]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[T11:.*]] = cir.load %[[temp_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T12:.*]] = cir.atomic.xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[T11]] : !s32i, relaxed) : !s32i
// CHECK: cir.store %[[T12]], %[[result:.*]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[T11:.*]] = cir.load %[[temp_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T12:.*]] = cir.atomic.xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[T11]] : !s32i, acquire) : !s32i
// CHECK: cir.store %[[T12]], %[[result]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 3) {
// CHECK: %[[T11:.*]] = cir.load %[[temp_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T12:.*]] = cir.atomic.xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[T11]] : !s32i, release) : !s32i
// CHECK: cir.store %[[T12]], %[[result]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 4) {
// CHECK: %[[T11:.*]] = cir.load %[[temp_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T12:.*]] = cir.atomic.xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[T11]] : !s32i, acq_rel) : !s32i
// CHECK: cir.store %[[T12]], %[[result]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[T11:.*]] = cir.load %[[temp_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T12:.*]] = cir.atomic.xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[T11]] : !s32i, seq_cst) : !s32i
// CHECK: cir.store %[[T12]], %[[result]] : !s32i, !cir.ptr<!s32i>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
bool atomic_compare_exchange_n(int* ptr, int* expected,
int desired, int success, int failure) {
return __atomic_compare_exchange_n(ptr, expected, desired, false,
success, failure);
}
// CHECK: %[[ptr:.*]] = cir.load %[[T0:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[success:.*]] = cir.load %[[T3:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[expected_addr:.*]] = cir.load %[[T1:.*]] : !cir.ptr<!cir.ptr<!s32i>>, !cir.ptr<!s32i>
// CHECK: %[[T11:.*]] = cir.load %[[T2:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: cir.store %[[T11]], %[[desired_var:.*]] : !s32i, !cir.ptr<!s32i>
// CHECK: %[[failure:.*]] = cir.load %[[T4:.*]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[T13:.*]] = cir.const #false
// CHECK: cir.switch (%[[success]] : !s32i) [
// CHECK: case (default) {
// CHECK: cir.switch (%[[failure]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = relaxed, failure = relaxed) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var:.*]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = relaxed, failure = acquire) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = relaxed, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: cir.switch (%[[failure]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acquire, failure = relaxed) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acquire, failure = acquire) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acquire, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 3) {
// CHECK: cir.switch (%[[failure]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = release, failure = relaxed) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = release, failure = acquire) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = release, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 4) {
// CHECK: cir.switch (%[[failure]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acq_rel, failure = relaxed) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acq_rel, failure = acquire) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = acq_rel, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: cir.switch (%[[failure]] : !s32i) [
// CHECK: case (default) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = seq_cst, failure = relaxed) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (anyof, [1, 2] : !s32i) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = seq_cst, failure = acquire) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: },
// CHECK: case (equal, 5) {
// CHECK: %[[expected:.*]] = cir.load %[[expected_addr]] : !cir.ptr<!s32i>, !s32i
// CHECK: %[[desired:.*]] = cir.load %[[desired_var]] : !cir.ptr<!s32i>, !s32i
// CHECK: %old, %cmp = cir.atomic.cmp_xchg(%[[ptr]] : !cir.ptr<!s32i>, %[[expected]] : !s32i, %[[desired]] : !s32i, success = seq_cst, failure = seq_cst) : (!s32i, !cir.bool)
// CHECK: %[[succeeded:.*]] = cir.unary(not, %cmp) : !cir.bool, !cir.bool
// CHECK: cir.if %[[succeeded]] {
// CHECK: cir.store %old, %[[expected_addr]] : !s32i, !cir.ptr<!s32i>
// CHECK: }
// CHECK: cir.store %cmp, %[[result_var]] : !cir.bool, !cir.ptr<!cir.bool>
// CHECK: cir.break
// CHECK: }
// CHECK: ]
// CHECK: cir.break
// CHECK: }
// CHECK: ]