NFC: unify clang / LLVM atomic ordering

This makes the C11 / C++11 *ABI* atomic ordering accessible from LLVM,
as discussed in http://reviews.llvm.org/D18200#inline-151433

This re-applies r266573 which I had reverted in r266576.

Original review: http://reviews.llvm.org/D18875

llvm-svn: 266640
This commit is contained in:
JF Bastien 2016-04-18 18:01:43 +00:00
parent b7fd9fa5e2
commit bbb0aee66e
3 changed files with 160 additions and 118 deletions

View File

@ -25,6 +25,7 @@
#include "llvm/IR/DerivedTypes.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/InstrTypes.h"
#include "llvm/Support/AtomicOrdering.h"
#include "llvm/Support/ErrorHandling.h"
#include <iterator>
@ -36,91 +37,11 @@ class ConstantRange;
class DataLayout;
class LLVMContext;
/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
/// Unordered, which are both below the C++ orders. See docs/Atomics.rst for
/// details.
///
/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
/// \-->consume-->acquire--/
enum class AtomicOrdering {
NotAtomic = 0,
Unordered = 1,
Monotonic = 2, // Equivalent to C++'s relaxed.
// Consume = 3, // Not specified yet.
Acquire = 4,
Release = 5,
AcquireRelease = 6,
SequentiallyConsistent = 7
};
bool operator<(AtomicOrdering, AtomicOrdering) = delete;
bool operator>(AtomicOrdering, AtomicOrdering) = delete;
bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
/// String used by LLVM IR to represent atomic ordering.
static inline const char *toIRString(AtomicOrdering ao) {
static const char *names[8] = {"not_atomic", "unordered", "monotonic",
"consume", "acquire", "release",
"acq_rel", "seq_cst"};
return names[(size_t)ao];
}
/// Returns true if ao is stronger than other as defined by the AtomicOrdering
/// lattice, which is based on C++'s definition.
static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ {0, 0, 0, 0, 0, 0, 0, 0},
/* Unordered */ {1, 0, 0, 0, 0, 0, 0, 0},
/* relaxed */ {1, 1, 0, 0, 0, 0, 0, 0},
/* consume */ {1, 1, 1, 0, 0, 0, 0, 0},
/* acquire */ {1, 1, 1, 1, 0, 0, 0, 0},
/* release */ {1, 1, 1, 0, 0, 0, 0, 0},
/* acq_rel */ {1, 1, 1, 1, 1, 1, 0, 0},
/* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 0},
};
return lookup[(size_t)ao][(size_t)other];
}
static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao,
AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ {1, 0, 0, 0, 0, 0, 0, 0},
/* Unordered */ {1, 1, 0, 0, 0, 0, 0, 0},
/* relaxed */ {1, 1, 1, 0, 0, 0, 0, 0},
/* consume */ {1, 1, 1, 1, 0, 0, 0, 0},
/* acquire */ {1, 1, 1, 1, 1, 0, 0, 0},
/* release */ {1, 1, 1, 0, 0, 1, 0, 0},
/* acq_rel */ {1, 1, 1, 1, 1, 1, 1, 0},
/* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 1},
};
return lookup[(size_t)ao][(size_t)other];
}
static inline bool isStrongerThanUnordered(AtomicOrdering Ord) {
return isStrongerThan(Ord, AtomicOrdering::Unordered);
}
static inline bool isStrongerThanMonotonic(AtomicOrdering Ord) {
return isStrongerThan(Ord, AtomicOrdering::Monotonic);
}
static inline bool isAcquireOrStronger(AtomicOrdering Ord) {
return isAtLeastOrStrongerThan(Ord, AtomicOrdering::Acquire);
}
static inline bool isReleaseOrStronger(AtomicOrdering Ord) {
return isAtLeastOrStrongerThan(Ord, AtomicOrdering::Release);
}
enum SynchronizationScope {
SingleThread = 0,
CrossThread = 1
};
//===----------------------------------------------------------------------===//
// AllocaInst Class
//===----------------------------------------------------------------------===//

View File

@ -0,0 +1,151 @@
//===-- llvm/Support/AtomicOrdering.h ---Atomic Ordering---------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// \brief Atomic ordering constants.
///
/// These values are used by LLVM to represent atomic ordering for C++11's
/// memory model and more, as detailed in docs/Atomics.rst.
///
//===----------------------------------------------------------------------===//
#ifndef LLVM_SUPPORT_ATOMICORDERING_H
#define LLVM_SUPPORT_ATOMICORDERING_H
namespace llvm {
/// Atomic ordering for C11 / C++11's memody models.
///
/// These values cannot change because they are shared with standard library
/// implementations as well as with other compilers.
enum class AtomicOrderingCABI {
relaxed = 0,
consume = 1,
acquire = 2,
release = 3,
acq_rel = 4,
seq_cst = 5,
};
bool operator<(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
bool operator>(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
bool operator<=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
bool operator>=(AtomicOrderingCABI, AtomicOrderingCABI) = delete;
// Validate an integral value which isn't known to fit within the enum's range
// is a valid AtomicOrderingCABI.
template <typename Int> static inline bool isValidAtomicOrderingCABI(Int I) {
return (Int)AtomicOrderingCABI::relaxed <= I &&
I <= (Int)AtomicOrderingCABI::seq_cst;
}
/// Atomic ordering for LLVM's memory model.
///
/// C++ defines ordering as a lattice. LLVM supplements this with NotAtomic and
/// Unordered, which are both below the C++ orders.
///
/// not_atomic-->unordered-->relaxed-->release--------------->acq_rel-->seq_cst
/// \-->consume-->acquire--/
enum class AtomicOrdering {
NotAtomic = 0,
Unordered = 1,
Monotonic = 2, // Equivalent to C++'s relaxed.
// Consume = 3, // Not specified yet.
Acquire = 4,
Release = 5,
AcquireRelease = 6,
SequentiallyConsistent = 7
};
bool operator<(AtomicOrdering, AtomicOrdering) = delete;
bool operator>(AtomicOrdering, AtomicOrdering) = delete;
bool operator<=(AtomicOrdering, AtomicOrdering) = delete;
bool operator>=(AtomicOrdering, AtomicOrdering) = delete;
// Validate an integral value which isn't known to fit within the enum's range
// is a valid AtomicOrdering.
template <typename Int> static inline bool isValidAtomicOrdering(Int I) {
return (Int)AtomicOrdering::NotAtomic <= I &&
I <= (Int)AtomicOrdering::SequentiallyConsistent;
}
/// String used by LLVM IR to represent atomic ordering.
static inline const char *toIRString(AtomicOrdering ao) {
static const char *names[8] = {"not_atomic", "unordered", "monotonic",
"consume", "acquire", "release",
"acq_rel", "seq_cst"};
return names[(size_t)ao];
}
/// Returns true if ao is stronger than other as defined by the AtomicOrdering
/// lattice, which is based on C++'s definition.
static inline bool isStrongerThan(AtomicOrdering ao, AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ {0, 0, 0, 0, 0, 0, 0, 0},
/* Unordered */ {1, 0, 0, 0, 0, 0, 0, 0},
/* relaxed */ {1, 1, 0, 0, 0, 0, 0, 0},
/* consume */ {1, 1, 1, 0, 0, 0, 0, 0},
/* acquire */ {1, 1, 1, 1, 0, 0, 0, 0},
/* release */ {1, 1, 1, 0, 0, 0, 0, 0},
/* acq_rel */ {1, 1, 1, 1, 1, 1, 0, 0},
/* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 0},
};
return lookup[(size_t)ao][(size_t)other];
}
static inline bool isAtLeastOrStrongerThan(AtomicOrdering ao,
AtomicOrdering other) {
static const bool lookup[8][8] = {
// NA UN RX CO AC RE AR SC
/* NotAtomic */ {1, 0, 0, 0, 0, 0, 0, 0},
/* Unordered */ {1, 1, 0, 0, 0, 0, 0, 0},
/* relaxed */ {1, 1, 1, 0, 0, 0, 0, 0},
/* consume */ {1, 1, 1, 1, 0, 0, 0, 0},
/* acquire */ {1, 1, 1, 1, 1, 0, 0, 0},
/* release */ {1, 1, 1, 0, 0, 1, 0, 0},
/* acq_rel */ {1, 1, 1, 1, 1, 1, 1, 0},
/* seq_cst */ {1, 1, 1, 1, 1, 1, 1, 1},
};
return lookup[(size_t)ao][(size_t)other];
}
static inline bool isStrongerThanUnordered(AtomicOrdering ao) {
return isStrongerThan(ao, AtomicOrdering::Unordered);
}
static inline bool isStrongerThanMonotonic(AtomicOrdering ao) {
return isStrongerThan(ao, AtomicOrdering::Monotonic);
}
static inline bool isAcquireOrStronger(AtomicOrdering ao) {
return isAtLeastOrStrongerThan(ao, AtomicOrdering::Acquire);
}
static inline bool isReleaseOrStronger(AtomicOrdering ao) {
return isAtLeastOrStrongerThan(ao, AtomicOrdering::Release);
}
static inline AtomicOrderingCABI toCABI(AtomicOrdering ao) {
static const AtomicOrderingCABI lookup[8] = {
/* NotAtomic */ AtomicOrderingCABI::relaxed,
/* Unordered */ AtomicOrderingCABI::relaxed,
/* relaxed */ AtomicOrderingCABI::relaxed,
/* consume */ AtomicOrderingCABI::consume,
/* acquire */ AtomicOrderingCABI::acquire,
/* release */ AtomicOrderingCABI::release,
/* acq_rel */ AtomicOrderingCABI::acq_rel,
/* seq_cst */ AtomicOrderingCABI::seq_cst,
};
return lookup[(size_t)ao];
}
} // End namespace llvm
#endif

