Chromium Code Reviews| Index: src/IceTargetLoweringARM32.cpp |
| diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp |
| index 0b12bc6a8a60d4c776dfd2bd4e92d2445a83189f..e042b1958e169707f096f338bfe3ff83eaf083c4 100644 |
| --- a/src/IceTargetLoweringARM32.cpp |
| +++ b/src/IceTargetLoweringARM32.cpp |
| @@ -385,7 +385,8 @@ void copyRegAllocFromInfWeightVariable64On32(const VarList &Vars) { |
| // This is not the variable we are looking for. |
| continue; |
| } |
| - assert(Var64->hasReg() || !Var64->mustHaveReg()); |
| + // only allow infinite-weight i64 temporaries to be register allocated. |
| + assert(!Var64->hasReg() || Var64->mustHaveReg()); |
| if (!Var64->hasReg()) { |
| continue; |
| } |
| @@ -3408,14 +3409,14 @@ void TargetARM32::lowerAssign(const InstAssign *Instr) { |
| if (Dest->getType() == IceType_i64) { |
| Src0 = legalizeUndef(Src0); |
| - Variable *T_Lo = makeReg(IceType_i32); |
| auto *DestLo = llvm::cast<Variable>(loOperand(Dest)); |
|
Jim Stichnoth
2016/02/17 03:50:17
Just curious - why these changes?
John
2016/02/17 13:01:38
I was fiddling around trying to avoid some unneces
|
| + Variable *T_Lo = makeReg(IceType_i32); |
| Operand *Src0Lo = legalize(loOperand(Src0), Legal_Reg | Legal_Flex); |
| _mov(T_Lo, Src0Lo); |
| _mov(DestLo, T_Lo); |
| - Variable *T_Hi = makeReg(IceType_i32); |
| auto *DestHi = llvm::cast<Variable>(hiOperand(Dest)); |
| + Variable *T_Hi = makeReg(IceType_i32); |
| Operand *Src0Hi = legalize(hiOperand(Src0), Legal_Reg | Legal_Flex); |
| _mov(T_Hi, Src0Hi); |
| _mov(DestHi, T_Hi); |
| @@ -4401,10 +4402,16 @@ TargetARM32::lowerInt8AndInt16IcmpCond(InstIcmp::ICond Condition, Operand *Src0, |
| } |
| TargetARM32::CondWhenTrue TargetARM32::lowerIcmpCond(const InstIcmp *Instr) { |
| - Operand *Src0 = legalizeUndef(Instr->getSrc(0)); |
| - Operand *Src1 = legalizeUndef(Instr->getSrc(1)); |
| + return lowerIcmpCond(Instr->getCondition(), Instr->getSrc(0), |
| + Instr->getSrc(1)); |
| +} |
| + |
| +TargetARM32::CondWhenTrue TargetARM32::lowerIcmpCond(InstIcmp::ICond Condition, |
| + Operand *Src0, |
| + Operand *Src1) { |
| + Src0 = legalizeUndef(Src0); |
| + Src1 = legalizeUndef(Src1); |
| - const InstIcmp::ICond Condition = Instr->getCondition(); |
| // a=icmp cond b, c ==> |
| // GCC does: |
| // <u/s>xtb tb, b |
| @@ -4504,162 +4511,156 @@ inline uint64_t getConstantMemoryOrder(Operand *Opnd) { |
| } |
| } // end of anonymous namespace |
| -void TargetARM32::lowerAtomicRMW(Variable *Dest, uint32_t Operation, |
| - Operand *Ptr, Operand *Val) { |
| - // retry: |
| - // ldrex contents, [addr] |
| - // op tmp, contents, operand |
| - // strex success, tmp, [addr] |
| - // jne retry |
| - // fake-use(addr, operand) @ prevents undesirable clobbering. |
| - // mov dest, contents |
| - assert(Dest != nullptr); |
| - Type DestTy = Dest->getType(); |
| - (void)Ptr; |
| - (void)Val; |
| - |
| - OperandARM32Mem *Mem; |
| - Variable *PtrContentsReg; |
| - Variable *PtrContentsHiReg; |
| - Variable *PtrContentsLoReg; |
| - Variable *Value = Func->makeVariable(DestTy); |
| - Variable *ValueReg; |
| - Variable *ValueHiReg; |
| - Variable *ValueLoReg; |
| - Variable *Success = makeReg(IceType_i32); |
| - Variable *TmpReg; |
| - Variable *TmpHiReg; |
| - Variable *TmpLoReg; |
| - Operand *_0 = Ctx->getConstantZero(IceType_i32); |
| - auto *Retry = InstARM32Label::create(Func, this); |
| - |
| - if (DestTy == IceType_i64) { |
| - Variable64On32 *PtrContentsReg64 = makeI64RegPair(); |
| - PtrContentsHiReg = PtrContentsReg64->getHi(); |
| - PtrContentsLoReg = PtrContentsReg64->getLo(); |
| - PtrContentsReg = PtrContentsReg64; |
| - |
| - llvm::cast<Variable64On32>(Value)->initHiLo(Func); |
| - Variable64On32 *ValueReg64 = makeI64RegPair(); |
| - ValueHiReg = ValueReg64->getHi(); |
| - ValueLoReg = ValueReg64->getLo(); |
| - ValueReg = ValueReg64; |
| - |
| - Variable64On32 *TmpReg64 = makeI64RegPair(); |
| - TmpHiReg = TmpReg64->getHi(); |
| - TmpLoReg = TmpReg64->getLo(); |
| - TmpReg = TmpReg64; |
| - } else { |
| - PtrContentsReg = makeReg(DestTy); |
| - PtrContentsHiReg = nullptr; |
| - PtrContentsLoReg = PtrContentsReg; |
| - |
| - ValueReg = makeReg(DestTy); |
| - ValueHiReg = nullptr; |
| - ValueLoReg = ValueReg; |
| - |
| - TmpReg = makeReg(DestTy); |
| - TmpHiReg = nullptr; |
| - TmpLoReg = TmpReg; |
| - } |
| - |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(Value); |
| +void TargetARM32::lowerLoadLinkedStoreExclusive( |
| + Type Ty, Operand *Addr, std::function<Variable *(Variable *)> Operation, |
| + CondARM32::Cond Cond) { |
| + |
| + auto *Retry = Context.insert<InstARM32Label>(this); |
| + { // scoping for loop highlighting. |
| + Variable *Tmp = (Ty == IceType_i64) ? makeI64RegPair() : makeReg(Ty); |
| + auto *Success = makeReg(IceType_i32); |
| + auto *_0 = Ctx->getConstantZero(IceType_i32); |
| + |
| + Context.insert<InstFakeDef>(Tmp); |
| + Context.insert<InstFakeUse>(Tmp); |
| + Variable *AddrR = legalizeToReg(Addr); |
| + _ldrex(Tmp, formMemoryOperand(AddrR, Ty))->setDestRedefined(); |
| + auto *StoreValue = Operation(Tmp); |
| + assert(StoreValue->mustHaveReg()); |
| + _strex(Success, StoreValue, formMemoryOperand(AddrR, Ty), Cond); |
| + _cmp(Success, _0, Cond); |
| } |
| - lowerAssign(InstAssign::create(Func, Value, Val)); |
| - |
| - Variable *PtrVar = Func->makeVariable(IceType_i32); |
| - lowerAssign(InstAssign::create(Func, PtrVar, Ptr)); |
| - |
| - _dmb(); |
| - Context.insert(Retry); |
| - Mem = formMemoryOperand(PtrVar, DestTy); |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(ValueReg, Value); |
| - } |
| - lowerAssign(InstAssign::create(Func, ValueReg, Value)); |
| - if (DestTy == IceType_i8 || DestTy == IceType_i16) { |
| - _uxt(ValueReg, ValueReg); |
| - } |
| - _ldrex(PtrContentsReg, Mem); |
| + _br(Retry, CondARM32::NE); |
| +} |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(TmpReg, ValueReg); |
| - } |
| +namespace { |
| +InstArithmetic *createArithInst(Cfg *Func, uint32_t Operation, Variable *Dest, |
| + Variable *Src0, Operand *Src1) { |
| + InstArithmetic::OpKind Oper; |
| switch (Operation) { |
| default: |
| - Func->setError("Unknown AtomicRMW operation"); |
| - return; |
| + llvm::report_fatal_error("Unknown AtomicRMW operation"); |
| + case Intrinsics::AtomicExchange: |
| + llvm::report_fatal_error("Can't handle Atomic xchg operation"); |
| case Intrinsics::AtomicAdd: |
| - if (DestTy == IceType_i64) { |
| - _adds(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - _adc(TmpHiReg, PtrContentsHiReg, ValueHiReg); |
| - } else { |
| - _add(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - } |
| + Oper = InstArithmetic::Add; |
| + break; |
| + case Intrinsics::AtomicAnd: |
| + Oper = InstArithmetic::And; |
| break; |
| case Intrinsics::AtomicSub: |
| - if (DestTy == IceType_i64) { |
| - _subs(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - _sbc(TmpHiReg, PtrContentsHiReg, ValueHiReg); |
| - } else { |
| - _sub(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - } |
| + Oper = InstArithmetic::Sub; |
| break; |
| case Intrinsics::AtomicOr: |
| - _orr(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - if (DestTy == IceType_i64) { |
| - _orr(TmpHiReg, PtrContentsHiReg, ValueHiReg); |
| - } |
| - break; |
| - case Intrinsics::AtomicAnd: |
| - _and(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - if (DestTy == IceType_i64) { |
| - _and(TmpHiReg, PtrContentsHiReg, ValueHiReg); |
| - } |
| + Oper = InstArithmetic::Or; |
| break; |
| case Intrinsics::AtomicXor: |
| - _eor(TmpLoReg, PtrContentsLoReg, ValueLoReg); |
| - if (DestTy == IceType_i64) { |
| - _eor(TmpHiReg, PtrContentsHiReg, ValueHiReg); |
| - } |
| - break; |
| - case Intrinsics::AtomicExchange: |
| - _mov(TmpLoReg, ValueLoReg); |
| - if (DestTy == IceType_i64) { |
| - _mov(TmpHiReg, ValueHiReg); |
| - } |
| + Oper = InstArithmetic::Xor; |
| break; |
| } |
| - _strex(Success, TmpReg, Mem); |
| - _cmp(Success, _0); |
| - _br(Retry, CondARM32::NE); |
| + return InstArithmetic::create(Func, Oper, Dest, Src0, Src1); |
| +} |
| +} // end of anonymous namespace |
| + |
| +void TargetARM32::lowerAtomicRMW(Variable *Dest, uint32_t Operation, |
| + Operand *Addr, Operand *Val) { |
| + // retry: |
| + // ldrex tmp, [addr] |
| + // mov contents, tmp |
| + // op result, contents, Val |
| + // strex success, result, [addr] |
| + // cmp success, 0 |
| + // jne retry |
| + // fake-use(addr, operand) @ prevents undesirable clobbering. |
| + // mov dest, contents |
| + auto DestTy = Dest->getType(); |
| + |
| + if (DestTy == IceType_i64) { |
| + lowerInt64AtomicRMW(Dest, Operation, Addr, Val); |
| + return; |
| + } |
| - // The following fake-uses ensure that Subzero will not clobber them in the |
| - // load-linked/store-conditional loop above. We might have to spill them, but |
| - // spilling is preferable over incorrect behavior. |
| - Context.insert<InstFakeUse>(PtrVar); |
| - if (auto *Value64 = llvm::dyn_cast<Variable64On32>(Value)) { |
| - Context.insert<InstFakeUse>(Value64->getHi()); |
| - Context.insert<InstFakeUse>(Value64->getLo()); |
| + Operand *ValRF = nullptr; |
| + if (llvm::isa<ConstantInteger32>(Val)) { |
| + ValRF = Val; |
| } else { |
| - Context.insert<InstFakeUse>(Value); |
| + ValRF = legalizeToReg(Val); |
| } |
| + auto *ContentsR = makeReg(DestTy); |
| + auto *ResultR = makeReg(DestTy); |
| + |
| _dmb(); |
| - if (DestTy == IceType_i8 || DestTy == IceType_i16) { |
| - _uxt(PtrContentsReg, PtrContentsReg); |
| + lowerLoadLinkedStoreExclusive( |
| + DestTy, Addr, |
| + [this, Operation, ResultR, ContentsR, ValRF](Variable *Tmp) { |
| + lowerAssign(InstAssign::create(Func, ContentsR, Tmp)); |
| + if (Operation == Intrinsics::AtomicExchange) { |
| + lowerAssign(InstAssign::create(Func, ResultR, ValRF)); |
| + } else { |
| + lowerArithmetic( |
| + createArithInst(Func, Operation, ResultR, ContentsR, ValRF)); |
| + } |
| + return ResultR; |
| + }); |
| + _dmb(); |
| + if (auto *ValR = llvm::dyn_cast<Variable>(ValRF)) { |
| + Context.insert<InstFakeUse>(ValR); |
| } |
| + // Can't dce ContentsR. |
| + Context.insert<InstFakeUse>(ContentsR); |
| + lowerAssign(InstAssign::create(Func, Dest, ContentsR)); |
| +} |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeUse>(PtrContentsReg); |
| - } |
| - lowerAssign(InstAssign::create(Func, Dest, PtrContentsReg)); |
| - if (auto *Dest64 = llvm::dyn_cast<Variable64On32>(Dest)) { |
| - Context.insert<InstFakeUse>(Dest64->getLo()); |
| - Context.insert<InstFakeUse>(Dest64->getHi()); |
| +void TargetARM32::lowerInt64AtomicRMW(Variable *Dest, uint32_t Operation, |
| + Operand *Addr, Operand *Val) { |
| + assert(Dest->getType() == IceType_i64); |
| + |
| + auto *ResultR = makeI64RegPair(); |
| + |
| + Context.insert<InstFakeDef>(ResultR); |
| + |
| + Operand *ValRF = nullptr; |
| + if (llvm::dyn_cast<ConstantInteger64>(Val)) { |
| + ValRF = Val; |
| } else { |
| - Context.insert<InstFakeUse>(Dest); |
| + auto *ValR64 = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| + ValR64->initHiLo(Func); |
| + ValR64->setMustNotHaveReg(); |
| + ValR64->getLo()->setMustHaveReg(); |
| + ValR64->getHi()->setMustHaveReg(); |
| + lowerAssign(InstAssign::create(Func, ValR64, Val)); |
| + ValRF = ValR64; |
| + } |
| + |
| + auto *ContentsR = llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| + ContentsR->initHiLo(Func); |
| + ContentsR->setMustNotHaveReg(); |
| + ContentsR->getLo()->setMustHaveReg(); |
| + ContentsR->getHi()->setMustHaveReg(); |
| + |
| + _dmb(); |
| + lowerLoadLinkedStoreExclusive( |
| + IceType_i64, Addr, |
| + [this, Operation, ResultR, ContentsR, ValRF](Variable *Tmp) { |
| + lowerAssign(InstAssign::create(Func, ContentsR, Tmp)); |
| + Context.insert<InstFakeUse>(Tmp); |
| + if (Operation == Intrinsics::AtomicExchange) { |
| + lowerAssign(InstAssign::create(Func, ResultR, ValRF)); |
| + } else { |
| + lowerArithmetic( |
| + createArithInst(Func, Operation, ResultR, ContentsR, ValRF)); |
| + } |
| + Context.insert<InstFakeUse>(ResultR->getHi()); |
| + Context.insert<InstFakeDef>(ResultR, ResultR->getLo()) |
| + ->setDestRedefined(); |
| + return ResultR; |
| + }); |
| + _dmb(); |
| + if (auto *ValR64 = llvm::dyn_cast<Variable64On32>(ValRF)) { |
| + Context.insert<InstFakeUse>(ValR64->getLo()); |
| + Context.insert<InstFakeUse>(ValR64->getHi()); |
| } |
| + lowerAssign(InstAssign::create(Func, Dest, ContentsR)); |
| } |
| void TargetARM32::postambleCtpop64(const InstCall *Instr) { |
| @@ -4733,10 +4734,9 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
| } |
| _dmb(); |
| lowerAssign(InstAssign::create(Func, Dest, T)); |
| - // Make sure the atomic load isn't elided when unused, by adding a FakeUse. |
| - // Since lowerLoad may fuse the load w/ an arithmetic instruction, insert |
| - // the FakeUse on the last-inserted instruction's dest. |
| - Context.insert<InstFakeUse>(Context.getLastInserted()->getDest()); |
| + // Adding a fake-use T to ensure the atomic load is not removed if Dest is |
| + // unused. |
| + Context.insert<InstFakeUse>(T); |
| return; |
| } |
| case Intrinsics::AtomicStore: { |
| @@ -4747,105 +4747,48 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
| Func->setError("Unexpected memory ordering for AtomicStore"); |
| return; |
| } |
| - Operand *Value = Instr->getArg(0); |
| - Type ValueTy = Value->getType(); |
| - assert(isScalarIntegerType(ValueTy)); |
| - Operand *Addr = Instr->getArg(1); |
| - |
| - if (ValueTy == IceType_i64) { |
| - // Atomic 64-bit stores require a load-locked/store-conditional loop using |
| - // ldrexd, and strexd. The lowered code is: |
| - // |
| - // retry: |
| - // ldrexd t.lo, t.hi, [addr] |
| - // strexd success, value.lo, value.hi, [addr] |
| - // cmp success, #0 |
| - // bne retry |
| - // fake-use(addr, value.lo, value.hi) |
| - // |
| - // The fake-use is needed to prevent those variables from being clobbered |
| - // in the loop (which will happen under register pressure.) |
| - Variable64On32 *Tmp = makeI64RegPair(); |
| - Variable64On32 *ValueVar = |
| - llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| - Variable *AddrVar = makeReg(IceType_i32); |
| - Variable *Success = makeReg(IceType_i32); |
| - OperandARM32Mem *Mem; |
| - Operand *_0 = Ctx->getConstantZero(IceType_i32); |
| - auto *Retry = InstARM32Label::create(Func, this); |
| - Variable64On32 *NewReg = makeI64RegPair(); |
| - ValueVar->initHiLo(Func); |
| - ValueVar->mustNotHaveReg(); |
| + auto *Value = Instr->getArg(0); |
| + if (Value->getType() == IceType_i64) { |
| + auto *ValueR = makeI64RegPair(); |
| + Context.insert<InstFakeDef>(ValueR); |
| + lowerAssign(InstAssign::create(Func, ValueR, Value)); |
| _dmb(); |
| - lowerAssign(InstAssign::create(Func, ValueVar, Value)); |
| - lowerAssign(InstAssign::create(Func, AddrVar, Addr)); |
| - |
| - Context.insert(Retry); |
| - Context.insert<InstFakeDef>(NewReg); |
| - lowerAssign(InstAssign::create(Func, NewReg, ValueVar)); |
| - Mem = formMemoryOperand(AddrVar, IceType_i64); |
| - _ldrex(Tmp, Mem); |
| - // This fake-use both prevents the ldrex from being dead-code eliminated, |
| - // while also keeping liveness happy about all defs being used. |
| - Context.insert<InstFakeUse>(Context.getLastInserted()->getDest()); |
| - _strex(Success, NewReg, Mem); |
| - _cmp(Success, _0); |
| - _br(Retry, CondARM32::NE); |
| - |
| - Context.insert<InstFakeUse>(ValueVar->getLo()); |
| - Context.insert<InstFakeUse>(ValueVar->getHi()); |
| - Context.insert<InstFakeUse>(AddrVar); |
| + lowerLoadLinkedStoreExclusive( |
| + IceType_i64, Instr->getArg(1), [this, ValueR](Variable *Tmp) { |
| + // The following fake-use prevents the ldrex instruction from being |
| + // dead code eliminated. |
| + Context.insert<InstFakeUse>(llvm::cast<Variable>(loOperand(Tmp))); |
| + Context.insert<InstFakeUse>(llvm::cast<Variable>(hiOperand(Tmp))); |
| + Context.insert<InstFakeUse>(Tmp); |
| + return ValueR; |
| + }); |
| + Context.insert<InstFakeUse>(ValueR); |
| _dmb(); |
| return; |
| } |
| + |
| + auto *ValueR = legalizeToReg(Instr->getArg(0)); |
| + Type ValueTy = ValueR->getType(); |
|
Jim Stichnoth
2016/02/17 03:50:17
Surprised that "auto" wasn't used here.
John
2016/02/17 13:01:39
not to mention the lack of constness... :)
Done.
|
| + assert(isScalarIntegerType(ValueTy)); |
| + auto *Addr = legalizeToReg(Instr->getArg(1)); |
| + |
| // non-64-bit stores are atomically as long as the address is aligned. This |
| // is PNaCl, so addresses are aligned. |
| - Variable *T = makeReg(ValueTy); |
| - |
| _dmb(); |
| - lowerAssign(InstAssign::create(Func, T, Value)); |
| - _str(T, formMemoryOperand(Addr, ValueTy)); |
| + _str(ValueR, formMemoryOperand(Addr, ValueTy)); |
| _dmb(); |
| return; |
| } |
| case Intrinsics::AtomicCmpxchg: { |
| - // The initial lowering for cmpxchg was: |
| - // |
| // retry: |
| // ldrex tmp, [addr] |
| // cmp tmp, expected |
| // mov expected, tmp |
| - // jne retry |
| - // strex success, new, [addr] |
| - // cmp success, #0 |
| - // bne retry |
| - // mov dest, expected |
| - // |
| - // Besides requiring two branches, that lowering could also potentially |
| - // write to memory (in mov expected, tmp) unless we were OK with increasing |
| - // the register pressure and requiring expected to be an infinite-weight |
| - // variable (spoiler alert: that was a problem for i64 cmpxchg.) Through |
| - // careful rewritting, and thanks to predication, we now implement the |
| - // lowering as: |
| - // |
| - // retry: |
| - // ldrex tmp, [addr] |
| - // cmp tmp, expected |
| // strexeq success, new, [addr] |
| - // movne expected, tmp |
| // cmpeq success, #0 |
| // bne retry |
| // mov dest, expected |
| - // |
| - // Predication lets us move the strex ahead of the mov expected, tmp, which |
| - // allows tmp to be a non-infinite weight temporary. We wanted to avoid |
| - // writing to memory between ldrex and strex because, even though most times |
| - // that would cause no issues, if any interleaving memory write aliased |
| - // [addr] than we would have undefined behavior. Undefined behavior isn't |
| - // cool, so we try to avoid it. See the "Synchronization and semaphores" |
| - // section of the "ARM Architecture Reference Manual." |
| - |
| assert(isScalarIntegerType(DestTy)); |
| // We require the memory address to be naturally aligned. Given that is the |
| // case, then normal loads are atomic. |
| @@ -4856,98 +4799,63 @@ void TargetARM32::lowerIntrinsicCall(const InstIntrinsicCall *Instr) { |
| return; |
| } |
| - OperandARM32Mem *Mem; |
| - Variable *TmpReg; |
| - Variable *Expected, *ExpectedReg; |
| - Variable *New, *NewReg; |
| - Variable *Success = makeReg(IceType_i32); |
| - Operand *_0 = Ctx->getConstantZero(IceType_i32); |
| - auto *Retry = InstARM32Label::create(Func, this); |
| - |
| if (DestTy == IceType_i64) { |
| - Variable64On32 *TmpReg64 = makeI64RegPair(); |
| - Variable64On32 *New64 = |
| - llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| - Variable64On32 *NewReg64 = makeI64RegPair(); |
| - Variable64On32 *Expected64 = |
| - llvm::cast<Variable64On32>(Func->makeVariable(IceType_i64)); |
| - Variable64On32 *ExpectedReg64 = makeI64RegPair(); |
| - |
| - New64->initHiLo(Func); |
| - New64->mustNotHaveReg(); |
| - Expected64->initHiLo(Func); |
| - Expected64->mustNotHaveReg(); |
| - |
| - TmpReg = TmpReg64; |
| - New = New64; |
| - NewReg = NewReg64; |
| - Expected = Expected64; |
| - ExpectedReg = ExpectedReg64; |
| - } else { |
| - TmpReg = makeReg(DestTy); |
| - New = Func->makeVariable(DestTy); |
| - NewReg = makeReg(DestTy); |
| - Expected = Func->makeVariable(DestTy); |
| - ExpectedReg = makeReg(DestTy); |
| - } |
| + auto *New = makeI64RegPair(); |
| + Context.insert<InstFakeDef>(New); |
| + lowerAssign(InstAssign::create(Func, New, Instr->getArg(2))); |
| - Mem = formMemoryOperand(Instr->getArg(0), DestTy); |
| - if (DestTy == IceType_i64) { |
| + auto *Expected = makeI64RegPair(); |
| Context.insert<InstFakeDef>(Expected); |
| - } |
| - lowerAssign(InstAssign::create(Func, Expected, Instr->getArg(1))); |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(New); |
| - } |
| - lowerAssign(InstAssign::create(Func, New, Instr->getArg(2))); |
| - _dmb(); |
| + lowerAssign(InstAssign::create(Func, Expected, Instr->getArg(1))); |
| - Context.insert(Retry); |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(ExpectedReg, Expected); |
| - } |
| - lowerAssign(InstAssign::create(Func, ExpectedReg, Expected)); |
| - if (DestTy == IceType_i64) { |
| - Context.insert<InstFakeDef>(NewReg, New); |
| - } |
| - lowerAssign(InstAssign::create(Func, NewReg, New)); |
| + _dmb(); |
| + lowerLoadLinkedStoreExclusive( |
| + DestTy, Instr->getArg(0), |
| + [this, Expected, New, Instr, DestTy](Variable *Tmp) { |
| + auto *ExpectedLoR = llvm::cast<Variable>(loOperand(Expected)); |
| + auto *ExpectedHiR = llvm::cast<Variable>(hiOperand(Expected)); |
| + auto *TmpLoR = llvm::cast<Variable>(loOperand(Tmp)); |
| + auto *TmpHiR = llvm::cast<Variable>(hiOperand(Tmp)); |
| + _cmp(TmpLoR, ExpectedLoR); |
| + _cmp(TmpHiR, ExpectedHiR, CondARM32::EQ); |
| + // Adding an explicit use of Tmp here, or its live range will not |
| + // reach here (only those of Tmp.Lo and Tmp.Hi will.) |
| + Context.insert<InstFakeUse>(Tmp); |
| + _mov_redefined(ExpectedLoR, TmpLoR); |
| + _mov_redefined(ExpectedHiR, TmpHiR); |
| + // Same as above. |
| + Context.insert<InstFakeUse>(Tmp); |
| + return New; |
| + }, |
| + CondARM32::EQ); |
| + _dmb(); |
| - _ldrex(TmpReg, Mem); |
| - Context.insert<InstFakeUse>(Context.getLastInserted()->getDest()); |
| - if (DestTy == IceType_i64) { |
| - auto *TmpReg64 = llvm::cast<Variable64On32>(TmpReg); |
| - auto *ExpectedReg64 = llvm::cast<Variable64On32>(ExpectedReg); |
| - // lowerAssign above has added fake-defs for TmpReg and ExpectedReg. Let's |
| - // keep liveness happy, shall we? |
| - Context.insert<InstFakeUse>(TmpReg); |
| - Context.insert<InstFakeUse>(ExpectedReg); |
| - _cmp(TmpReg64->getHi(), ExpectedReg64->getHi()); |
| - _cmp(TmpReg64->getLo(), ExpectedReg64->getLo(), CondARM32::EQ); |
| - } else { |
| - _cmp(TmpReg, ExpectedReg); |
| - } |
| - _strex(Success, NewReg, Mem, CondARM32::EQ); |
| - if (DestTy == IceType_i64) { |
| - auto *TmpReg64 = llvm::cast<Variable64On32>(TmpReg); |
| - auto *Expected64 = llvm::cast<Variable64On32>(Expected); |
| - _mov_redefined(Expected64->getHi(), TmpReg64->getHi(), CondARM32::NE); |
| - _mov_redefined(Expected64->getLo(), TmpReg64->getLo(), CondARM32::NE); |
| - Context.insert<InstFakeDef>(Expected, TmpReg); |
| - _set_dest_redefined(); |
| - } else { |
| - _mov_redefined(Expected, TmpReg, CondARM32::NE); |
| + lowerAssign(InstAssign::create(Func, Dest, Expected)); |
| + // The fake-use Expected prevents the assignments to Expected (above) |
| + // from being removed if Dest is not used. |
| + Context.insert<InstFakeUse>(Expected); |
| + // New needs to be alive here, or its live range will end in the |
| + // strex instruction. |
| + Context.insert<InstFakeUse>(New); |
| + return; |
| } |
| - _cmp(Success, _0, CondARM32::EQ); |
| - _br(Retry, CondARM32::NE); |
| + |
| + auto *New = legalizeToReg(Instr->getArg(2)); |
| + auto *Expected = legalizeToReg(Instr->getArg(1)); |
| + |
| + _dmb(); |
| + lowerLoadLinkedStoreExclusive( |
| + DestTy, |
| + Instr->getArg(0), [this, Expected, New, Instr, DestTy](Variable *Tmp) { |
| + lowerIcmpCond(InstIcmp::Eq, Tmp, Expected); |
| + _mov_redefined(Expected, Tmp); |
| + return New; |
| + }, CondARM32::EQ); |
| _dmb(); |
| + |
| lowerAssign(InstAssign::create(Func, Dest, Expected)); |
| Context.insert<InstFakeUse>(Expected); |
| - if (auto *New64 = llvm::dyn_cast<Variable64On32>(New)) { |
| - Context.insert<InstFakeUse>(New64->getLo()); |
| - Context.insert<InstFakeUse>(New64->getHi()); |
| - } else { |
| - Context.insert<InstFakeUse>(New); |
| - } |
| + Context.insert<InstFakeUse>(New); |
| return; |
| } |
| case Intrinsics::AtomicRMW: { |