Index: include/llvm/Analysis/PtrUseVisitor.h =================================================================== --- include/llvm/Analysis/PtrUseVisitor.h +++ include/llvm/Analysis/PtrUseVisitor.h @@ -287,6 +287,12 @@ case Intrinsic::lifetime_start: case Intrinsic::lifetime_end: return; // No-op intrinsics. + + // fake_use is a noop. A pointer used by a fake_use is escaped to prevent + // SROA from transforming it. + case Intrinsic::fake_use: + PI.setEscaped(&II); + return; } } Index: include/llvm/CodeGen/ISDOpcodes.h =================================================================== --- include/llvm/CodeGen/ISDOpcodes.h +++ include/llvm/CodeGen/ISDOpcodes.h @@ -801,6 +801,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 @@ -866,6 +866,8 @@ 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 { @@ -890,6 +892,7 @@ case TargetOpcode::EH_LABEL: case TargetOpcode::GC_LABEL: case TargetOpcode::DBG_VALUE: + case TargetOpcode::FAKE_USE: return true; } } Index: include/llvm/CodeGen/SelectionDAGISel.h =================================================================== --- include/llvm/CodeGen/SelectionDAGISel.h +++ include/llvm/CodeGen/SelectionDAGISel.h @@ -283,6 +283,7 @@ void Select_READ_REGISTER(SDNode *N); void Select_WRITE_REGISTER(SDNode *N); void Select_UNDEF(SDNode *N); + void Select_FAKE_USE(SDNode *N); void CannotYetSelect(SDNode *N); private: Index: include/llvm/CodeGen/TargetOpcodes.def =================================================================== --- include/llvm/CodeGen/TargetOpcodes.def +++ include/llvm/CodeGen/TargetOpcodes.def @@ -187,6 +187,9 @@ /// patched to insert instrumentation instructions. HANDLE_TARGET_OPCODE(PATCHABLE_EVENT_CALL) +/// 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/IR/Intrinsics.td =================================================================== --- include/llvm/IR/Intrinsics.td +++ include/llvm/IR/Intrinsics.td @@ -827,6 +827,9 @@ def int_clear_cache : Intrinsic<[], [llvm_ptr_ty, llvm_ptr_ty], [], "llvm.clear_cache">; +// 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/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -1081,6 +1081,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 unknown:$dst); let InOperandList = (ins variable_ops); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1064,6 +1064,8 @@ case TargetOpcode::KILL: if (isVerbose()) emitKill(&MI, *this); break; + case TargetOpcode::FAKE_USE: + break; default: EmitInstruction(&MI); break; Index: lib/CodeGen/DeadMachineInstructionElim.cpp =================================================================== --- lib/CodeGen/DeadMachineInstructionElim.cpp +++ lib/CodeGen/DeadMachineInstructionElim.cpp @@ -65,7 +65,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 @@ -354,7 +354,7 @@ bool MachineCSE::isCSECandidate(MachineInstr *MI) { if (MI->isPosition() || MI->isPHI() || MI->isImplicitDef() || MI->isKill() || - MI->isInlineAsm() || MI->isDebugValue()) + MI->isInlineAsm() || MI->isDebugValue() || MI->isFakeUse()) return false; // Ignore copies. Index: lib/CodeGen/SelectionDAG/FastISel.cpp =================================================================== --- lib/CodeGen/SelectionDAG/FastISel.cpp +++ lib/CodeGen/SelectionDAG/FastISel.cpp @@ -1264,6 +1264,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/LegalizeIntegerTypes.cpp =================================================================== --- lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp +++ lib/CodeGen/SelectionDAG/LegalizeIntegerTypes.cpp @@ -908,6 +908,9 @@ 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: @@ -2888,6 +2891,9 @@ 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; @@ -3555,6 +3561,17 @@ return DAG.getAnyExtOrTrunc(Ext, dl, N->getValueType(0)); } +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 @@ -293,6 +293,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); @@ -630,6 +631,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 @@ -681,6 +683,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); @@ -745,6 +748,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_MSCATTER(SDNode* N, unsigned OpNo); @@ -862,6 +866,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 @@ -409,6 +409,17 @@ 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 @@ -451,6 +451,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: @@ -505,6 +508,14 @@ N->getValueType(0), Elt); } +/// Scalarize the operand of a fake use. The vector 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) { @@ -1551,6 +1562,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: @@ -1683,6 +1698,14 @@ return DAG.getNode(ISD::CONCAT_VECTORS, dl, ResVT, Lo, Hi); } +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 @@ -3315,6 +3338,9 @@ 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; @@ -3476,6 +3502,12 @@ return CreateStackStoreLoad(InOp, VT); } +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) { // If the input vector is not legal, it is likely that we will not find a // legal vector of the same size. Replace the concatenate vector with a Index: lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp =================================================================== --- lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp +++ lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp @@ -2378,6 +2378,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; @@ -5961,6 +5962,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 @@ -316,6 +316,8 @@ 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 @@ -2305,6 +2305,11 @@ CurDAG->SelectNodeTo(N, TargetOpcode::IMPLICIT_DEF, N->getValueType(0)); } +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) { @@ -2955,6 +2960,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 @@ -3803,6 +3803,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 @@ -426,6 +426,23 @@ 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! @@ -1651,7 +1668,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 @@ -326,6 +326,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 @@ -1847,6 +1847,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/DebugInfo/X86/Inputs/check-fake-use.py =================================================================== --- test/DebugInfo/X86/Inputs/check-fake-use.py +++ test/DebugInfo/X86/Inputs/check-fake-use.py @@ -0,0 +1,94 @@ +# 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]+) - 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 + +for line in sys.stdin: + if State == AllDone: + break + Pattern = StateTable[State][StatePattern] + 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) + EndOffset = int(m.group(2), 16) + State = StateTable[State][NextState] + else: + State = StateTable[State][FailState] + +Success = True + +# Check that the first entry starts 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 =================================================================== --- test/DebugInfo/X86/fake-use.ll +++ test/DebugInfo/X86/fake-use.ll @@ -0,0 +1,99 @@ +; 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 -O3 -filetype=obj -dwarf-linkage-names=Abstract < %s | llvm-dwarfdump -v - | %python %p/Inputs/check-fake-use.py + +; Generated with: +; clang -O2 -g -S -emit-llvm -fextend-this-ptr 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(); bar(); 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 + tail call void (...) @bar() #2, !dbg !32 + 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:\test") +!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, variables: !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)