mirror of
https://github.com/c3lang/c3c.git
synced 2026-02-27 12:01:16 +00:00
Fix atomic_fetch_sub builtin + Updated atomic library (#997)
Fix atomic_fetch_sub builtin + Updated atomic library
This commit is contained in:
committed by
GitHub
parent
8ed9be9c58
commit
8d11794f83
@@ -85,31 +85,31 @@ macro Type Atomic.min(&self, Type value, AtomicOrdering ordering = SEQ_CONSISTEN
|
|||||||
return @atomic_exec(atomic::fetch_min, data, value, ordering);
|
return @atomic_exec(atomic::fetch_min, data, value, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro Type Atomic.or(&self, ulong value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
macro Type Atomic.or(&self, uint value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
||||||
{
|
{
|
||||||
Type* data = &self.data;
|
Type* data = &self.data;
|
||||||
return @atomic_exec(atomic::fetch_or, data, value, ordering);
|
return @atomic_exec(atomic::fetch_or, data, value, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn Type Atomic.xor(&self, ulong value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
fn Type Atomic.xor(&self, uint value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
||||||
{
|
{
|
||||||
Type* data = &self.data;
|
Type* data = &self.data;
|
||||||
return @atomic_exec(atomic::fetch_xor, data, value, ordering);
|
return @atomic_exec(atomic::fetch_xor, data, value, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro Type Atomic.and(&self, ulong value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
macro Type Atomic.and(&self, uint value, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
||||||
{
|
{
|
||||||
Type* data = &self.data;
|
Type* data = &self.data;
|
||||||
return @atomic_exec(atomic::fetch_and, data, value, ordering);
|
return @atomic_exec(atomic::fetch_and, data, value, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro Type Atomic.shift_right(&self, ulong amount, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
macro Type Atomic.shift_right(&self, uint amount, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
||||||
{
|
{
|
||||||
Type* data = &self.data;
|
Type* data = &self.data;
|
||||||
return @atomic_exec(atomic::fetch_shift_right, data, amount, ordering);
|
return @atomic_exec(atomic::fetch_shift_right, data, amount, ordering);
|
||||||
}
|
}
|
||||||
|
|
||||||
macro Type Atomic.shift_left(&self, ulong amount, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
macro Type Atomic.shift_left(&self, uint amount, AtomicOrdering ordering = SEQ_CONSISTENT) @if(!types::is_float(Type))
|
||||||
{
|
{
|
||||||
Type* data = &self.data;
|
Type* data = &self.data;
|
||||||
return @atomic_exec(atomic::fetch_shift_left, data, amount, ordering);
|
return @atomic_exec(atomic::fetch_shift_left, data, amount, ordering);
|
||||||
@@ -139,31 +139,12 @@ module std::atomic;
|
|||||||
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
var $load_ordering = $ordering;
|
$if $alignment == 0:
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$alignment = $typeof(*ptr).sizeof;
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
|
||||||
$endif
|
$endif
|
||||||
|
return $$atomic_fetch_add(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
|
|
||||||
|
|
||||||
$StorageType* storage_ptr = ($StorageType*)ptr;
|
|
||||||
|
|
||||||
$typeof(*ptr) old_value;
|
|
||||||
$typeof(*ptr) new_value;
|
|
||||||
|
|
||||||
$StorageType storage_old_value;
|
|
||||||
$StorageType storage_new_value;
|
|
||||||
|
|
||||||
do {
|
|
||||||
storage_old_value = $$atomic_load(storage_ptr, false, $load_ordering.ordinal);
|
|
||||||
old_value = bitcast(storage_old_value, $typeof(*ptr));
|
|
||||||
new_value = old_value + y;
|
|
||||||
storage_new_value = bitcast(new_value, $StorageType);
|
|
||||||
} while (mem::compare_exchange(storage_ptr, storage_old_value, storage_new_value, $ordering, $load_ordering) != storage_old_value);
|
|
||||||
|
|
||||||
return old_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -175,31 +156,12 @@ macro fetch_add(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_sub(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_sub(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
var $load_ordering = $ordering;
|
$if $alignment == 0:
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$alignment = $typeof(*ptr).sizeof;
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
|
||||||
$endif
|
$endif
|
||||||
|
return $$atomic_fetch_sub(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
|
|
||||||
|
|
||||||
$StorageType* storage_ptr = ($StorageType*)ptr;
|
|
||||||
|
|
||||||
$typeof(*ptr) old_value;
|
|
||||||
$typeof(*ptr) new_value;
|
|
||||||
|
|
||||||
$StorageType storage_old_value;
|
|
||||||
$StorageType storage_new_value;
|
|
||||||
|
|
||||||
do {
|
|
||||||
storage_old_value = $$atomic_load(storage_ptr, false, $load_ordering.ordinal);
|
|
||||||
old_value = bitcast(storage_old_value, $typeof(*ptr));
|
|
||||||
new_value = old_value - y;
|
|
||||||
storage_new_value = bitcast(new_value, $StorageType);
|
|
||||||
} while (mem::compare_exchange(storage_ptr, storage_old_value, storage_new_value, $ordering, $load_ordering) != storage_old_value);
|
|
||||||
|
|
||||||
return old_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -285,8 +247,12 @@ macro fetch_div(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
|
$if types::is_int($typeof(*ptr)):
|
||||||
|
return $$atomic_fetch_or(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
|
$endif
|
||||||
|
|
||||||
var $load_ordering = $ordering;
|
var $load_ordering = $ordering;
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
||||||
@@ -323,8 +289,12 @@ macro fetch_or(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
|
$if types::is_int($typeof(*ptr)):
|
||||||
|
return $$atomic_fetch_xor(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
|
$endif
|
||||||
|
|
||||||
var $load_ordering = $ordering;
|
var $load_ordering = $ordering;
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
||||||
@@ -361,8 +331,12 @@ macro fetch_xor(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
* @require types::is_int($typeof(y)) "The value for or must be an int"
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_and(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_and(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
|
$if types::is_int($typeof(*ptr)):
|
||||||
|
return $$atomic_fetch_and(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
|
$endif
|
||||||
|
|
||||||
var $load_ordering = $ordering;
|
var $load_ordering = $ordering;
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
||||||
@@ -514,30 +488,12 @@ macro flag_clear(ptr, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_max(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_max(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
var $load_ordering = $ordering;
|
$if $alignment == 0:
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$alignment = $typeof(*ptr).sizeof;
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
|
||||||
$endif
|
$endif
|
||||||
|
return $$atomic_fetch_max(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
|
|
||||||
|
|
||||||
$StorageType* storage_ptr = ($StorageType*)ptr;
|
|
||||||
|
|
||||||
$typeof(*ptr) old_value;
|
|
||||||
$typeof(*ptr) new_value = y;
|
|
||||||
|
|
||||||
$StorageType storage_old_value;
|
|
||||||
$StorageType storage_new_value = bitcast(new_value, $StorageType);
|
|
||||||
|
|
||||||
do {
|
|
||||||
storage_old_value = $$atomic_load(storage_ptr, false, $load_ordering.ordinal);
|
|
||||||
old_value = bitcast(storage_old_value, $typeof(*ptr));
|
|
||||||
if (old_value >= new_value) break;
|
|
||||||
} while (mem::compare_exchange(storage_ptr, storage_old_value, storage_new_value, $ordering, $load_ordering) != storage_old_value);
|
|
||||||
|
|
||||||
return old_value;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -549,28 +505,10 @@ macro fetch_max(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
|||||||
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
* @require types::is_int($typeof(*ptr)) || types::is_float($typeof(*ptr)) "Only integer/float pointers may be used."
|
||||||
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
* @require $ordering != AtomicOrdering.NOT_ATOMIC && $ordering != AtomicOrdering.UNORDERED "Acquire ordering is not valid."
|
||||||
**/
|
**/
|
||||||
macro fetch_min(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT)
|
macro fetch_min(ptr, y, AtomicOrdering $ordering = SEQ_CONSISTENT, bool $volatile = false, usz $alignment = 0)
|
||||||
{
|
{
|
||||||
var $load_ordering = $ordering;
|
$if $alignment == 0:
|
||||||
$if $ordering == RELEASE || $ordering == ACQUIRE_RELEASE:
|
$alignment = $typeof(*ptr).sizeof;
|
||||||
$load_ordering = AtomicOrdering.SEQ_CONSISTENT;
|
|
||||||
$endif
|
$endif
|
||||||
|
return $$atomic_fetch_min(ptr, y, $volatile, $ordering.ordinal, $alignment);
|
||||||
var $StorageType = $typefrom(types::lower_to_atomic_compatible_type($typeof(*ptr)));
|
|
||||||
|
|
||||||
$StorageType* storage_ptr = ($StorageType*)ptr;
|
|
||||||
|
|
||||||
$typeof(*ptr) old_value;
|
|
||||||
$typeof(*ptr) new_value = y;
|
|
||||||
|
|
||||||
$StorageType storage_old_value;
|
|
||||||
$StorageType storage_new_value = bitcast(new_value, $StorageType);
|
|
||||||
|
|
||||||
do {
|
|
||||||
storage_old_value = $$atomic_load(storage_ptr, false, $load_ordering.ordinal);
|
|
||||||
old_value = bitcast(storage_old_value, $typeof(*ptr));
|
|
||||||
if (old_value <= new_value) break;
|
|
||||||
} while (mem::compare_exchange(storage_ptr, storage_old_value, storage_new_value, $ordering, $load_ordering) != storage_old_value);
|
|
||||||
|
|
||||||
return old_value;
|
|
||||||
}
|
}
|
||||||
|
|||||||
63
lib/std/atomic_nolibc.c3
Normal file
63
lib/std/atomic_nolibc.c3
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
// Copyright (c) 2023 Eduardo José Gómez Hernández. All rights reserved.
|
||||||
|
// Use of this source code is governed by the MIT license
|
||||||
|
// a copy of which can be found in the LICENSE_STDLIB file.
|
||||||
|
module std::atomic;
|
||||||
|
|
||||||
|
macro @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, $success, failure, $alignment) {
|
||||||
|
switch(failure)
|
||||||
|
{
|
||||||
|
case AtomicOrdering.RELAXED.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.RELAXED.ordinal, $alignment);
|
||||||
|
case AtomicOrdering.ACQUIRE.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.ACQUIRE.ordinal, $alignment);
|
||||||
|
case AtomicOrdering.SEQ_CONSISTENT.ordinal: return $$compare_exchange(ptr, expected, desired, false, false, $success, AtomicOrdering.SEQ_CONSISTENT.ordinal, $alignment);
|
||||||
|
default: assert(false, "Unrecognized failure ordering");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
macro @__atomic_compare_exchange_ordering_success(ptr, expected, desired, success, failure, $alignment)
|
||||||
|
{
|
||||||
|
switch(success)
|
||||||
|
{
|
||||||
|
case AtomicOrdering.RELAXED.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.RELAXED.ordinal, failure, $alignment);
|
||||||
|
case AtomicOrdering.ACQUIRE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.ACQUIRE.ordinal, failure, $alignment);
|
||||||
|
case AtomicOrdering.RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.RELEASE.ordinal, failure, $alignment);
|
||||||
|
case AtomicOrdering.ACQUIRE_RELEASE.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.ACQUIRE_RELEASE.ordinal, failure, $alignment);
|
||||||
|
case AtomicOrdering.SEQ_CONSISTENT.ordinal: return @__atomic_compare_exchange_ordering_failure(ptr, expected, desired, AtomicOrdering.SEQ_CONSISTENT.ordinal, failure, $alignment);
|
||||||
|
default: assert(false, "Unrecognized success ordering");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
fn CInt __atomic_compare_exchange(CInt size, any* ptr, any* expected, any* desired, CInt success, CInt failure) @extern("__atomic_compare_exchange") @export
|
||||||
|
{
|
||||||
|
switch (size)
|
||||||
|
{
|
||||||
|
case 1:
|
||||||
|
char* pt = (char*)ptr;
|
||||||
|
char ex = *(char*)expected;
|
||||||
|
char de = *(char*)desired;
|
||||||
|
if (ex == @__atomic_compare_exchange_ordering_success(pt, ex, de, success, failure, 1)) return 1;
|
||||||
|
case 2:
|
||||||
|
short* pt = (short*)ptr;
|
||||||
|
short ex = *(short*)expected;
|
||||||
|
short de = *(short*)desired;
|
||||||
|
if (ex == @__atomic_compare_exchange_ordering_success(pt, ex, de, success, failure, 2)) return 1;
|
||||||
|
case 4:
|
||||||
|
int* pt = (int*)ptr;
|
||||||
|
int ex = *(int*)expected;
|
||||||
|
int de = *(int*)desired;
|
||||||
|
if (ex == @__atomic_compare_exchange_ordering_success(pt, ex, de, success, failure, 4)) return 1;
|
||||||
|
case 8:
|
||||||
|
$if iptr.sizeof >= 8:
|
||||||
|
long* pt = (long*)ptr;
|
||||||
|
long ex = *(long*)expected;
|
||||||
|
long de = *(long*)desired;
|
||||||
|
if (ex == @__atomic_compare_exchange_ordering_success(pt, ex, de, success, failure, 8)) return 1;
|
||||||
|
$else
|
||||||
|
nextcase;
|
||||||
|
$endif
|
||||||
|
default:
|
||||||
|
assert(false, "Unsuported size (%d) for atomic_compare_exchange", size);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
@@ -199,7 +199,7 @@ INLINE void llvm_emit_atomic_fetch(GenContext *c, BuiltinFunction func, BEValue
|
|||||||
op = is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd;
|
op = is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd;
|
||||||
break;
|
break;
|
||||||
case BUILTIN_ATOMIC_FETCH_SUB:
|
case BUILTIN_ATOMIC_FETCH_SUB:
|
||||||
op = is_float ? LLVMAtomicRMWBinOpFAdd : LLVMAtomicRMWBinOpAdd;
|
op = is_float ? LLVMAtomicRMWBinOpFSub : LLVMAtomicRMWBinOpSub;
|
||||||
break;
|
break;
|
||||||
case BUILTIN_ATOMIC_FETCH_MAX:
|
case BUILTIN_ATOMIC_FETCH_MAX:
|
||||||
op = is_float ? LLVMAtomicRMWBinOpFMax : (is_unsigned ? LLVMAtomicRMWBinOpUMax : LLVMAtomicRMWBinOpMax);
|
op = is_float ? LLVMAtomicRMWBinOpFMax : (is_unsigned ? LLVMAtomicRMWBinOpUMax : LLVMAtomicRMWBinOpMax);
|
||||||
|
|||||||
Reference in New Issue
Block a user