Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
93 changes: 73 additions & 20 deletions llvm/lib/CodeGen/CFIInstrInserter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,61 @@ class CFIInstrInserter : public MachineFunctionPass {
#define INVALID_REG UINT_MAX
#define INVALID_OFFSET INT_MAX
/// contains the location where CSR register is saved.
struct CSRSavedLocation {
CSRSavedLocation(std::optional<unsigned> R, std::optional<int> O)
: Reg(R), Offset(O) {
assert((Reg.has_value() ^ Offset.has_value()) &&
"Register and offset can not both be valid");
class CSRSavedLocation {
public:
enum Kind { Invalid, Register, CFAOffset };
Kind K = Invalid;

private:
union {
// Dwarf register number
unsigned Reg;
// CFA offset
int64_t Offset;
} U;

public:
CSRSavedLocation() { K = Kind::Invalid; }

static CSRSavedLocation createCFAOffset(int64_t Offset) {
CSRSavedLocation Loc;
Loc.K = Kind::CFAOffset;
Loc.U.Offset = Offset;
return Loc;
}
std::optional<unsigned> Reg;
std::optional<int> Offset;

bool operator==(const CSRSavedLocation &RHS) const {
return Reg == RHS.Reg && Offset == RHS.Offset;
static CSRSavedLocation createRegister(unsigned Reg) {
CSRSavedLocation Loc;
Loc.K = Kind::Register;
Loc.U.Reg = Reg;
return Loc;
}

bool isValid() const { return K != Kind::Invalid; }

unsigned getRegister() const {
assert(K == Kind::Register);
return U.Reg;
}

int64_t getOffset() const {
assert(K == Kind::CFAOffset);
return U.Offset;
}

bool operator==(const CSRSavedLocation &RHS) const {
if (K != RHS.K)
return false;
switch (K) {
case Kind::Invalid:
return !RHS.isValid();
case Kind::Register:
return getRegister() == RHS.getRegister();
case Kind::CFAOffset:
return getOffset() == RHS.getOffset();
}
llvm_unreachable("Unknown CSRSavedLocation Kind!");
}
bool operator!=(const CSRSavedLocation &RHS) const {
return !(*this == RHS);
}
Expand Down Expand Up @@ -277,13 +319,19 @@ void CFIInstrInserter::calculateOutgoingCFAInfo(MBBCFAInfo &MBBInfo) {
case MCCFIInstruction::OpValOffset:
break;
}
if (CSRReg || CSROffset) {
CSRSavedLocation Loc(CSRReg, CSROffset);
auto [It, Inserted] = CSRLocMap.insert({CFI.getRegister(), Loc});
if (!Inserted && It->second != Loc) {
assert((!CSRReg.has_value() || !CSROffset.has_value()) &&
"A register can only be at an offset from CFA or in another "
"register, but not both!");
CSRSavedLocation CSRLoc;
if (CSRReg)
CSRLoc = CSRSavedLocation::createRegister(*CSRReg);
else if (CSROffset)
CSRLoc = CSRSavedLocation::createCFAOffset(*CSROffset);
if (CSRLoc.isValid()) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would prefer we not add the Invalid state. The prior code didn't need it, your switch based code shouldn't either. Is there a strong reason this needs to exist?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It will be needed here: https://github.com/llvm/llvm-project/pull/168531/files#diff-54d9d06f60ce6c927ea0f2c1380a50bdf93c689d1781186966ef2234660e47c9R421

Unless we want to collect all callee-saved registers in a vector before we come to this line. But... we also need CFIs for exception handling (or something else) and I suspect it may require emitting CFIs for non-callee saved registers.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

EDIT: I don't think we'll ever need to care about CFIs for registers which are not returned by getCalleeSavedRegs, so we can make CFIInstrInserter only track those. That should save some memory too. I'll create a separate PR for that.

auto [It, Inserted] = CSRLocMap.insert({CFI.getRegister(), CSRLoc});
if (!Inserted && It->second != CSRLoc)
reportFatalInternalError(
"Different saved locations for the same CSR");
}
CSRSaved.set(CFI.getRegister());
}
}
Expand Down Expand Up @@ -403,14 +451,19 @@ bool CFIInstrInserter::insertCFIInstrs(MachineFunction &MF) {
assert(it != CSRLocMap.end() && "Reg should have an entry in CSRLocMap");
unsigned CFIIndex;
CSRSavedLocation RO = it->second;
if (!RO.Reg && RO.Offset) {
switch (RO.K) {
case CSRSavedLocation::CFAOffset: {
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createOffset(nullptr, Reg, *RO.Offset));
} else {
assert((RO.Reg && !RO.Offset) &&
"Reg and Offset cannot both be valid/invalid");
MCCFIInstruction::createOffset(nullptr, Reg, RO.getOffset()));
break;
}
case CSRSavedLocation::Register: {
CFIIndex = MF.addFrameInst(
MCCFIInstruction::createRegister(nullptr, Reg, *RO.Reg));
MCCFIInstruction::createRegister(nullptr, Reg, RO.getRegister()));
break;
}
default:
llvm_unreachable("Invalid CSRSavedLocation!");
}
BuildMI(*MBBInfo.MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
.addCFIIndex(CFIIndex);
Expand Down
Loading