Skip to content

[IR] llvm.reloc.none intrinsic for no-op symbol references #147427

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
32 changes: 32 additions & 0 deletions llvm/docs/LangRef.rst
Original file line number Diff line number Diff line change
Expand Up @@ -30439,6 +30439,38 @@ This intrinsic does nothing, but optimizers must consider it a use of its single
operand and should try to preserve the intrinsic and its position in the
function.

.. _llvm_reloc_none:

'``llvm.reloc.none``' Intrinsic
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

Syntax:
"""""""

::

declare void @llvm.reloc.none(ptrty %ptr)

Overview:
"""""""""

The ``llvm.reloc.none`` intrinsic emits a no-op relocation against a given
operand symbol. This can bring the symbol
definition into the link without emitting any code or data to the binary for
that purpose.
Comment on lines +30457 to +30460
Copy link
Contributor

Choose a reason for hiding this comment

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

Why against a pointer type? We have the llvm.amdgcn.reloc.constant intrinsic for similar purposes but uses metadata for the string name of the symbol

Copy link
Contributor Author

Choose a reason for hiding this comment

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

The reason being... I had no idea you could do that! This is essentially my first time monkeying in the IR; I've been a backend/linker jocky for the most part. But thanks, that does seem a lot semantically simpler. I'll make the change throughout the PR chain and report back here.


Arguments:
""""""""""

The ``llvm.reloc.none`` intrinsic takes one argument, which may be any global
value.

