@@ -771,39 +771,42 @@ static void cleanUpDeadVals(RDVFinalCleanupList &list) {
771771 // 4. Operands
772772 LDBG () << " Cleaning up " << list.operands .size () << " operand lists" ;
773773 for (OperationToCleanup &o : list.operands ) {
774- if ( auto call = dyn_cast<CallOpInterface>(o. op )) {
775- // Use the stored callee reference if available, avoiding expensive symbol
776- // lookup
777- if (o.callee ) {
778- auto it = erasedFuncArgs. find (o.callee );
779- if ( it ! = erasedFuncArgs.end ()) {
780- const BitVector &deadArgIdxs = it-> second ;
781- MutableOperandRange args = call. getArgOperandsMutable () ;
782- // First, erase the call arguments corresponding to erased callee
783- // args.
784- for ( int i = static_cast < int >( args.size ()) - 1 ; i >= 0 ; --i) {
785- if (i < static_cast <int >(deadArgIdxs .size ()) && deadArgIdxs. test (i))
786- args. erase (i);
787- }
788- // If this operand cleanup entry also has a generic nonLive bitvector,
789- // clear bits for call arguments we already erased above to avoid
790- // double-erasing (which could impact other segments of ops with
791- // AttrSizedOperandSegments).
792- if (o. nonLive . any ()) {
793- // Map the argument logical index to the operand number(s) recorded.
794- int operandOffset = call. getArgOperands (). getBeginOperandIndex ();
795- for ( int argIdx : deadArgIdxs. set_bits ()) {
796- int operandNumber = operandOffset + argIdx;
797- if (operandNumber < static_cast < int >(o. nonLive . size ()))
798- o.nonLive .reset (operandNumber);
799- }
774+ // Handle call-specific cleanup only when we have a cached callee reference.
775+ // This avoids expensive symbol lookup and is defensive against future changes.
776+ bool handledAsCall = false ;
777+ if (o.callee && isa<CallOpInterface>(o. op ) ) {
778+ auto call = cast<CallOpInterface> (o.op );
779+ auto it = erasedFuncArgs.find (o. callee );
780+ if (it != erasedFuncArgs. end ()) {
781+ const BitVector &deadArgIdxs = it-> second ;
782+ MutableOperandRange args = call. getArgOperandsMutable ();
783+ // First, erase the call arguments corresponding to erased callee
784+ // args.
785+ for ( int i = static_cast <int >(args .size ()) - 1 ; i >= 0 ; --i) {
786+ if (i < static_cast < int >(deadArgIdxs. size ()) && deadArgIdxs. test (i))
787+ args. erase (i);
788+ }
789+ // If this operand cleanup entry also has a generic nonLive bitvector,
790+ // clear bits for call arguments we already erased above to avoid
791+ // double-erasing (which could impact other segments of ops with
792+ // AttrSizedOperandSegments).
793+ if (o. nonLive . any ()) {
794+ // Map the argument logical index to the operand number(s) recorded.
795+ int operandOffset = call. getArgOperands (). getBeginOperandIndex ();
796+ for ( int argIdx : deadArgIdxs. set_bits ()) {
797+ int operandNumber = operandOffset + argIdx;
798+ if (operandNumber < static_cast < int >( o.nonLive .size ()))
799+ o. nonLive . reset (operandNumber);
800800 }
801801 }
802+ handledAsCall = true ;
802803 }
803804 }
804- // Only perform generic operand erasure for non-call ops; for call ops we
805- // already handled argument removals via the segment-aware path above.
806- if (!isa<CallOpInterface>(o.op ) && o.nonLive .any ()) {
805+ // Perform generic operand erasure for:
806+ // - Non-call operations
807+ // - Call operations without cached callee (where handledAsCall is false)
808+ // But skip call operations that were already handled via segment-aware path
809+ if (!handledAsCall && o.nonLive .any ()) {
807810 o.op ->eraseOperands (o.nonLive );
808811 }
809812 }
0 commit comments