Chromium Code Reviews| Index: src/IceTargetLoweringX8632.cpp |
| diff --git a/src/IceTargetLoweringX8632.cpp b/src/IceTargetLoweringX8632.cpp |
| index 449e41378df44a6f5a0e5c23fd4fc5fc8d903966..d6e6f08ee8914e71dbaf4e435dcc69b507d6efef 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,16 +1781,108 @@ 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; |
| + } |
| + // TODO(jvoung): fill it in. |
| + 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(); |
|
JF
2014/06/24 01:23:29
FenceAll is meant as an equivalent to asm(:::"m"),
jvoung (off chromium)
2014/06/24 21:16:55
Added a comment, and a couple of speculative tests
|
| + return; |
| + case Intrinsics::AtomicIsLockFree: { |
| + Constant *One = Ctx->getConstantInt(IceType_i32, 1); |
|
JF
2014/06/24 01:23:29
It would be good to explain that x86 is always loc
jvoung (off chromium)
2014/06/24 21:16:55
iOn 2014/06/24 01:23:29, JF wrote:
|
| + 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); |
| + // Make sure that the atomic load isn't elided. |
| + Context.insert(InstFakeUse::create(Func, Dest->getLo())); |
| + Context.insert(InstFakeUse::create(Func, Dest->getHi())); |
| + return; |
| + } |
| + InstLoad *Load = InstLoad::create(Func, Dest, Instr->getArg(0)); |
| + lowerLoad(Load); |
| + // Make sure the atomic load isn't elided. |
| + Context.insert(InstFakeUse::create(Func, Dest)); |
| + 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(), |
| + static_cast<uint32_t>(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); |
| + _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: |
| case Intrinsics::Cttz: |
| + // TODO(jvoung): fill it in. |
| Func->setError("Unhandled intrinsic"); |
| return; |
| case Intrinsics::Longjmp: { |
| @@ -1798,7 +1890,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 +1900,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 +1908,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,32 +1922,33 @@ 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: |
| case Intrinsics::Stackrestore: |
| + // TODO(jvoung): fill it in. |
| Func->setError("Unhandled intrinsic"); |
| return; |
| case Intrinsics::Trap: |
| _ud2(); |
| - break; |
| + return; |
| case Intrinsics::UnknownIntrinsic: |
| Func->setError("Should not be lowering UnknownIntrinsic"); |
| return; |
| @@ -1863,6 +1956,51 @@ 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. |
| + // TODO(jvoung): fill it in. |
| + Func->setError("Unhandled AtomicRMW operation"); |
| + return; |
| + } |
| + OperandX8632Mem *Addr = FormMemoryOperand(Ptr, Dest->getType()); |
| + const bool Locked = true; |
| + Variable *T = NULL; |
| + _mov(T, Val); |
| + _xadd(Addr, T, Locked); |
| + _mov(Dest, T); |
| + return; |
| + } |
| + case Intrinsics::AtomicSub: { |
| + if (Dest->getType() == IceType_i64) { |
| + // Do a nasty cmpxchg8b loop. |
| + // TODO(jvoung): fill it in. |
| + Func->setError("Unhandled AtomicRMW operation"); |
| + return; |
| + } |
| + // Generate a memory operand from Ptr. |
| + // neg... |
| + // Then do the same as AtomicAdd. |
| + // TODO(jvoung): fill it in. |
| + Func->setError("Unhandled AtomicRMW operation"); |
| + return; |
| + } |
| + case Intrinsics::AtomicOr: |
| + case Intrinsics::AtomicAnd: |
| + case Intrinsics::AtomicXor: |
| + case Intrinsics::AtomicExchange: |
| + // TODO(jvoung): fill it in. |
| + Func->setError("Unhandled AtomicRMW operation"); |
| + return; |
| + } |
| +} |
| + |
| namespace { |
| bool isAdd(const Inst *Inst) { |
| @@ -1999,15 +2137,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,19 +2275,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); |
| - } |
| - NewAddr = llvm::cast<OperandX8632Mem>(legalize(NewAddr)); |
| + OperandX8632Mem *NewAddr = FormMemoryOperand(Addr, Value->getType()); |
| if (NewAddr->getType() == IceType_i64) { |
| Value = legalize(Value); |
| @@ -2275,10 +2393,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 +2430,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 llvm::cast<OperandX8632Mem>(legalize(Mem)); |
| +} |
| + |
| Variable *TargetX8632::makeReg(Type Type, int32_t RegNum) { |
| Variable *Reg = Func->makeVariable(Type, Context.getNode()); |
| if (RegNum == Variable::NoRegister) |