Semantics:
""""""""""

This intrinsic emits a no-op relocation at the location of the intrinsic call
for the symbol that corresponds to the global value argument.


Stack Map Intrinsics
--------------------
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/CodeGen/ISDOpcodes.h
Original file line number Diff line number Diff line change
Expand Up @@ -1531,6 +1531,9 @@ enum NodeType {
#define BEGIN_REGISTER_VP_SDNODE(VPSDID, ...) VPSDID,
#include "llvm/IR/VPIntrinsics.def"

// Issue a no-op relocation against a given symbol at the current location.
RELOC_NONE,

// The `llvm.experimental.convergence.*` intrinsics.
CONVERGENCECTRL_ANCHOR,
CONVERGENCECTRL_ENTRY,
Expand Down
1 change: 1 addition & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGISel.h
Original file line number Diff line number Diff line change
Expand Up @@ -473,6 +473,7 @@ class SelectionDAGISel {
void Select_WRITE_REGISTER(SDNode *Op);
void Select_UNDEF(SDNode *N);
void Select_FAKE_USE(SDNode *N);
void Select_RELOC_NONE(SDNode *N);
void CannotYetSelect(SDNode *N);

void Select_FREEZE(SDNode *N);
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/IR/Intrinsics.td
Original file line number Diff line number Diff line change
Expand Up @@ -1917,6 +1917,9 @@ def int_threadlocal_address : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [LLVMMatch
def int_stepvector : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
[], [IntrNoMem]>;

def int_reloc_none : DefaultAttrsIntrinsic<[], [llvm_ptr_ty],
[IntrHasSideEffects, IntrInaccessibleMemOnly, IntrWillReturn]>;

//===---------------- Vector Predication Intrinsics --------------===//
// Memory Intrinsics
def int_vp_store : DefaultAttrsIntrinsic<[],
Expand Down
3 changes: 3 additions & 0 deletions llvm/include/llvm/Support/TargetOpcodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -233,6 +233,9 @@ HANDLE_TARGET_OPCODE(MEMBARRIER)
// using.
HANDLE_TARGET_OPCODE(JUMP_TABLE_DEBUG_INFO)

// Issue a no-op relocation against a given symbol at the current location.
HANDLE_TARGET_OPCODE(RELOC_NONE)

HANDLE_TARGET_OPCODE(CONVERGENCECTRL_ENTRY)
HANDLE_TARGET_OPCODE(CONVERGENCECTRL_ANCHOR)
HANDLE_TARGET_OPCODE(CONVERGENCECTRL_LOOP)
Expand Down
5 changes: 5 additions & 0 deletions llvm/include/llvm/Target/Target.td
Original file line number Diff line number Diff line change
Expand Up @@ -1532,6 +1532,11 @@ def JUMP_TABLE_DEBUG_INFO : StandardPseudoInstruction {
let Size = 0;
let isMeta = true;
}
def RELOC_NONE : StandardPseudoInstruction {
let OutOperandList = (outs);
let InOperandList = (ins unknown:$symbol);
let hasSideEffects = true;
}

let hasSideEffects = false, isMeta = true, isConvergent = true in {
def CONVERGENCECTRL_ANCHOR : StandardPseudoInstruction {
Expand Down
14 changes: 14 additions & 0 deletions llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1930,6 +1930,20 @@ void AsmPrinter::emitFunctionBody() {
// This is only used to influence register allocation behavior, no
// actual initialization is needed.
break;
case TargetOpcode::RELOC_NONE: {
// Generate a temporary label for the current PC.
MCSymbol *Sym = OutContext.createTempSymbol("reloc_none");
OutStreamer->emitLabel(Sym);
const MCExpr *Dot = MCSymbolRefExpr::create(Sym, OutContext);

assert(MI.getNumOperands() == 1 &&
"RELOC_NONE can only have one operand");
const MCExpr *Value = MCSymbolRefExpr::create(
getSymbol(MI.getOperand(0).getGlobal()), OutContext);
OutStreamer->emitRelocDirective(*Dot, "BFD_RELOC_NONE", Value, SMLoc(),
*STI);
break;
}
default:
emitInstruction(&MI);

Expand Down
13 changes: 13 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7757,6 +7757,19 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
return;
}

case Intrinsic::reloc_none: {
SDValue V = getValue(I.getArgOperand(0));
auto *GA = dyn_cast<GlobalAddressSDNode>(V);
if (!GA)
report_fatal_error("llvm.reloc.none operand must be a GlobalValue");
Comment on lines +7763 to +7764
Copy link
Contributor

Choose a reason for hiding this comment

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

Belongs in IR verifier

SDValue Ops[2];
Ops[0] = getRoot();
Ops[1] = DAG.getTargetGlobalAddress(GA->getGlobal(), sdl, V.getValueType(),
GA->getOffset());
DAG.setRoot(DAG.getNode(ISD::RELOC_NONE, sdl, MVT::Other, Ops));
return;
}

case Intrinsic::eh_exceptionpointer:
case Intrinsic::eh_exceptioncode: {
// Get the exception pointer vreg, copy from it, and resize it to fit.
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::LIFETIME_END: return "lifetime.end";
case ISD::FAKE_USE:
return "fake_use";
case ISD::RELOC_NONE:
return "reloc_none";
case ISD::PSEUDO_PROBE:
return "pseudoprobe";
case ISD::GC_TRANSITION_START: return "gc_transition.start";
Expand Down
8 changes: 8 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2498,6 +2498,11 @@ void SelectionDAGISel::Select_FAKE_USE(SDNode *N) {
N->getOperand(1), N->getOperand(0));
}

void SelectionDAGISel::Select_RELOC_NONE(SDNode *N) {
CurDAG->SelectNodeTo(N, TargetOpcode::RELOC_NONE, N->getValueType(0),
N->getOperand(1), N->getOperand(0));
}

void SelectionDAGISel::Select_FREEZE(SDNode *N) {
// TODO: We don't have FREEZE pseudo-instruction in MachineInstr-level now.
// If FREEZE instruction is added later, the code below must be changed as
Expand Down Expand Up @@ -3273,6 +3278,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case ISD::FAKE_USE:
Select_FAKE_USE(NodeToMatch);
return;
case ISD::RELOC_NONE:
Select_RELOC_NONE(NodeToMatch);
return;
case ISD::FREEZE:
Select_FREEZE(NodeToMatch);
return;
Expand Down
Loading