This is an archive of the discontinued LLVM Phabricator instance.

[NFC][MachineInstr] Pass-by-value DebugLoc in CreateMachineInstr
ClosedPublic

Authored by mtrofin on Dec 6 2021, 5:36 PM.

Details

Summary

DebugLoc is cheap to move, passing it by-val rather than const ref to take advantage of the fact that it is consumed that way by the MachineInstr ctor, which creates some optimization oportunities.

Diff Detail

Event Timeline

mtrofin created this revision.Dec 6 2021, 5:36 PM
mtrofin requested review of this revision.Dec 6 2021, 5:36 PM
Herald added a project: Restricted Project. · View Herald TranscriptDec 6 2021, 5:36 PM

I /think/ given that DebugLoc has a TrackingMDNodeRef member, which has a TrackingMDRef member which has cheaper move than copy, then DebugLoc /probably/ should be passed by value when a copy is going to be made - since it means callers can pass by lvalue or rvalue and get move opportunities when possible.

Given this API scenario:

CheapToMove Dest;
void Caller() {
  CheapToMove Source;
  Intermediate(Source); // 1 
  Intermediate(CheapToMove()); //2
}
void Implementation(/* What Type Goes here? */ CTM) {
  Dest = std::move(CTM); // move is a no-op here if CTM hapens to be a const ref
}

If the type is const ref, then (1) produces a single copy and (2) produces a single copy.
If the type is by-value, then (1) produces a move and a copy (worse by a copy, that should be cheap), and (2) produces 2 moves (better for cheaply movable things).

Does that make sense?

I /think/ given that DebugLoc has a TrackingMDNodeRef member, which has a TrackingMDRef member which has cheaper move than copy, then DebugLoc /probably/ should be passed by value when a copy is going to be made - since it means callers can pass by lvalue or rvalue and get move opportunities when possible.

Given this API scenario:

CheapToMove Dest;
void Caller() {
  CheapToMove Source;
  Intermediate(Source); // 1 
  Intermediate(CheapToMove()); //2
}
void Implementation(/* What Type Goes here? */ CTM) {
  Dest = std::move(CTM); // move is a no-op here if CTM hapens to be a const ref
}

If the type is const ref, then (1) produces a single copy and (2) produces a single copy.
If the type is by-value, then (1) produces a move and a copy (worse by a copy, that should be cheap), and (2) produces 2 moves (better for cheaply movable things).

Does that make sense?

Ah, so you're saying MachineFunction::CreateMachineInstr should instead accept its DebugLoc by value - leaving the rest unchanged (i.e. revert this patch and change CreateMachineInstr instead)?

I /think/ given that DebugLoc has a TrackingMDNodeRef member, which has a TrackingMDRef member which has cheaper move than copy, then DebugLoc /probably/ should be passed by value when a copy is going to be made - since it means callers can pass by lvalue or rvalue and get move opportunities when possible.

Given this API scenario:

CheapToMove Dest;
void Caller() {
  CheapToMove Source;
  Intermediate(Source); // 1 
  Intermediate(CheapToMove()); //2
}
void Implementation(/* What Type Goes here? */ CTM) {
  Dest = std::move(CTM); // move is a no-op here if CTM hapens to be a const ref
}

If the type is const ref, then (1) produces a single copy and (2) produces a single copy.
If the type is by-value, then (1) produces a move and a copy (worse by a copy, that should be cheap), and (2) produces 2 moves (better for cheaply movable things).

Does that make sense?

Ah, so you're saying MachineFunction::CreateMachineInstr should instead accept its DebugLoc by value - leaving the rest unchanged (i.e. revert this patch and change CreateMachineInstr instead)?

Yeah, that sounds like the right direction - MachineFunction::CreateMachineInstr would take DebugLoc by value, and std::move it along to the MachineInstr constructor. DebugLoc used to be cheap to copy, I think, so there's probably lots of stuff in the codebase that passes it around by value without std::move, or other things - it's probably not the biggest perf issue to worry about in terms of doing widescale cleanup, but if you're visiting/want to clean something up, cleaning it up in this direction (pass by value+std::move if "consuming"/copying into a non-local-lifetime variable like a member in this case, etc).

mtrofin updated this revision to Diff 392264.Dec 6 2021, 7:40 PM

feedback

mtrofin retitled this revision from [NFC][MachineInstr] No need to std::move the DebugLoc to [NFC][MachineInstr] Pass-by-value DebugLoc in CreateMachineInstr.Dec 6 2021, 7:41 PM
mtrofin edited the summary of this revision. (Show Details)
dblaikie accepted this revision.Dec 6 2021, 7:41 PM

looks good!

This revision is now accepted and ready to land.Dec 6 2021, 7:41 PM
This revision was landed with ongoing or failed builds.Dec 6 2021, 7:45 PM
This revision was automatically updated to reflect the committed changes.