Subzero: lower the rest of the atomic operations.
64-bit ops are expanded via a cmpxchg8b loop.
64/32-bit and/or/xor are also expanded into a cmpxchg /
cmpxchg8b loop.
Add a cross test for atomic RMW operations and
compare and swap.
Misc: Test that atomic.is.lock.free can be optimized out if result is ignored.
TODO:
* optimize compare and swap with compare+branch further down
instruction stream.
* optimize atomic RMW when the return value is ignored
(adds a locked field to binary ops though).
* We may want to do some actual target-dependent basic
block splitting + expansion (the instructions inserted by
the expansion must reference the pre-colored registers,
etc.). Otherwise, we are currently getting by with modeling
the extended liveness of the variables used in the loops
using fake uses.
BUG= https://code.google.com/p/nativeclient/issues/detail?id=3882
R=jfb@chromium.org, stichnot@chromium.org
Review URL: https://codereview.chromium.org/362463002
diff --git a/src/IceInstX8632.cpp b/src/IceInstX8632.cpp
index cd5095f..c0e8c8d 100644
--- a/src/IceInstX8632.cpp
+++ b/src/IceInstX8632.cpp
@@ -51,9 +51,8 @@
llvm::array_lengthof(TypeX8632Attributes);
const char *InstX8632SegmentRegNames[] = {
-#define X(val, name) \
- name,
- SEG_REGX8632_TABLE
+#define X(val, name) name,
+ SEG_REGX8632_TABLE
#undef X
};
const size_t InstX8632SegmentRegNamesSize =
@@ -140,6 +139,33 @@
addSource(Source);
}
+InstX8632Cmpxchg::InstX8632Cmpxchg(Cfg *Func, Operand *DestOrAddr,
+ Variable *Eax, Variable *Desired,
+ bool Locked)
+ : InstX8632Lockable(Func, InstX8632::Cmpxchg, 3,
+ llvm::dyn_cast<Variable>(DestOrAddr), Locked) {
+ assert(Eax->getRegNum() == TargetX8632::Reg_eax);
+ addSource(DestOrAddr);
+ addSource(Eax);
+ addSource(Desired);
+}
+
+InstX8632Cmpxchg8b::InstX8632Cmpxchg8b(Cfg *Func, OperandX8632 *Addr,
+ Variable *Edx, Variable *Eax,
+ Variable *Ecx, Variable *Ebx,
+ bool Locked)
+ : InstX8632Lockable(Func, InstX8632::Cmpxchg, 5, NULL, Locked) {
+ assert(Edx->getRegNum() == TargetX8632::Reg_edx);
+ assert(Eax->getRegNum() == TargetX8632::Reg_eax);
+ assert(Ecx->getRegNum() == TargetX8632::Reg_ecx);
+ assert(Ebx->getRegNum() == TargetX8632::Reg_ebx);
+ addSource(Addr);
+ addSource(Edx);
+ addSource(Eax);
+ addSource(Ecx);
+ addSource(Ebx);
+}
+
InstX8632Cvt::InstX8632Cvt(Cfg *Func, Variable *Dest, Operand *Source)
: InstX8632(Func, InstX8632::Cvt, 1, Dest) {
addSource(Source);
@@ -284,9 +310,14 @@
InstX8632Xadd::InstX8632Xadd(Cfg *Func, Operand *Dest, Variable *Source,
bool Locked)
- : InstX8632(Func, InstX8632::Xadd, 2, llvm::dyn_cast<Variable>(Dest)),
- Locked(Locked) {
- HasSideEffects = Locked;
+ : InstX8632Lockable(Func, InstX8632::Xadd, 2,
+ llvm::dyn_cast<Variable>(Dest), Locked) {
+ addSource(Dest);
+ addSource(Source);
+}
+
+InstX8632Xchg::InstX8632Xchg(Cfg *Func, Operand *Dest, Variable *Source)
+ : InstX8632(Func, InstX8632::Xchg, 2, llvm::dyn_cast<Variable>(Dest)) {
addSource(Dest);
addSource(Source);
}
@@ -398,6 +429,7 @@
Str << "\n";
}
+template <> const char *InstX8632Neg::Opcode = "neg";
template <> const char *InstX8632Add::Opcode = "add";
template <> const char *InstX8632Addps::Opcode = "addps";
template <> const char *InstX8632Adc::Opcode = "adc";
@@ -554,6 +586,48 @@
dumpSources(Func);
}
+void InstX8632Cmpxchg::emit(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrEmit();
+ assert(getSrcSize() == 3);
+ if (Locked) {
+ Str << "\tlock";
+ }
+ Str << "\tcmpxchg\t";
+ getSrc(0)->emit(Func);
+ Str << ", ";
+ getSrc(2)->emit(Func);
+ Str << "\n";
+}
+
+void InstX8632Cmpxchg::dump(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrDump();
+ if (Locked) {
+ Str << "lock ";
+ }
+ Str << "cmpxchg." << getSrc(0)->getType() << " ";
+ dumpSources(Func);
+}
+
+void InstX8632Cmpxchg8b::emit(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrEmit();
+ assert(getSrcSize() == 5);
+ if (Locked) {
+ Str << "\tlock";
+ }
+ Str << "\tcmpxchg8b\t";
+ getSrc(0)->emit(Func);
+ Str << "\n";
+}
+
+void InstX8632Cmpxchg8b::dump(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrDump();
+ if (Locked) {
+ Str << "lock ";
+ }
+ Str << "cmpxchg8b ";
+ dumpSources(Func);
+}
+
void InstX8632Cvt::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
assert(getSrcSize() == 1);
@@ -955,10 +1029,9 @@
void InstX8632Xadd::emit(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrEmit();
if (Locked) {
- Str << "\tlock xadd ";
- } else {
- Str << "\txadd\t";
+ Str << "\tlock";
}
+ Str << "\txadd\t";
getSrc(0)->emit(Func);
Str << ", ";
getSrc(1)->emit(Func);
@@ -975,6 +1048,22 @@
dumpSources(Func);
}
+void InstX8632Xchg::emit(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrEmit();
+ Str << "\txchg\t";
+ getSrc(0)->emit(Func);
+ Str << ", ";
+ getSrc(1)->emit(Func);
+ Str << "\n";
+}
+
+void InstX8632Xchg::dump(const Cfg *Func) const {
+ Ostream &Str = Func->getContext()->getStrDump();
+ Type Ty = getSrc(0)->getType();
+ Str << "xchg." << Ty << " ";
+ dumpSources(Func);
+}
+
void OperandX8632::dump(const Cfg *Func) const {
Ostream &Str = Func->getContext()->getStrDump();
Str << "<OperandX8632>";