// Utility helper routines.
bool isTypeLegal(Type *Ty, MVT &VT);
bool isLoadStoreTypeLegal(Type *Ty, MVT &VT);
- bool isLegalToFoldAddress(const Value *Obj);
- bool computeAddress(const Value *Obj, Address &Addr, Type *Ty = nullptr);
- bool computeAddressRecursively(const Value *Obj, Address &Addr, Type *Ty);
- bool computeAddressBase(const Value *Obj, Address &Addr);
-
+ bool isValueAvailable(const Value *V) const;
+ bool ComputeAddress(const Value *Obj, Address &Addr, Type *Ty = nullptr);
bool ComputeCallAddress(const Value *V, Address &Addr);
bool SimplifyAddress(Address &Addr, MVT VT);
void AddLoadStoreOperands(Address &Addr, const MachineInstrBuilder &MIB,
return FastEmitInst_r(Opc, TLI.getRegClassFor(VT), ZReg, /*IsKill=*/true);
}
-bool AArch64FastISel::isLegalToFoldAddress(const Value *Obj) {
- // Look through BitCast, IntToPtr, and PtrToInt.
- const User *U = nullptr;
- unsigned Opcode = Instruction::UserOp1;
- if (const auto *I = dyn_cast<Instruction>(Obj)) {
- // Bail out if the result is used in a different basic block.
- if (FuncInfo.isExportedInst(I))
- return false;
-
- Opcode = I->getOpcode();
- U = I;
- } else if (const auto *CE = dyn_cast<ConstantExpr>(Obj)) {
- Opcode = CE->getOpcode();
- U = CE;
- }
-
- switch (Opcode) {
- default:
- break;
- case Instruction::BitCast:
- return isLegalToFoldAddress(U->getOperand(0));
- case Instruction::IntToPtr:
- if (TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy())
- return isLegalToFoldAddress(U->getOperand(0));
- break;
- case Instruction::PtrToInt:
- if (TLI.getValueType(U->getType()) == TLI.getPointerTy())
- return isLegalToFoldAddress(U->getOperand(0));
- break;
- }
-
- // Allocas never kill their operands, so it is safe to fold it.
- if (isa<AllocaInst>(Obj) || !isa<Instruction>(Obj))
- return true;
-
- const auto *I = cast<Instruction>(Obj);
- // Trivial case - the memory instruction is the only user.
- if (I->hasOneUse())
- return true;
-
- // Check all users - if all of them are memory instructions that FastISel
- // can handle, then it is safe to fold the instruction.
- for (auto *U : I->users())
- if (!isa<LoadInst>(U) && !isa<StoreInst>(U))
- return false;
-
- return true;
-}
-
// Computes the address to get to an object.
-bool AArch64FastISel::computeAddress(const Value *Obj, Address &Addr,
- Type *Ty) {
- // Don't fold instructions into the memory operation if their result is
- // exported to another basic block or has more than one use - except if all
- // uses are memory operations.
- if (isLegalToFoldAddress(Obj))
- return computeAddressRecursively(Obj, Addr, Ty);
- return computeAddressBase(Obj, Addr);
-}
-
-bool AArch64FastISel::computeAddressRecursively(const Value *Obj, Address &Addr,
- Type *Ty) {
+bool AArch64FastISel::ComputeAddress(const Value *Obj, Address &Addr, Type *Ty)
+{
const User *U = nullptr;
unsigned Opcode = Instruction::UserOp1;
if (const Instruction *I = dyn_cast<Instruction>(Obj)) {
break;
case Instruction::BitCast: {
// Look through bitcasts.
- return computeAddressRecursively(U->getOperand(0), Addr, Ty);
+ return ComputeAddress(U->getOperand(0), Addr, Ty);
}
case Instruction::IntToPtr: {
// Look past no-op inttoptrs.
if (TLI.getValueType(U->getOperand(0)->getType()) == TLI.getPointerTy())
- return computeAddressRecursively(U->getOperand(0), Addr, Ty);
+ return ComputeAddress(U->getOperand(0), Addr, Ty);
break;
}
case Instruction::PtrToInt: {
- // Look past no-op ptrtoints. Don't increment recursion level.
+ // Look past no-op ptrtoints.
if (TLI.getValueType(U->getType()) == TLI.getPointerTy())
- return computeAddressRecursively(U->getOperand(0), Addr, Ty);
+ return ComputeAddress(U->getOperand(0), Addr, Ty);
break;
}
case Instruction::GetElementPtr: {
// Try to grab the base operand now.
Addr.setOffset(TmpOffset);
- if (computeAddressRecursively(U->getOperand(0), Addr, Ty))
+ if (ComputeAddress(U->getOperand(0), Addr, Ty))
return true;
// We failed, restore everything and try the other options.
break;
}
case Instruction::Add: {
- if (!U->hasOneUse())
- break;
-
// Adds of constants are common and easy enough.
const Value *LHS = U->getOperand(0);
const Value *RHS = U->getOperand(1);
if (const ConstantInt *CI = dyn_cast<ConstantInt>(RHS)) {
Addr.setOffset(Addr.getOffset() + (uint64_t)CI->getSExtValue());
- return computeAddressRecursively(LHS, Addr, Ty);
+ return ComputeAddress(LHS, Addr, Ty);
}
Address Backup = Addr;
- if (computeAddressRecursively(LHS, Addr, Ty) &&
- computeAddressRecursively(RHS, Addr, Ty))
+ if (ComputeAddress(LHS, Addr, Ty) && ComputeAddress(RHS, Addr, Ty))
return true;
Addr = Backup;
break;
}
case Instruction::Shl:
- if (!U->hasOneUse())
- break;
-
if (Addr.getOffsetReg())
break;
Addr.setShift(Val);
Addr.setExtendType(AArch64_AM::LSL);
- // Only try to fold the operand if it has one use.
if (const auto *I = dyn_cast<Instruction>(U->getOperand(0)))
- if (I->hasOneUse() &&
- (FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB))
+ if (FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB)
U = I;
if (const auto *ZE = dyn_cast<ZExtInst>(U))
break;
}
- return computeAddressBase(Obj, Addr);
-}
-
-bool AArch64FastISel::computeAddressBase(const Value *Obj, Address &Addr) {
if (Addr.getReg()) {
if (!Addr.getOffsetReg()) {
unsigned Reg = getRegForValue(Obj);
return false;
}
+bool AArch64FastISel::isValueAvailable(const Value *V) const {
+ if (!isa<Instruction>(V))
+ return true;
+
+ const auto *I = cast<Instruction>(V);
+ if (FuncInfo.MBBMap[I->getParent()] == FuncInfo.MBB)
+ return true;
+
+ return false;
+}
+
bool AArch64FastISel::SimplifyAddress(Address &Addr, MVT VT) {
unsigned ScaleFactor;
switch (VT.SimpleTy) {
std::swap(LHS, RHS);
// Canonicalize shift immediate to the RHS.
- if (UseAdds)
+ if (UseAdds && isValueAvailable(LHS))
if (const auto *SI = dyn_cast<BinaryOperator>(LHS))
if (isa<ConstantInt>(SI->getOperand(1)))
if (SI->getOpcode() == Instruction::Shl ||
return ResultReg;
// Only extend the RHS within the instruction if there is a valid extend type.
- if (ExtendType != AArch64_AM::InvalidShiftExtend) {
+ if (ExtendType != AArch64_AM::InvalidShiftExtend && isValueAvailable(RHS)) {
if (const auto *SI = dyn_cast<BinaryOperator>(RHS))
if (const auto *C = dyn_cast<ConstantInt>(SI->getOperand(1)))
if ((SI->getOpcode() == Instruction::Shl) && (C->getZExtValue() < 4)) {
}
// Check if the shift can be folded into the instruction.
- if (const auto *SI = dyn_cast<BinaryOperator>(RHS)) {
- if (const auto *C = dyn_cast<ConstantInt>(SI->getOperand(1))) {
- AArch64_AM::ShiftExtendType ShiftType = AArch64_AM::InvalidShiftExtend;
- switch (SI->getOpcode()) {
- default: break;
- case Instruction::Shl: ShiftType = AArch64_AM::LSL; break;
- case Instruction::LShr: ShiftType = AArch64_AM::LSR; break;
- case Instruction::AShr: ShiftType = AArch64_AM::ASR; break;
- }
- uint64_t ShiftVal = C->getZExtValue();
- if (ShiftType != AArch64_AM::InvalidShiftExtend) {
- unsigned RHSReg = getRegForValue(SI->getOperand(0));
- if (!RHSReg)
- return 0;
- bool RHSIsKill = hasTrivialKill(SI->getOperand(0));
- return emitAddsSubs_rs(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg,
- RHSIsKill, ShiftType, ShiftVal, WantResult);
+ if (isValueAvailable(RHS))
+ if (const auto *SI = dyn_cast<BinaryOperator>(RHS)) {
+ if (const auto *C = dyn_cast<ConstantInt>(SI->getOperand(1))) {
+ AArch64_AM::ShiftExtendType ShiftType = AArch64_AM::InvalidShiftExtend;
+ switch (SI->getOpcode()) {
+ default: break;
+ case Instruction::Shl: ShiftType = AArch64_AM::LSL; break;
+ case Instruction::LShr: ShiftType = AArch64_AM::LSR; break;
+ case Instruction::AShr: ShiftType = AArch64_AM::ASR; break;
+ }
+ uint64_t ShiftVal = C->getZExtValue();
+ if (ShiftType != AArch64_AM::InvalidShiftExtend) {
+ unsigned RHSReg = getRegForValue(SI->getOperand(0));
+ if (!RHSReg)
+ return 0;
+ bool RHSIsKill = hasTrivialKill(SI->getOperand(0));
+ return emitAddsSubs_rs(UseAdds, RetVT, LHSReg, LHSIsKill, RHSReg,
+ RHSIsKill, ShiftType, ShiftVal, WantResult);
+ }
}
}
- }
unsigned RHSReg = getRegForValue(RHS);
if (!RHSReg)
// See if we can handle this address.
Address Addr;
- if (!computeAddress(I->getOperand(0), Addr, I->getType()))
+ if (!ComputeAddress(I->getOperand(0), Addr, I->getType()))
return false;
unsigned ResultReg;
// See if we can handle this address.
Address Addr;
- if (!computeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType()))
+ if (!ComputeAddress(I->getOperand(1), Addr, I->getOperand(0)->getType()))
return false;
if (!EmitStore(VT, SrcReg, Addr, createMachineMemOperandFor(I)))
if (MTI->isVolatile())
return false;
- // Disable inlining for memmove before calls to computeAddress. Otherwise,
+ // Disable inlining for memmove before calls to ComputeAddress. Otherwise,
// we would emit dead code because we don't currently handle memmoves.
bool IsMemCpy = (II->getIntrinsicID() == Intrinsic::memcpy);
if (isa<ConstantInt>(MTI->getLength()) && IsMemCpy) {
unsigned Alignment = MTI->getAlignment();
if (IsMemCpySmall(Len, Alignment)) {
Address Dest, Src;
- if (!computeAddress(MTI->getRawDest(), Dest) ||
- !computeAddress(MTI->getRawSource(), Src))
+ if (!ComputeAddress(MTI->getRawDest(), Dest) ||
+ !ComputeAddress(MTI->getRawSource(), Src))
return false;
if (TryEmitSmallMemCpy(Dest, Src, Len, Alignment))
return true;
bool SrcIsKill = hasTrivialKill(Op);
// If we're truncating from i64 to a smaller non-legal type then generate an
- // AND. Otherwise, we know the high bits are undefined and a truncate doesn't
- // generate any code.
+ // AND. Otherwise, we know the high bits are undefined and a truncate only
+ // generate a COPY. We cannot mark the source register also as result
+ // register, because this can incorrectly transfer the kill flag onto the
+ // source register.
+ unsigned ResultReg;
if (SrcVT == MVT::i64) {
uint64_t Mask = 0;
switch (DestVT.SimpleTy) {
unsigned Reg32 = FastEmitInst_extractsubreg(MVT::i32, SrcReg, SrcIsKill,
AArch64::sub_32);
// Create the AND instruction which performs the actual truncation.
- unsigned ANDReg = emitAND_ri(MVT::i32, Reg32, /*IsKill=*/true, Mask);
- assert(ANDReg && "Unexpected AND instruction emission failure.");
- SrcReg = ANDReg;
+ ResultReg = emitAND_ri(MVT::i32, Reg32, /*IsKill=*/true, Mask);
+ assert(ResultReg && "Unexpected AND instruction emission failure.");
+ } else {
+ ResultReg = createResultReg(&AArch64::GPR32RegClass);
+ BuildMI(*FuncInfo.MBB, FuncInfo.InsertPt, DbgLoc,
+ TII.get(TargetOpcode::COPY), ResultReg)
+ .addReg(SrcReg, getKillRegState(SrcIsKill));
}
- UpdateValueMap(I, SrcReg);
+ UpdateValueMap(I, ResultReg);
return true;
}
uint64_t ShiftVal = C->getZExtValue();
MVT SrcVT = RetVT;
bool IsZExt = (I->getOpcode() == Instruction::AShr) ? false : true;
- const Value * Op0 = I->getOperand(0);
+ const Value *Op0 = I->getOperand(0);
if (const auto *ZExt = dyn_cast<ZExtInst>(Op0)) {
MVT TmpVT;
- if (isLoadStoreTypeLegal(ZExt->getSrcTy(), TmpVT)) {
+ if (isValueAvailable(ZExt) &&
+ isLoadStoreTypeLegal(ZExt->getSrcTy(), TmpVT)) {
SrcVT = TmpVT;
IsZExt = true;
Op0 = ZExt->getOperand(0);
}
} else if (const auto *SExt = dyn_cast<SExtInst>(Op0)) {
MVT TmpVT;
- if (isLoadStoreTypeLegal(SExt->getSrcTy(), TmpVT)) {
+ if (isValueAvailable(SExt) &&
+ isLoadStoreTypeLegal(SExt->getSrcTy(), TmpVT)) {
SrcVT = TmpVT;
IsZExt = false;
Op0 = SExt->getOperand(0);