Index: include/llvm/Analysis/PtrUseVisitor.h =================================================================== --- include/llvm/Analysis/PtrUseVisitor.h +++ include/llvm/Analysis/PtrUseVisitor.h @@ -286,6 +286,15 @@ case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: + return; + + // fake_use is a noop. + // A pointer used by a fake_use is escaped to prevent SROA + // from transforming it. + // FIXME: revisit this and find another way to deal with the resulting + // inconsistencies in SROA. + case Intrinsic::fake_use: + PI.setEscaped(&II); return; // No-op intrinsics. } } Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -832,6 +832,11 @@ /// is the chain and the second operand is the alloca pointer. LIFETIME_START, LIFETIME_END, + /// FAKE_USE represents a use of the operand but does not do anything. + /// Its purpose is the extension of the operand's lifetime mainly for + /// debugging purposes. + FAKE_USE, + /// GC_TRANSITION_START/GC_TRANSITION_END - These operators mark the /// beginning and end of GC transition sequence, and carry arbitrary /// information that target might need for lowering. The first operand is Index: include/llvm/CodeGen/MachineInstr.h =================================================================== --- include/llvm/CodeGen/MachineInstr.h +++ include/llvm/CodeGen/MachineInstr.h @@ -1049,6 +1049,10 @@ return getOpcode() == TargetOpcode::EXTRACT_SUBREG; } + bool isFakeUse() const { + return getOpcode() == TargetOpcode::FAKE_USE; + } + /// Return true if the instruction behaves like a copy. /// This does not include native copy instructions. bool isCopyLike() const { @@ -1076,6 +1080,7 @@ case TargetOpcode::DBG_LABEL: case TargetOpcode::LIFETIME_START: case TargetOpcode::LIFETIME_END: + case TargetOpcode::FAKE_USE: return true; } } Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -295,6 +295,8 @@ void Select_READ_REGISTER(SDNode *Op); void Select_WRITE_REGISTER(SDNode *Op); void Select_UNDEF(SDNode *N); + void Select_FAKE_USE(SDNode *N); + void CannotYetSelect(SDNode *N); private: Index: include/llvm/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -908,6 +908,9 @@ def int_is_constant : Intrinsic<[llvm_i1_ty], [llvm_any_ty], [IntrNoMem], "llvm.is.constant">; +// Introduce a use of the argument without generating any code. +def int_fake_use : Intrinsic<[], [llvm_vararg_ty]>; + //===-------------------------- Masked Intrinsics -------------------------===// // def int_masked_store : Intrinsic<[], [llvm_anyvector_ty, Index: include/llvm/Support/TargetOpcodes.def =================================================================== --- include/llvm/Support/TargetOpcodes.def +++ include/llvm/Support/TargetOpcodes.def @@ -196,6 +196,9 @@ HANDLE_TARGET_OPCODE(ICALL_BRANCH_FUNNEL) +/// Represents a use of the operand but generates no code. +HANDLE_TARGET_OPCODE(FAKE_USE) + /// The following generic opcodes are not supposed to appear after ISel. /// This is something we might want to relax, but for now, this is convenient /// to produce diagnostics. Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -1103,6 +1103,13 @@ let isTerminator = 1; let isBranch = 1; } +def FAKE_USE : StandardPseudoInstruction { + // An instruction that uses its operands but does nothing. + let OutOperandList = (outs); + let InOperandList = (ins variable_ops); + let AsmString = "FAKE_USE"; + let hasSideEffects = 0; +} def PATCHABLE_OP : StandardPseudoInstruction { let OutOperandList = (outs); let InOperandList = (ins variable_ops); Index: lib/Analysis/ValueTracking.cpp =================================================================== --- lib/Analysis/ValueTracking.cpp +++ lib/Analysis/ValueTracking.cpp @@ -3802,7 +3802,9 @@ if (!II) return false; if (II->getIntrinsicID() != Intrinsic::lifetime_start && - II->getIntrinsicID() != Intrinsic::lifetime_end) + II->getIntrinsicID() != Intrinsic::lifetime_end && + II->getIntrinsicID() != Intrinsic::fake_use) + return false; } return true; Index: lib/CodeGen/Analysis.cpp =================================================================== --- lib/CodeGen/Analysis.cpp +++ lib/CodeGen/Analysis.cpp @@ -496,6 +496,9 @@ // Debug info intrinsics do not get in the way of tail call optimization. if (isa(BBI)) continue; + if (auto *II = dyn_cast(BBI)) + if (II->getIntrinsicID() == Intrinsic::fake_use) + continue; // A lifetime end intrinsic should not stop tail call optimization. if (const IntrinsicInst *II = dyn_cast(BBI)) if (II->getIntrinsicID() == Intrinsic::lifetime_end) Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1130,6 +1130,8 @@ case TargetOpcode::KILL: if (isVerbose()) emitKill(&MI, *this); break; + case TargetOpcode::FAKE_USE: + break; default: EmitInstruction(&MI); break; Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -1846,7 +1846,11 @@ // return is the first instruction in the block. if (PN) { BasicBlock::iterator BI = BB->begin(); - do { ++BI; } while (isa(BI)); + for (++BI; auto *II = dyn_cast(&*BI); ++BI) + if (!isa(II) && + (II->getIntrinsicID() != Intrinsic::fake_use)) + break; + if (&*BI == BCI) // Also skip over the bitcast. ++BI; @@ -1854,7 +1858,11 @@ return false; } else { BasicBlock::iterator BI = BB->begin(); - while (isa(BI)) ++BI; + for (; auto *II = dyn_cast(&*BI); ++BI) + if (!isa(II) && + (II->getIntrinsicID() != Intrinsic::fake_use)) + break; + if (&*BI != RetI) return false; } @@ -1881,7 +1889,13 @@ BasicBlock::InstListType &InstList = (*PI)->getInstList(); BasicBlock::InstListType::reverse_iterator RI = InstList.rbegin(); BasicBlock::InstListType::reverse_iterator RE = InstList.rend(); - do { ++RI; } while (RI != RE && isa(&*RI)); + for (++RI; RI != RE; ++RI) { + auto *II = dyn_cast(&*RI); + if (!II || (!isa(II) && + (II->getIntrinsicID() != Intrinsic::fake_use))) + break; + } + if (RI == RE) continue; Index: lib/CodeGen/DeadMachineInstructionElim.cpp =================================================================== --- lib/CodeGen/DeadMachineInstructionElim.cpp +++ lib/CodeGen/DeadMachineInstructionElim.cpp @@ -64,7 +64,8 @@ return false; // Don't delete frame allocation labels. - if (MI->getOpcode() == TargetOpcode::LOCAL_ESCAPE) + if (MI->getOpcode() == TargetOpcode::LOCAL_ESCAPE || + MI->getOpcode() == TargetOpcode::FAKE_USE) return false; // Don't delete instructions with side effects. Index: lib/CodeGen/MachineCSE.cpp =================================================================== --- lib/CodeGen/MachineCSE.cpp +++ lib/CodeGen/MachineCSE.cpp @@ -372,7 +372,8 @@ bool MachineCSE::isCSECandidate(MachineInstr *MI) { if (MI->isPosition() || MI->isPHI() || MI->isImplicitDef() || MI->isKill() || - MI->isInlineAsm() || MI->isDebugInstr()) + MI->isInlineAsm() || MI->isDebugInstr() || + MI->isFakeUse()) return false; // Ignore copies. Index: lib/CodeGen/PostRASchedulerList.cpp =================================================================== --- lib/CodeGen/PostRASchedulerList.cpp +++ lib/CodeGen/PostRASchedulerList.cpp @@ -283,6 +283,9 @@ if (skipFunction(Fn.getFunction())) return false; + if (Fn.getFunction().hasFnAttribute("disable-post-ra")) + return false; + TII = Fn.getSubtarget().getInstrInfo(); MachineLoopInfo &MLI = getAnalysis(); AliasAnalysis *AA = &getAnalysis().getAAResults(); Index: lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FastISel.cpp +++ lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1467,6 +1467,9 @@ updateValueMap(II, ResultReg); return true; } + case Intrinsic::fake_use: + // At -O0, we don't need fake use, so just ignore it. + return true; case Intrinsic::experimental_stackmap: return selectStackmap(II); case Intrinsic::experimental_patchpoint_void: Index: lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeFloatTypes.cpp @@ -129,6 +129,13 @@ return BitConvertToInteger(N->getOperand(0)); } +SDValue DAGTypeLegalizer::PromoteFloatOp_FAKE_USE(SDNode *N, unsigned OpNo) { + assert(OpNo == 1 && "Only Operand 1 must need promotion here"); + SDValue Op = GetPromotedFloat(N->getOperand(OpNo)); + return DAG.getNode(N->getOpcode(), SDLoc(N), MVT::Other, + N->getOperand(0), Op); +} + SDValue DAGTypeLegalizer::SoftenFloatRes_MERGE_VALUES(SDNode *N, unsigned ResNo) { SDValue Op = DisintegrateMERGE_VALUES(N, ResNo); @@ -1765,6 +1772,7 @@ llvm_unreachable("Do not know how to promote this operator's operand!"); case ISD::BITCAST: R = PromoteFloatOp_BITCAST(N, OpNo); break; + case ISD::FAKE_USE: R = PromoteFloatOp_FAKE_USE(N, OpNo); break; case ISD::FCOPYSIGN: R = PromoteFloatOp_FCOPYSIGN(N, OpNo); break; case ISD::FP_TO_SINT: case ISD::FP_TO_UINT: R = PromoteFloatOp_FP_TO_XINT(N, OpNo); break; Index: lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -1008,6 +1008,7 @@ case ISD::BUILD_VECTOR: Res = PromoteIntOp_BUILD_VECTOR(N); break; case ISD::CONCAT_VECTORS: Res = PromoteIntOp_CONCAT_VECTORS(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = PromoteIntOp_EXTRACT_VECTOR_ELT(N); break; + case ISD::FAKE_USE: Res = PromoteIntOp_FAKE_USE(N); break; case ISD::INSERT_VECTOR_ELT: Res = PromoteIntOp_INSERT_VECTOR_ELT(N, OpNo);break; case ISD::SCALAR_TO_VECTOR: @@ -3012,6 +3013,7 @@ case ISD::BR_CC: Res = ExpandIntOp_BR_CC(N); break; case ISD::BUILD_VECTOR: Res = ExpandOp_BUILD_VECTOR(N); break; case ISD::EXTRACT_ELEMENT: Res = ExpandOp_EXTRACT_ELEMENT(N); break; + case ISD::FAKE_USE: Res = ExpandOp_FAKE_USE(N); break; case ISD::INSERT_VECTOR_ELT: Res = ExpandOp_INSERT_VECTOR_ELT(N); break; case ISD::SCALAR_TO_VECTOR: Res = ExpandOp_SCALAR_TO_VECTOR(N); break; case ISD::SELECT_CC: Res = ExpandIntOp_SELECT_CC(N); break; @@ -3662,6 +3664,19 @@ return DAG.getAnyExtOrTrunc(Ext, dl, N->getValueType(0)); } +// FIXME: We wouldn't need this if clang could promote short integers +// that are arguments to FAKE_USE. +SDValue DAGTypeLegalizer::PromoteIntOp_FAKE_USE(SDNode *N) { + SDLoc dl(N); + SDValue V0 = N->getOperand(0); + SDValue V1 = N->getOperand(1); + EVT InVT1 = V1.getValueType(); + SDValue VPromoted = DAG.getNode( + ISD::ANY_EXTEND, dl, TLI.getTypeToTransformTo(*DAG.getContext(), InVT1), + V1); + return DAG.getNode(N->getOpcode(), dl, N->getValueType(0), V0, VPromoted); +} + SDValue DAGTypeLegalizer::PromoteIntOp_EXTRACT_SUBVECTOR(SDNode *N) { SDLoc dl(N); SDValue V0 = GetPromotedInteger(N->getOperand(0)); Index: lib/CodeGen/SelectionDAG/LegalizeTypes.h =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypes.h +++ lib/CodeGen/SelectionDAG/LegalizeTypes.h @@ -344,6 +344,7 @@ SDValue PromoteIntOp_INSERT_VECTOR_ELT(SDNode *N, unsigned OpNo); SDValue PromoteIntOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue PromoteIntOp_EXTRACT_SUBVECTOR(SDNode *N); + SDValue PromoteIntOp_FAKE_USE(SDNode *N); SDValue PromoteIntOp_CONCAT_VECTORS(SDNode *N); SDValue PromoteIntOp_SCALAR_TO_VECTOR(SDNode *N); SDValue PromoteIntOp_SELECT(SDNode *N, unsigned OpNo); @@ -624,6 +625,7 @@ bool PromoteFloatOperand(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_BITCAST(SDNode *N, unsigned OpNo); + SDValue PromoteFloatOp_FAKE_USE(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_FCOPYSIGN(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_FP_EXTEND(SDNode *N, unsigned OpNo); SDValue PromoteFloatOp_FP_TO_XINT(SDNode *N, unsigned OpNo); @@ -681,6 +683,7 @@ SDValue ScalarizeVecOp_VSETCC(SDNode *N); SDValue ScalarizeVecOp_STORE(StoreSDNode *N, unsigned OpNo); SDValue ScalarizeVecOp_FP_ROUND(SDNode *N, unsigned OpNo); + SDValue ScalarizeVecOp_FAKE_USE(SDNode *N); //===--------------------------------------------------------------------===// // Vector Splitting Support: LegalizeVectorTypes.cpp @@ -733,6 +736,7 @@ SDValue SplitVecOp_EXTRACT_SUBVECTOR(SDNode *N); SDValue SplitVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue SplitVecOp_ExtVecInRegOp(SDNode *N); + SDValue SplitVecOp_FAKE_USE(SDNode *N); SDValue SplitVecOp_STORE(StoreSDNode *N, unsigned OpNo); SDValue SplitVecOp_MSTORE(MaskedStoreSDNode *N, unsigned OpNo); SDValue SplitVecOp_MSCATTER(MaskedScatterSDNode *N, unsigned OpNo); @@ -798,6 +802,7 @@ SDValue WidenVecOp_EXTEND(SDNode *N); SDValue WidenVecOp_EXTRACT_VECTOR_ELT(SDNode *N); SDValue WidenVecOp_EXTRACT_SUBVECTOR(SDNode *N); + SDValue WidenVecOp_FAKE_USE(SDNode *N); SDValue WidenVecOp_STORE(SDNode* N); SDValue WidenVecOp_MSTORE(SDNode* N, unsigned OpNo); SDValue WidenVecOp_MGATHER(SDNode* N, unsigned OpNo); @@ -913,6 +918,7 @@ SDValue ExpandOp_BITCAST (SDNode *N); SDValue ExpandOp_BUILD_VECTOR (SDNode *N); SDValue ExpandOp_EXTRACT_ELEMENT (SDNode *N); + SDValue ExpandOp_FAKE_USE (SDNode *N); SDValue ExpandOp_INSERT_VECTOR_ELT(SDNode *N); SDValue ExpandOp_SCALAR_TO_VECTOR (SDNode *N); SDValue ExpandOp_NormalStore (SDNode *N, unsigned OpNo); Index: lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp +++ lib/CodeGen/SelectionDAG/LegalizeTypesGeneric.cpp @@ -410,6 +410,18 @@ return cast(N->getOperand(1))->getZExtValue() ? Hi : Lo; } +// Split the integer operand in two and create a second FAKE_USE node for +// the other half. The original SDNode is updated in place. +SDValue DAGTypeLegalizer::ExpandOp_FAKE_USE(SDNode *N) +{ + SDValue Lo, Hi; + SDValue Chain = N->getOperand(0); + GetExpandedOp(N->getOperand(1), Lo, Hi); + SDValue LoUse = DAG.getNode(ISD::FAKE_USE, SDLoc(), MVT::Other, Chain, Lo); + DAG.UpdateNodeOperands(N, LoUse, Hi); + return SDValue(N, 0); +} + SDValue DAGTypeLegalizer::ExpandOp_INSERT_VECTOR_ELT(SDNode *N) { // The vector type is legal but the element type needs expansion. EVT VecVT = N->getValueType(0); Index: lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeVectorTypes.cpp @@ -522,6 +522,9 @@ case ISD::BITCAST: Res = ScalarizeVecOp_BITCAST(N); break; + case ISD::FAKE_USE: + Res = ScalarizeVecOp_FAKE_USE(N); + break; case ISD::ANY_EXTEND: case ISD::ZERO_EXTEND: case ISD::SIGN_EXTEND: @@ -576,6 +579,14 @@ N->getValueType(0), Elt); } +// Need to legalize vector operands of fake uses. Must be <1 x ty>. +SDValue DAGTypeLegalizer::ScalarizeVecOp_FAKE_USE(SDNode *N) { + assert(N->getOperand(1).getValueType().getVectorNumElements() == 1 && + "Fake Use: Unexpected vector type!"); + SDValue Elt = GetScalarizedVector(N->getOperand(1)); + return DAG.getNode(ISD::FAKE_USE, SDLoc(), MVT::Other, N->getOperand(0), Elt); +} + /// If the input is a vector that needs to be scalarized, it must be <1 x ty>. /// Do the operation on the element instead. SDValue DAGTypeLegalizer::ScalarizeVecOp_UnaryOp(SDNode *N) { @@ -1720,6 +1731,10 @@ Res = SplitVecOp_UnaryOp(N); break; + case ISD::FAKE_USE: + Res = SplitVecOp_FAKE_USE(N); + break; + case ISD::ANY_EXTEND_VECTOR_INREG: case ISD::SIGN_EXTEND_VECTOR_INREG: case ISD::ZERO_EXTEND_VECTOR_INREG: @@ -1852,6 +1867,15 @@ return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi); } +// Split a FAKE_USE use of a vector into FAKE_USEs of hi and lo part. +SDValue DAGTypeLegalizer::SplitVecOp_FAKE_USE(SDNode *N) { + SDValue Lo, Hi; + GetSplitVector(N->getOperand(1), Lo, Hi); + SDValue Chain = + DAG.getNode(ISD::FAKE_USE, SDLoc(), MVT::Other, N->getOperand(0), Lo); + return DAG.getNode(ISD::FAKE_USE, SDLoc(), MVT::Other, Chain, Hi); +} + SDValue DAGTypeLegalizer::SplitVecOp_BITCAST(SDNode *N) { // For example, i64 = BITCAST v4i16 on alpha. Typically the vector will // end up being split all the way down to individual components. Convert the @@ -3663,6 +3687,7 @@ llvm_unreachable("Do not know how to widen this operator's operand!"); case ISD::BITCAST: Res = WidenVecOp_BITCAST(N); break; + case ISD::FAKE_USE: Res = WidenVecOp_FAKE_USE(N); break; case ISD::CONCAT_VECTORS: Res = WidenVecOp_CONCAT_VECTORS(N); break; case ISD::EXTRACT_SUBVECTOR: Res = WidenVecOp_EXTRACT_SUBVECTOR(N); break; case ISD::EXTRACT_VECTOR_ELT: Res = WidenVecOp_EXTRACT_VECTOR_ELT(N); break; @@ -3835,6 +3860,16 @@ return CreateStackStoreLoad(InOp, VT); } +// Vectors with sizes that are not powers of 2 need to be widened to the +// next largest power of 2. For example, we may get a vector of 3 32-bit +// integers or of 6 16-bit integers, both of which have to be widened to a +// 128-bit vector. +SDValue DAGTypeLegalizer::WidenVecOp_FAKE_USE(SDNode *N) { + SDValue WidenedOp = GetWidenedVector(N->getOperand(1)); + return DAG.getNode( + ISD::FAKE_USE, SDLoc(), MVT::Other, N->getOperand(0), WidenedOp); +} + SDValue DAGTypeLegalizer::WidenVecOp_CONCAT_VECTORS(SDNode *N) { EVT VT = N->getValueType(0); EVT EltVT = VT.getVectorElementType(); Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2472,6 +2472,7 @@ switch (Fn->getIntrinsicID()) { default: llvm_unreachable("Cannot invoke this intrinsic"); + case Intrinsic::fake_use: case Intrinsic::donothing: // Ignore invokes to @llvm.donothing: jump directly to the next BB. break; @@ -6178,6 +6179,14 @@ return nullptr; } + case Intrinsic::fake_use: { + SDValue Ops[2]; + Ops[0] = getRoot(); + Ops[1] = getValue(I.getArgOperand(0)); + DAG.setRoot(DAG.getNode(ISD::FAKE_USE, sdl, MVT::Other, Ops)); + return nullptr; + } + case Intrinsic::eh_exceptionpointer: case Intrinsic::eh_exceptioncode: { // Get the exception pointer vreg, copy from it, and resize it to fit. Index: lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -352,6 +352,7 @@ case ISD::DEBUGTRAP: return "debugtrap"; case ISD::LIFETIME_START: return "lifetime.start"; case ISD::LIFETIME_END: return "lifetime.end"; + case ISD::FAKE_USE: return "fake_use"; case ISD::GC_TRANSITION_START: return "gc_transition.start"; case ISD::GC_TRANSITION_END: return "gc_transition.end"; case ISD::GET_DYNAMIC_AREA_OFFSET: return "get.dynamic.area.offset"; Index: lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -647,6 +647,59 @@ ORE.emit(R); } +// Return true if operand 0 of a fake use is def'd by a given TailCall +// instruction or if it is def'd after it. +static bool opDefdByOrAfter(BasicBlock::iterator FakeUse, + BasicBlock::iterator TailCall) { + llvm::Value *Op = FakeUse->getOperand(0); + if (auto Def = dyn_cast(Op)) + for (BasicBlock::const_iterator Inst = TailCall; Inst != FakeUse; ++Inst) + if (&*Inst == Def) + return true; + return false; +} + +// Detect any fake uses that follow a tail call and move them before the tail +// call. Ignore fake uses that use values that are def'd by or after the tail +// call. +static void preserveFakeUses(SelectionDAGBuilder *SDB, + BasicBlock::iterator Begin, + BasicBlock::iterator End) { + BasicBlock::iterator I = End; + if (--I == Begin || !isa(*I)) + return; + // Detect whether there are any fake uses trailing a (potential) tail call. + bool HaveFakeUse = false; + bool HaveTailCall = false; + do { + if (const CallInst *CI = dyn_cast(--I)) + if (CI->isTailCall()) { + HaveTailCall = true; + break; + } + if (const IntrinsicInst *II = dyn_cast(I)) + if (II->getIntrinsicID() == Intrinsic::fake_use) + HaveFakeUse = true; + } while (I != Begin); + + // If we didn't find any tail calls followed by fake uses, we are done. + if (!HaveTailCall || !HaveFakeUse) + return; + + std::vector FakeUses; + // Record the fake uses we found so we can move them to the front of the + // tail call. Ignore them if they use a value that is def'd by or after + // the tail call. + for (BasicBlock::iterator Inst = I; Inst != End; Inst++) + if (IntrinsicInst *II = dyn_cast(Inst)) + if (II->getIntrinsicID() == Intrinsic::fake_use) + if (!opDefdByOrAfter(Inst, I)) + FakeUses.push_back(&*Inst); + + for (auto *Inst : FakeUses) + Inst->moveBefore(*Inst->getParent(), I); +} + void SelectionDAGISel::SelectBasicBlock(BasicBlock::const_iterator Begin, BasicBlock::const_iterator End, bool &HadTailCall) { @@ -1617,6 +1670,16 @@ FuncInfo->VisitedBBs.insert(LLVMBB); } + // Fake uses that follow tail calls are dropped. To avoid this, move + // such fake uses in front of the tail call, provided they don't + // use anything def'd by or after the tail call. + { + BasicBlock::iterator BBStart = + const_cast(LLVMBB)->getFirstNonPHI()->getIterator(); + BasicBlock::iterator BBEnd = const_cast(LLVMBB)->end(); + preserveFakeUses(SDB, BBStart, BBEnd); + } + BasicBlock::const_iterator const Begin = LLVMBB->getFirstNonPHI()->getIterator(); BasicBlock::const_iterator const End = LLVMBB->end(); @@ -2460,6 +2523,14 @@ CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); } +// Use the generic target FAKE_USE target opcode. The chain operand +// must come last, because InstrEmitter::AddOperand() requires it. +void SelectionDAGISel::Select_FAKE_USE(SDNode *N) { + CurDAG->SelectNodeTo(N, TargetOpcode::FAKE_USE, N->getValueType(0), + N->getOperand(1), N->getOperand(0)); +} + + /// GetVBR - decode a vbr encoding whose top bit is set. LLVM_ATTRIBUTE_ALWAYS_INLINE static inline uint64_t GetVBR(uint64_t Val, const unsigned char *MatcherTable, unsigned &Idx) { @@ -2983,6 +3054,9 @@ case ISD::UNDEF: Select_UNDEF(NodeToMatch); return; + case ISD::FAKE_USE: + Select_FAKE_USE(NodeToMatch); + return; } assert(!NodeToMatch->isMachineOpcode() && "Node already selected!"); Index: lib/IR/Verifier.cpp =================================================================== --- lib/IR/Verifier.cpp +++ lib/IR/Verifier.cpp @@ -3948,6 +3948,7 @@ F->getIntrinsicID() == Intrinsic::coro_destroy || F->getIntrinsicID() == Intrinsic::experimental_patchpoint_void || F->getIntrinsicID() == Intrinsic::experimental_patchpoint_i64 || + F->getIntrinsicID() == Intrinsic::fake_use || F->getIntrinsicID() == Intrinsic::experimental_gc_statepoint, "Cannot invoke an intrinsic other than donothing, patchpoint, " "statepoint, coro_resume or coro_destroy", Index: lib/Target/X86/X86FloatingPoint.cpp =================================================================== --- lib/Target/X86/X86FloatingPoint.cpp +++ lib/Target/X86/X86FloatingPoint.cpp @@ -427,6 +427,24 @@ if (MI.isCall()) FPInstClass = X86II::SpecialFP; + // A fake_use with a floating point pseudo register argument that is + // killed must behave like any other floating point operation and pop + // the floating point stack (this is done in handleSpecialFP()). + // Fake_use is, however, unusual, in that sometimes its operand is not + // killed because a later instruction (probably a return) will use it. + // It is this instruction that will pop the stack. + // In this scenario we can safely remove the fake_use's operand + // (it is live anyway). + if (MI.isFakeUse()) { + const MachineOperand &MO = MI.getOperand(0); + if (MO.isReg() && X86::RFP80RegClass.contains(MO.getReg())) { + if (MO.isKill()) + FPInstClass = X86II::SpecialFP; + else + MI.RemoveOperand(0); + } + } + if (FPInstClass == X86II::NotFP) continue; // Efficiently ignore non-fp insts! @@ -1658,6 +1676,21 @@ // Don't delete the inline asm! return; } + + // FAKE_USE must pop its register operand off the stack if it is killed, + // because this constitutes the register's last use. If the operand + // is not killed, it will have its last use later, so we leave it alone. + // In either case we remove the operand so later passes don't see it. + case TargetOpcode::FAKE_USE: { + assert(MI.getNumExplicitOperands() == 1 && + "FAKE_USE must have exactly one operand"); + if (MI.getOperand(0).isKill()) { + freeStackSlotBefore(Inst, getFPReg(MI.getOperand(0))); + } + MI.RemoveOperand(0); + return; + } + } Inst = MBB->erase(Inst); // Remove the pseudo instruction Index: lib/Transforms/Utils/CloneFunction.cpp =================================================================== --- lib/Transforms/Utils/CloneFunction.cpp +++ lib/Transforms/Utils/CloneFunction.cpp @@ -319,6 +319,12 @@ for (BasicBlock::const_iterator II = StartingInst, IE = --BB->end(); II != IE; ++II) { + // Don't clone fake_use as it may suppress many optimizations + // due to inlining, especially SROA. + if (auto *IntrInst = dyn_cast(II)) + if (IntrInst->getIntrinsicID() == Intrinsic::fake_use) + continue; + Instruction *NewInst = II->clone(); // Eagerly remap operands to the newly cloned instruction, except for PHI Index: lib/Transforms/Utils/Local.cpp =================================================================== --- lib/Transforms/Utils/Local.cpp +++ lib/Transforms/Utils/Local.cpp @@ -2413,6 +2413,9 @@ for (Value::use_iterator UI = From->use_begin(), UE = From->use_end(); UI != UE;) { Use &U = *UI++; + auto *II = dyn_cast(U.getUser()); + if (II && II->getIntrinsicID() == Intrinsic::fake_use) + continue; if (!Dominates(Root, U)) continue; U.set(To); Index: lib/Transforms/Utils/PromoteMemoryToRegister.cpp =================================================================== --- lib/Transforms/Utils/PromoteMemoryToRegister.cpp +++ lib/Transforms/Utils/PromoteMemoryToRegister.cpp @@ -83,7 +83,8 @@ return false; } else if (const IntrinsicInst *II = dyn_cast(U)) { if (II->getIntrinsicID() != Intrinsic::lifetime_start && - II->getIntrinsicID() != Intrinsic::lifetime_end) + II->getIntrinsicID() != Intrinsic::lifetime_end && + II->getIntrinsicID() != Intrinsic::fake_use) return false; } else if (const BitCastInst *BCI = dyn_cast(U)) { if (BCI->getType() != Type::getInt8PtrTy(U->getContext(), AS)) Index: test/CodeGen/ARM/fake-use-longlong.ll =================================================================== --- /dev/null +++ test/CodeGen/ARM/fake-use-longlong.ll @@ -0,0 +1,55 @@ +; Bug: Assertion in type legalization with -fextend-lifetimes. +; +; RUN: llc -O2 -filetype=asm < %s | FileCheck %s +; +; REQUIRES: asserts +; +; Generated with clang -O2 -fextend-lifetimes -S -emit-llvm +; +; extern unsigned long long vbl; +; void foo(void) +; { +; unsigned long long result = vbl; +; } +; +; We check that the 64-bit argument to fake.use does not cause an assertion +; in the backend and furthermore that the instructions that set up the address +; of the variable that holds the value are emitted. Note that we don't want +; to check for a load instruction because it may be optimized away. +; +; ModuleID = 'eapv.c' +; +; CHECK-LABEL: foo: +; CHECK-DAG: movw {{.*}}vbl +; CHECK-DAG: movt {{.*}}vbl +; CHECK: bx lr +; +target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64" +target triple = "armv7a-scei-ps4-eabi" + +@vbl = external global i64, align 8 + +; Function Attrs: norecurse nounwind uwtable +define arm_aapcs_vfpcc void @foo() #0 { +entry: + %0 = load i64, i64* @vbl, align 8, !tbaa !3 + tail call arm_aapcs_vfpcc void (...) @llvm.fake.use(i64 %0) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) #1 + +attributes #0 = { norecurse nounwind uwtable "disable-post-ra" "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="cortex-a9" "target-features"="+dsp,+fp16,+neon,+strict-align,+vfp3" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0, !1} +!llvm.ident = !{!2} + +!0 = !{i32 1, !"wchar_size", i32 2} +!1 = !{i32 1, !"min_enum_size", i32 4} +!2 = !{!"clang version 3.8.1 (EAP clang version 4.00.0.170 a089c432 debug)"} +!3 = !{!4, !4, i64 0} +!4 = !{!"long long", !5, i64 0} +!5 = !{!"omnipotent char", !6, i64 0} +!6 = !{!"Simple C/C++ TBAA"} Index: test/CodeGen/Generic/fake-use-constprop.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/fake-use-constprop.ll @@ -0,0 +1,90 @@ +; RUN: opt -gvn %s | FileCheck %s +; +; The Global Value Numbering pass (GVN) propagates boolean values +; that are constant in dominated basic blocks to all the uses +; in these basic blocks. However, we don't want the constant propagated +; into fake.use intrinsics since this would render the intrinsic useless +; with respect to keeping the variable live up until the fake.use. +; This test checks that we don't generate any fake.uses with constant 0. +; +; Generate with clang -O2 -S -emit-llvm -fextend-lifetimes test.c +; +; extern void func1(); +; extern int bar(); +; extern void baz(int); +; +; int foo(int i, float f, int *punused) +; { +; int j = 3*i; +; if (j > 0) { +; int m = bar(i); +; if (m) { +; char b = f; +; baz(b); +; if (b) +; goto lab; +; func1(); +; } +; lab: +; func1(); +; } +; return 1; +; } +; +; ModuleID = 'test.c' +; +; CHECK-NOT: fake.use({{.*}} 0) +; +; Function Attrs: nounwind sspstrong uwtable +define i32 @foo(i32 %i, float %f, i32* %punused) #0 { +entry: + %mul = mul nsw i32 %i, 3 + %cmp = icmp sgt i32 %i, 0 + br i1 %cmp, label %if.then, label %if.end6 + +if.then: ; preds = %entry + %call = tail call i32 (i32, ...) bitcast (i32 (...)* @bar to i32 (i32, ...)*)(i32 %i) #2 + %tobool = icmp eq i32 %call, 0 + br i1 %tobool, label %lab, label %if.then1 + +if.then1: ; preds = %if.then + %conv = fptosi float %f to i8 + %conv2 = sext i8 %conv to i32 + tail call void @baz(i32 %conv2) #2 + %tobool3 = icmp eq i8 %conv, 0 + br i1 %tobool3, label %if.end, label %lab + +if.end: ; preds = %if.then1 + tail call void (...) @func1() #2 + tail call void (...) @llvm.fake.use(i8 signext %conv) + br label %lab + +lab: ; preds = %if.end, %if.then1, %if.then + tail call void (...) @func1() #2 + tail call void (...) @llvm.fake.use(i32 %call) + br label %if.end6 + +if.end6: ; preds = %lab, %entry + tail call void (...) @llvm.fake.use(i32 %i) + tail call void (...) @llvm.fake.use(float %f) + tail call void (...) @llvm.fake.use(i32* %punused) + tail call void (...) @llvm.fake.use(i32 %mul) + ret i32 1 +} + +declare i32 @bar(...) + +declare void @baz(i32) + +declare void @func1(...) + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) + +attributes #0 = { nounwind sspstrong uwtable "no-frame-pointer-elim"="false" } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.9.0 (PS4 clang version 99.99.0.810 2c64e5d5 checking)"} Index: test/CodeGen/Generic/fake-use-tailcall.ll =================================================================== --- /dev/null +++ test/CodeGen/Generic/fake-use-tailcall.ll @@ -0,0 +1,25 @@ +; RUN: llc < %s -stop-after=expand-isel-pseudos -O2 - | FileCheck %s +; Fake uses following tail calls should be pulled in front +; of the TCRETURN instruction. Fake uses using something defined by +; the tail call or after it should be suppressed. + +; CHECK: body: +; CHECK: bb.0.{{.*}}: +; CHECK: %0:{{.*}}= COPY +; CHECK-NOT: FAKE_USE +; CHECK: FAKE_USE %0 +; CHECK-NOT: FAKE_USE +; CHECK: TCRETURN + +define void @bar(i32 %v) { +entry: + %call = tail call i32 @_Z3fooi(i32 %v) + %mul = mul nsw i32 %call, 3 + notail call void (...) @llvm.fake.use(i32 %mul) + notail call void (...) @llvm.fake.use(i32 %call) + notail call void (...) @llvm.fake.use(i32 %v) + ret void +} + +declare i32 @_Z3fooi(i32) local_unnamed_addr +declare void @llvm.fake.use(...) Index: test/CodeGen/X86/fake-use-escape.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fake-use-escape.ll @@ -0,0 +1,37 @@ +; RUN: opt -O2 -S %s | FileCheck %s +; +; Check that we do not assert and that we retain the fake_use +; instruction that uses the address of bar. +; +; CHECK: define{{.*}}foo +; CHECK: call{{.*llvm\.fake\.use.*}}%bar.addr +; +target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-scei-ps4" + +; Function Attrs: nounwind sspstrong uwtable +define void @_Z3fooPi(i32* %bar) #0 { +entry: + %bar.addr = alloca i32*, align 8 + %baz = alloca i8**, align 8 + store i32* %bar, i32** %bar.addr, align 8 + %0 = bitcast i32** %bar.addr to i8** + store i8** %0, i8*** %baz, align 8 + %1 = load i32*, i32** %bar.addr, align 8 + call void (...) @llvm.fake.use(i32* %1) + %2 = load i8**, i8*** %baz, align 8 + call void (...) @llvm.fake.use(i8** %2) + ret void +} + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) #1 + +attributes #0 = { nounwind sspstrong uwtable "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "target-cpu"="btver2" "target-features"="+aes,+avx,+bmi,+cx16,+f16c,+fxsr,+lzcnt,+mmx,+pclmul,+popcnt,+prfchw,+sse,+sse2,+sse3,+sse4.1,+sse4.2,+sse4a,+ssse3,+xsave,+xsaveopt" "unsafe-fp-math"="false" "use-soft-float"="false" } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.9.0 (PS4 clang version 99.99.0.756 e7d04800 checking)"} Index: test/CodeGen/X86/fake-use-hpfloat.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fake-use-hpfloat.ll @@ -0,0 +1,16 @@ +; Bug: Assert in DAGlegalizer with fake use of half precision float. +; RUN: llc -O2 -stop-after=expand-isel-pseudos -filetype=asm -o - %s | FileCheck %s +; +; CHECK: bb.0.entry: +; CHECK: %0:fr32 = FsFLD0SS +; CHECK: FAKE_USE killed %0 +; +target triple = "x86_64-scei-ps4" + +define void @_Z6doTestv() local_unnamed_addr { +entry: + tail call void (...) @llvm.fake.use(half 0xH0000) + ret void +} + +declare void @llvm.fake.use(...) Index: test/CodeGen/X86/fake-use-ld.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fake-use-ld.ll @@ -0,0 +1,63 @@ +; RUN: llc -O0 -mtriple=x86_64-unknown-unknown < %s | FileCheck %s + +; Checks that we can compile without crashing and that a spill is generated +; before the call to fma. This latter fact indicates that the fake.use had +; the desired effect. +; +; /*******************************************************************/ +; extern long double fmal(long double, long double, long double); +; +; long double actual(long double p1, long double p2, long double p3) { +; return fmal(p1, p2, p3); +; } +; /*******************************************************************/ +; +; We just check for the function label, the call and the return +; to demonstrate that the compilation went as expected. +; +; Function Attrs: nounwind sspstrong uwtable +define x86_fp80 @actual(x86_fp80 %p1, x86_fp80 %p2, x86_fp80 %p3) #0 { +; +; CHECK-LABEL: actual +; +entry: + %p1.addr = alloca x86_fp80, align 16 + %p2.addr = alloca x86_fp80, align 16 + %p3.addr = alloca x86_fp80, align 16 + store x86_fp80 %p1, x86_fp80* %p1.addr, align 16 + store x86_fp80 %p2, x86_fp80* %p2.addr, align 16 + store x86_fp80 %p3, x86_fp80* %p3.addr, align 16 + %0 = load x86_fp80, x86_fp80* %p1.addr, align 16 + %1 = load x86_fp80, x86_fp80* %p2.addr, align 16 + %2 = load x86_fp80, x86_fp80* %p3.addr, align 16 +; +; CHECK: callq{{.*}}foobar +; + %3 = call x86_fp80 @foobar(x86_fp80 %0, x86_fp80 %1, x86_fp80 %2) + %4 = load x86_fp80, x86_fp80* %p1.addr, align 16 + call void (...) @llvm.fake.use(x86_fp80 %4) + %5 = load x86_fp80, x86_fp80* %p2.addr, align 16 + call void (...) @llvm.fake.use(x86_fp80 %5) + %6 = load x86_fp80, x86_fp80* %p3.addr, align 16 + call void (...) @llvm.fake.use(x86_fp80 %6) +; +; CHECK: ret +; + ret x86_fp80 %3 +} + +; Function Attrs: nounwind readnone +declare x86_fp80 @foobar(x86_fp80, x86_fp80, x86_fp80) #1 + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) #2 + +attributes #0 = { nounwind sspstrong uwtable } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 3.9.0 (PS4 clang version 99.99.0.736 a4543fa5 checking)"} Index: test/CodeGen/X86/fake-use-vector.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fake-use-vector.ll @@ -0,0 +1,47 @@ +; Bug: Assert in DAGlegalizer with fake use of 1-element vectors. +; RUN: llc -stop-after=expand-isel-pseudos -filetype=asm -o - %s | FileCheck %s +; +; ModuleID = 't2.cpp' +; source_filename = "t2.cpp" +; target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128" +; +; Check that we get past ISel and generate FAKE_USE machine instructions for +; one-element vectors. +; +; CHECK: bb.0.entry: +; CHECK-DAG: %1:gr64 = COPY $rdi +; CHECK-DAG: %0:vr128 = COPY $xmm0 +; CHECK: %2:vr64 = +; CHECK-DAG: FAKE_USE %1 +; CHECK-DAG: FAKE_USE %0 +; CHECK: RET + + +target triple = "x86_64-scei-ps4" + +; Function Attrs: nounwind sspstrong uwtable +define <4 x float> @_Z3runDv4_fDv1_x(<4 x float> %r, i64 %b.coerce) local_unnamed_addr #0 { +entry: + %0 = insertelement <1 x i64> undef, i64 %b.coerce, i32 0 + %1 = bitcast i64 %b.coerce to x86_mmx + %2 = tail call <4 x float> @llvm.x86.sse.cvtpi2ps(<4 x float> %r, x86_mmx %1) + tail call void (...) @llvm.fake.use(<1 x i64> %0) #2 + tail call void (...) @llvm.fake.use(<4 x float> %r) #2 + ret <4 x float> %2 +} + +; Function Attrs: nounwind readnone +declare <4 x float> @llvm.x86.sse.cvtpi2ps(<4 x float>, x86_mmx) #1 + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) #2 + +attributes #0 = { nounwind sspstrong uwtable "target-cpu"="btver2" } +attributes #1 = { nounwind readnone } +attributes #2 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 5.0.0 (PS4 clang version 99.99.0.1035 178bad39 checking)"} Index: test/CodeGen/X86/fake-use-vector2.ll =================================================================== --- /dev/null +++ test/CodeGen/X86/fake-use-vector2.ll @@ -0,0 +1,37 @@ +; RUN: llc -stop-after=expand-isel-pseudos -filetype=asm -o - %s | FileCheck %s +; +; Make sure we can split vectors that are used as operands of +; FAKE_USE. + +; Generated from: +; +; typedef long __attribute__((ext_vector_type(8))) long8; +; void test0() { long8 id208 {0, 1, 2, 3, 4, 5, 6, 7}; } +; +; CHECK: %0:vr256 = VMOV +; CHECK: %1:vr256 = VMOV +; CHECK-DAG: FAKE_USE killed %1 +; CHECK-DAG: FAKE_USE killed %0 +; CHECK: RET +; +; ModuleID = 't5.cpp' +source_filename = "t5.cpp" + +; Function Attrs: nounwind sspstrong uwtable +define void @_Z5test0v() local_unnamed_addr #0 { +entry: + tail call void (...) @llvm.fake.use(<8 x i64> ) #1 + ret void +} + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) #1 + +attributes #0 = { nounwind sspstrong uwtable "target-cpu"="btver2" } +attributes #1 = { nounwind } + +!llvm.module.flags = !{!0} +!llvm.ident = !{!1} + +!0 = !{i32 1, !"PIC Level", i32 2} +!1 = !{!"clang version 5.0.0 (PS4 clang version 99.99.0.1037 23c8e815 checking)"} Index: test/DebugInfo/X86/Inputs/check-fake-use.py =================================================================== --- /dev/null +++ test/DebugInfo/X86/Inputs/check-fake-use.py @@ -0,0 +1,98 @@ +# Parsing dwarfdump's output to determine whether the location list for the +# parameter "b" covers all of the function. The script is written in form of a +# state machine and expects that dwarfdump output adheres to a certain order: +# 1) The .debug_info section must appear before the .debug_loc section. +# 2) The DW_AT_location attribute must appear before the parameter's name in the +# formal parameter DIE. +# +import re +import sys + +DebugInfoPattern = r'\.debug_info contents:' +SubprogramPattern = r'^0x[0-9a-f]+:\s+DW_TAG_subprogram' +HighPCPattern = r'DW_AT_high_pc.*0x([0-9a-f]+)' +FormalPattern = r'^0x[0-9a-f]+:\s+DW_TAG_formal_parameter' +LocationPattern = r'DW_AT_location\s+\[DW_FORM_sec_offset\].*0x([a-f0-9]+)' +DebugLocPattern = r'\[0x([a-f0-9]+),\s+0x([a-f0-9]+)\):' + +# States +LookingForDebugInfo = 0 +LookingForSubProgram = LookingForDebugInfo + 1 #1 +LookingForHighPC = LookingForSubProgram + 1 #2 +LookingForFormal = LookingForHighPC + 1 #3 +LookingForLocation = LookingForFormal + 1 #4 +DebugLocations = LookingForLocation + 1 #5 +AllDone = DebugLocations + 1 #6 + +# For each state, the state table contains 3-item sublists with the following +# entries: +# 1) The regex pattern we use in each state. +# 2) The state we enter when we have a successful match for the current pattern. +# 3) The state we enter when we do not have a successful match for the +# current pattern. +StateTable = [ + # LookingForDebugInfo + [ DebugInfoPattern, LookingForSubProgram, LookingForDebugInfo ], + # LookingForSubProgram + [ SubprogramPattern, LookingForHighPC, LookingForSubProgram ], + # LookingForHighPC + [ HighPCPattern, LookingForFormal, LookingForHighPC ], + # LookingForFormal + [ FormalPattern, LookingForLocation, LookingForFormal ], + # LookingForLocation + [ LocationPattern, DebugLocations, LookingForFormal ], + # DebugLocations + [ DebugLocPattern, DebugLocations, AllDone ], + # AllDone + [ None, AllDone, AllDone ] +] + +# Symbolic indices +StatePattern = 0 +NextState = 1 +FailState = 2 + +State = LookingForDebugInfo +FirstBeginOffset = -1 + +# Read output from file provided as command arg +with open(sys.argv[1], "r") as dwarf_dump_file: + for line in dwarf_dump_file: + if State == AllDone: + break + Pattern = StateTable[State][StatePattern] + # print "State: %d - Searching '%s' for '%s'" % (State, line, Pattern) + m = re.search(Pattern, line) + if m: + # Match. Depending on the state, we extract various values. + if State == LookingForHighPC: + HighPC = int(m.group(1), 16) + elif State == DebugLocations: + # Extract the range values + if FirstBeginOffset == -1: + FirstBeginOffset = int(m.group(1), 16) + # print "FirstBeginOffset set to %d" % FirstBeginOffset + EndOffset = int(m.group(2), 16) + # print "EndOffset set to %d" % EndOffset + State = StateTable[State][NextState] + else: + State = StateTable[State][FailState] + +Success = True + +# Check that the first entry start with 0 and that the last ending address +# in our location list is close to the high pc of the subprogram. +if State != AllDone: + print('Error in expected sequence of DWARF information:') + print(' State = %d\n' % State) + Success = False +elif FirstBeginOffset == -1: + print('Location list for \'b\' not found, did the debug info format change?') + Success = False +elif FirstBeginOffset != 0 or abs(EndOffset - HighPC) > 16: + print('Location list for \'b\' does not cover the whole function:') + print('Location starts at 0x%x, ends at 0x%x, HighPC = 0x%x' % + (FirstBeginOffset, EndOffset, HighPC)) + Success = False + +sys.exit(not Success) Index: test/DebugInfo/X86/fake-use.ll =================================================================== --- /dev/null +++ test/DebugInfo/X86/fake-use.ll @@ -0,0 +1,98 @@ +; REQUIRES: object-emission + +; Make sure the fake use of 'b' at the end of 'foo' causes location information for 'b' +; to extend all the way to the end of the function. + +; RUN: %llc_dwarf -O2 -filetype=obj -dwarf-linkage-names=Abstract < %s | llvm-dwarfdump -v - -o %t +; RUN: %python %p/Inputs/check-fake-use.py %t + +; Generated with: +; clang -O2 -g -S -emit-llvm -fextend-this-ptr sce-fake-use.c +; +; int glob[10]; +; extern void bar(); +; +; int foo(int b, int i) +; { +; int loc = glob[i] * 2; +; if (b) { +; glob[2] = loc; +; bar(); +; } +; return loc; +; } +; +; ModuleID = 't2.c' +source_filename = "t2.c" + +@glob = common local_unnamed_addr global [10 x i32] zeroinitializer, align 16, !dbg !0 + +; Function Attrs: nounwind sspstrong uwtable +define i32 @foo(i32 %b, i32 %i) local_unnamed_addr !dbg !13 { +entry: + tail call void @llvm.dbg.value(metadata i32 %b, i64 0, metadata !17, metadata !20), !dbg !21 + %idxprom = sext i32 %i to i64, !dbg !22 + %arrayidx = getelementptr inbounds [10 x i32], [10 x i32]* @glob, i64 0, i64 %idxprom, !dbg !22 + %0 = load i32, i32* %arrayidx, align 4, !dbg !22, !tbaa !23 + %mul = shl nsw i32 %0, 1, !dbg !22 + %tobool = icmp eq i32 %b, 0, !dbg !27 + br i1 %tobool, label %if.end, label %if.then, !dbg !29 + +if.then: ; preds = %entry + store i32 %mul, i32* getelementptr inbounds ([10 x i32], [10 x i32]* @glob, i64 0, i64 2), align 8, !dbg !30, !tbaa !23 + tail call void (...) @bar() #2, !dbg !32 + br label %if.end, !dbg !33 + +if.end: ; preds = %entry, %if.then + tail call void (...) @llvm.fake.use(i32 %b), !dbg !34 + ret i32 %mul, !dbg !35 +} + +declare void @bar(...) local_unnamed_addr + +; Function Attrs: nounwind +declare void @llvm.fake.use(...) + +; Function Attrs: nounwind readnone +declare void @llvm.dbg.value(metadata, i64, metadata, metadata) + +!llvm.dbg.cu = !{!1} +!llvm.module.flags = !{!9, !10, !11} +!llvm.ident = !{!12} + +!0 = distinct !DIGlobalVariableExpression(var: !DIGlobalVariable(name: "glob", scope: !1, file: !2, line: 1, type: !5, isLocal: false, isDefinition: true), expr: !DIExpression()) +!1 = distinct !DICompileUnit(language: DW_LANG_C99, file: !2, producer: "clang version 4.0.0 (PS4 clang version 99.99.0.898 da49a30f checking)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !3, globals: !4) +!2 = !DIFile(filename: "t2.c", directory: "D:\5CPS4\5CBugzillas\5CBZ138432") +!3 = !{} +!4 = !{!0} +!5 = !DICompositeType(tag: DW_TAG_array_type, baseType: !6, size: 320, align: 32, elements: !7) +!6 = !DIBasicType(name: "int", size: 32, align: 32, encoding: DW_ATE_signed) +!7 = !{!8} +!8 = !DISubrange(count: 10) +!9 = !{i32 2, !"Dwarf Version", i32 4} +!10 = !{i32 2, !"Debug Info Version", i32 3} +!11 = !{i32 1, !"PIC Level", i32 2} +!12 = !{!"clang version 4.0.0 (PS4 clang version 99.99.0.898 da49a30f checking)"} +!13 = distinct !DISubprogram(name: "foo", scope: !2, file: !2, line: 4, type: !14, isLocal: false, isDefinition: true, scopeLine: 5, flags: DIFlagPrototyped, isOptimized: true, unit: !1, retainedNodes: !16) +!14 = !DISubroutineType(types: !15) +!15 = !{!6, !6, !6} +!16 = !{!17, !18, !19} +!17 = !DILocalVariable(name: "b", arg: 1, scope: !13, file: !2, line: 4, type: !6) +!18 = !DILocalVariable(name: "i", arg: 2, scope: !13, file: !2, line: 4, type: !6) +!19 = !DILocalVariable(name: "loc", scope: !13, file: !2, line: 6, type: !6) +!20 = !DIExpression() +!21 = !DILocation(line: 4, scope: !13) +!22 = !DILocation(line: 6, scope: !13) +!23 = !{!24, !24, i64 0} +!24 = !{!"int", !25, i64 0} +!25 = !{!"omnipotent char", !26, i64 0} +!26 = !{!"Simple C/C++ TBAA"} +!27 = !DILocation(line: 7, scope: !28) +!28 = distinct !DILexicalBlock(scope: !13, file: !2, line: 7) +!29 = !DILocation(line: 7, scope: !13) +!30 = !DILocation(line: 8, scope: !31) +!31 = distinct !DILexicalBlock(scope: !28, file: !2, line: 7) +!32 = !DILocation(line: 9, scope: !31) +!33 = !DILocation(line: 10, scope: !31) +!34 = !DILocation(line: 12, scope: !13) +!35 = !DILocation(line: 11, scope: !13)