Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2314)

Unified Diff: src/IceTargetLoweringX8632.cpp

Issue 342763004: Add atomic load/store, fetch_add, fence, and is-lock-free lowering. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: beef up test a bit Created 6 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: src/IceTargetLoweringX8632.cpp
diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp
index 449e41378df44a6f5a0e5c23fd4fc5fc8d903966..212bfec2658c8acff360c06c73e99de699416dd7 100644
--- a/src/IceTargetLoweringX8632.cpp
+++ b/src/IceTargetLoweringX8632.cpp
@@ -1600,7 +1600,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
Variable *Spill = Func->makeVariable(IceType_f64, Context.getNode());
Spill->setWeight(RegWeight::Zero);
Spill->setPreferredRegister(llvm::dyn_cast<Variable>(Src0RM), true);
- _mov(Spill, Src0RM);
+ _movq(Spill, Src0RM);
Variable *DestLo = llvm::cast<Variable>(loOperand(Dest));
Variable *DestHi = llvm::cast<Variable>(hiOperand(Dest));
@@ -1640,7 +1640,7 @@ void TargetX8632::lowerCast(const InstCast *Inst) {
_store(T_Lo, SpillLo);
_mov(T_Hi, hiOperand(Src0RM));
_store(T_Hi, SpillHi);
- _mov(Dest, Spill);
+ _movq(Dest, Spill);
} break;
}
break;
@@ -1781,12 +1781,97 @@ void TargetX8632::lowerIcmp(const InstIcmp *Inst) {
void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
switch (Instr->getIntrinsicInfo().ID) {
case Intrinsics::AtomicCmpxchg:
+ if (!Intrinsics::VerifyMemoryOrder(
+ llvm::cast<ConstantInteger>(Instr->getArg(3))->getValue())) {
+ Func->setError("Unexpected memory order for AtomicCmpxchg");
+ return;
+ }
+ Func->setError("Unhandled intrinsic");
+ return;
case Intrinsics::AtomicFence:
+ if (!Intrinsics::VerifyMemoryOrder(
+ llvm::cast<ConstantInteger>(Instr->getArg(0))->getValue())) {
+ Func->setError("Unexpected memory order for AtomicFence");
+ return;
+ }
+ _mfence();
+ return;
case Intrinsics::AtomicFenceAll:
- case Intrinsics::AtomicIsLockFree:
- case Intrinsics::AtomicLoad:
+ _mfence();
+ return;
+ case Intrinsics::AtomicIsLockFree: {
+ Constant *One = Ctx->getConstantInt(IceType_i32, 1);
+ Variable *Dest = Instr->getDest();
+ _mov(Dest, One);
+ return;
+ }
+ case Intrinsics::AtomicLoad: {
+ // We require the memory address to be naturally aligned.
+ // Given that is the case, then normal loads are atomic.
+ if (!Intrinsics::VerifyMemoryOrder(
+ llvm::cast<ConstantInteger>(Instr->getArg(1))->getValue())) {
+ Func->setError("Unexpected memory ordering for AtomicLoad");
+ return;
+ }
+ Variable *Dest = Instr->getDest();
+ if (Dest->getType() == IceType_i64) {
+ // Follow what GCC does and use a movq instead of what lowerLoad()
+ // normally does (split the load into two).
+ // Thus, this skips load/arithmetic op folding. Load/arithmetic folding
+ // can't happen anyway, since this is x86-32 and integer arithmetic only
+ // happens on 32-bit quantities.
+ Variable *T = makeReg(IceType_f64);
+ OperandX8632Mem *Addr = FormMemoryOperand(Instr->getArg(0), IceType_f64);
+ _movq(T, Addr);
+ // Then cast the bits back out of the XMM register to the i64 Dest.
+ InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, Dest, T);
+ lowerCast(Cast);
+ return;
+ }
+ InstLoad *Load = InstLoad::create(Func, Instr->getDest(), Instr->getArg(0));
+ lowerLoad(Load);
+ return;
+ }
case Intrinsics::AtomicRMW:
- case Intrinsics::AtomicStore:
+ if (!Intrinsics::VerifyMemoryOrder(
+ llvm::cast<ConstantInteger>(Instr->getArg(3))->getValue())) {
+ Func->setError("Unexpected memory ordering for AtomicRMW");
+ return;
+ }
+ lowerAtomicRMW(Instr->getDest(),
+ llvm::cast<ConstantInteger>(Instr->getArg(0))->getValue(),
+ Instr->getArg(1), Instr->getArg(2));
+ return;
+ case Intrinsics::AtomicStore: {
+ if (!Intrinsics::VerifyMemoryOrder(
+ llvm::cast<ConstantInteger>(Instr->getArg(2))->getValue())) {
+ Func->setError("Unexpected memory ordering for AtomicStore");
+ return;
+ }
+ // We require the memory address to be naturally aligned.
+ // Given that is the case, then normal stores are atomic.
+ // Add a fence after the store to make it visible.
+ Operand *Value = Instr->getArg(0);
+ Operand *Ptr = Instr->getArg(1);
+ if (Value->getType() == IceType_i64) {
+ // Use a movq instead of what lowerStore() normally does
+ // (split the store into two), following what GCC does.
+ // Cast the bits from int -> to an xmm register first.
+ Variable *T = makeReg(IceType_f64);
+ InstCast *Cast = InstCast::create(Func, InstCast::Bitcast, T, Value);
+ lowerCast(Cast);
+ // Then store XMM w/ a movq.
+ OperandX8632Mem *Addr = FormMemoryOperand(Ptr, IceType_f64);
+ Addr = llvm::cast<OperandX8632Mem>(legalize(Addr));
+ _storeq(T, Addr);
+ _mfence();
+ return;
+ }
+ InstStore *Store = InstStore::create(Func, Value, Ptr);
+ lowerStore(Store);
+ _mfence();
+ return;
+ }
case Intrinsics::Bswap:
case Intrinsics::Ctlz:
case Intrinsics::Ctpop:
@@ -1798,7 +1883,7 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Call->addArg(Instr->getArg(0));
Call->addArg(Instr->getArg(1));
lowerCall(Call);
- break;
+ return;
}
case Intrinsics::Memcpy: {
// In the future, we could potentially emit an inline memcpy/memset, etc.
@@ -1808,7 +1893,7 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Call->addArg(Instr->getArg(1));
Call->addArg(Instr->getArg(2));
lowerCall(Call);
- break;
+ return;
}
case Intrinsics::Memmove: {
InstCall *Call = makeHelperCall("memmove", NULL, 3);
@@ -1816,7 +1901,7 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Call->addArg(Instr->getArg(1));
Call->addArg(Instr->getArg(2));
lowerCall(Call);
- break;
+ return;
}
case Intrinsics::Memset: {
// The value operand needs to be extended to a stack slot size
@@ -1830,23 +1915,23 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
Call->addArg(ValExt);
Call->addArg(Instr->getArg(2));
lowerCall(Call);
- break;
+ return;
}
case Intrinsics::NaClReadTP: {
- Constant *Zero = Ctx->getConstantInt(IceType_i32, 0);
+ Constant *Zero = Ctx->getConstantZero(IceType_i32);
Operand *Src = OperandX8632Mem::create(Func, IceType_i32, NULL, Zero, NULL,
0, OperandX8632Mem::SegReg_GS);
Variable *Dest = Instr->getDest();
Variable *T = NULL;
_mov(T, Src);
_mov(Dest, T);
- break;
+ return;
}
case Intrinsics::Setjmp: {
InstCall *Call = makeHelperCall("setjmp", Instr->getDest(), 1);
Call->addArg(Instr->getArg(0));
lowerCall(Call);
- break;
+ return;
}
case Intrinsics::Sqrt:
case Intrinsics::Stacksave:
@@ -1855,7 +1940,7 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
return;
case Intrinsics::Trap:
_ud2();
- break;
+ return;
case Intrinsics::UnknownIntrinsic:
Func->setError("Should not be lowering UnknownIntrinsic");
return;
@@ -1863,6 +1948,48 @@ void TargetX8632::lowerIntrinsicCall(const InstIntrinsicCall *Instr) {
return;
}
+void TargetX8632::lowerAtomicRMW(Variable *Dest, uint32_t Operation,
+ Operand *Ptr, Operand *Val) {
+ switch (Operation) {
+ default:
+ Func->setError("Unknown AtomicRMW operation");
+ return;
+ case Intrinsics::AtomicAdd: {
+ if (Dest->getType() == IceType_i64) {
+ // Do a nasty cmpxchg8b loop. Factor this into a function.
+ Func->setError("Unhandled AtomicRMW operation");
+ return;
+ }
+ // Generate a memory operand from Ptr.
+ OperandX8632Mem *Addr = FormMemoryOperand(Ptr, Dest->getType());
+ const bool Locked = true;
+ Variable *T = NULL;
+ _mov(T, Val);
+ _xadd(Addr, T, Locked);
+ Context.insert(InstFakeDef::create(Func, T));
+ _mov(Dest, T);
+ break;
+ }
+ case Intrinsics::AtomicSub: {
+ if (Dest->getType() == IceType_i64) {
+ // Do a nasty cmpxchg8b loop.
+ Func->setError("Unhandled AtomicRMW operation");
+ return;
+ }
+ // Generate a memory operand from Ptr.
+ // neg...
+ // Then do the same as AtomicAdd.
+ break;
+ }
+ case Intrinsics::AtomicOr:
+ case Intrinsics::AtomicAnd:
+ case Intrinsics::AtomicXor:
+ case Intrinsics::AtomicExchange:
+ Func->setError("Unhandled AtomicRMW operation");
+ return;
+ }
+}
+
namespace {
bool isAdd(const Inst *Inst) {
@@ -1999,15 +2126,7 @@ void TargetX8632::lowerLoad(const InstLoad *Inst) {
// optimization already creates an OperandX8632Mem operand, so it
// doesn't need another level of transformation.
Type Ty = Inst->getDest()->getType();
- Operand *Src0 = Inst->getSourceAddress();
- // Address mode optimization already creates an OperandX8632Mem
- // operand, so it doesn't need another level of transformation.
- if (!llvm::isa<OperandX8632Mem>(Src0)) {
- Variable *Base = llvm::dyn_cast<Variable>(Src0);
- Constant *Offset = llvm::dyn_cast<Constant>(Src0);
- assert(Base || Offset);
- Src0 = OperandX8632Mem::create(Func, Ty, Base, Offset);
- }
+ Operand *Src0 = FormMemoryOperand(Inst->getSourceAddress(), Ty);
// Fuse this load with a subsequent Arithmetic instruction in the
// following situations:
@@ -2145,18 +2264,7 @@ void TargetX8632::lowerSelect(const InstSelect *Inst) {
void TargetX8632::lowerStore(const InstStore *Inst) {
Operand *Value = Inst->getData();
Operand *Addr = Inst->getAddr();
- OperandX8632Mem *NewAddr = llvm::dyn_cast<OperandX8632Mem>(Addr);
- // Address mode optimization already creates an OperandX8632Mem
- // operand, so it doesn't need another level of transformation.
- if (!NewAddr) {
- // The address will be either a constant (which represents a global
- // variable) or a variable, so either the Base or Offset component
- // of the OperandX8632Mem will be set.
- Variable *Base = llvm::dyn_cast<Variable>(Addr);
- Constant *Offset = llvm::dyn_cast<Constant>(Addr);
- assert(Base || Offset);
- NewAddr = OperandX8632Mem::create(Func, Value->getType(), Base, Offset);
- }
+ OperandX8632Mem *NewAddr = FormMemoryOperand(Addr, Value->getType());
NewAddr = llvm::cast<OperandX8632Mem>(legalize(NewAddr));
if (NewAddr->getType() == IceType_i64) {
@@ -2275,10 +2383,11 @@ Operand *TargetX8632::legalize(Operand *From, LegalMask Allowed,
// need to go in uninitialized registers.
From = Ctx->getConstantZero(From->getType());
}
- bool NeedsReg = !(Allowed & Legal_Imm) ||
+ bool NeedsReg =
+ !(Allowed & Legal_Imm) ||
// ConstantFloat and ConstantDouble are actually memory operands.
- (!(Allowed & Legal_Mem) && (From->getType() == IceType_f32 ||
- From->getType() == IceType_f64));
+ (!(Allowed & Legal_Mem) &&
+ (From->getType() == IceType_f32 || From->getType() == IceType_f64));
if (NeedsReg) {
Variable *Reg = makeReg(From->getType(), RegNum);
_mov(Reg, From);
@@ -2311,6 +2420,20 @@ Variable *TargetX8632::legalizeToVar(Operand *From, bool AllowOverlap,
return llvm::cast<Variable>(legalize(From, Legal_Reg, AllowOverlap, RegNum));
}
+OperandX8632Mem *TargetX8632::FormMemoryOperand(Operand *Operand, Type Ty) {
+ OperandX8632Mem *Mem = llvm::dyn_cast<OperandX8632Mem>(Operand);
+ // It may be the case that address mode optimization already creates
+ // an OperandX8632Mem, so in that case it wouldn't need another level
+ // of transformation.
+ if (!Mem) {
+ Variable *Base = llvm::dyn_cast<Variable>(Operand);
+ Constant *Offset = llvm::dyn_cast<Constant>(Operand);
+ assert(Base || Offset);
+ Mem = OperandX8632Mem::create(Func, Ty, Base, Offset);
+ }
+ return Mem;
+}
+
Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) {
Variable *Reg = Func->makeVariable(Type, Context.getNode());
if (RegNum == Variable::NoRegister)

Powered by Google App Engine
This is Rietveld 408576698