View File

@ -937,39 +937,6 @@ bool llvm::expandAtomicRMWToCmpXchg(AtomicRMWInst *AI,
return true;
}
// This converts from LLVM's internal AtomicOrdering enum to the
// memory_order_* value required by the __atomic_* libcalls.
static int libcallAtomicModel(AtomicOrdering AO) {
enum {
AO_ABI_memory_order_relaxed = 0,
AO_ABI_memory_order_consume = 1,
AO_ABI_memory_order_acquire = 2,
AO_ABI_memory_order_release = 3,
AO_ABI_memory_order_acq_rel = 4,
AO_ABI_memory_order_seq_cst = 5
};
switch (AO) {
case AtomicOrdering::NotAtomic:
llvm_unreachable("Expected atomic memory order.");
case AtomicOrdering::Unordered:
case AtomicOrdering::Monotonic:
return AO_ABI_memory_order_relaxed;
// Not implemented yet in llvm:
// case AtomicOrdering::Consume:
// return AO_ABI_memory_order_consume;
case AtomicOrdering::Acquire:
return AO_ABI_memory_order_acquire;
case AtomicOrdering::Release:
return AO_ABI_memory_order_release;
case AtomicOrdering::AcquireRelease:
return AO_ABI_memory_order_acq_rel;
case AtomicOrdering::SequentiallyConsistent:
return AO_ABI_memory_order_seq_cst;
}
llvm_unreachable("Unknown atomic memory order.");
}
// In order to use one of the sized library calls such as
// __atomic_fetch_add_4, the alignment must be sufficient, the size
// must be one of the potentially-specialized sizes, and the value
@ -1151,12 +1118,15 @@ bool AtomicExpand::expandAtomicOpToLibcall(
// TODO: the "order" argument type is "int", not int32. So
// getInt32Ty may be wrong if the arch uses e.g. 16-bit ints.
ConstantInt *SizeVal64 = ConstantInt::get(Type::getInt64Ty(Ctx), Size);
assert(Ordering != AtomicOrdering::NotAtomic && "expect atomic MO");
Constant *OrderingVal =
ConstantInt::get(Type::getInt32Ty(Ctx), libcallAtomicModel(Ordering));
Constant *Ordering2Val = CASExpected
? ConstantInt::get(Type::getInt32Ty(Ctx),
libcallAtomicModel(Ordering2))
: nullptr;
ConstantInt::get(Type::getInt32Ty(Ctx), (int)toCABI(Ordering));
Constant *Ordering2Val = nullptr;
if (CASExpected) {
assert(Ordering2 != AtomicOrdering::NotAtomic && "expect atomic MO");
Ordering2Val =
ConstantInt::get(Type::getInt32Ty(Ctx), (int)toCABI(Ordering2));
}
bool HasResult = I->getType() != Type::getVoidTy(Ctx);
RTLIB::Libcall RTLibType;