[IR] llvm.reloc.none intrinsic for no-op symbol references (#147427)
This intrinsic emits a BFD_RELOC_NONE relocation at the point of call, which allows optimizations and languages to explicitly pull in symbols from static libraries without there being any code or data that has an effectual relocation against such a symbol. See issue #146159 for context.
This commit is contained in:
parent
71927ddb63
commit
5f08fb4d72
@ -30968,6 +30968,37 @@ 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(metadata !<name_str>)
|
||||
|
||||
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.
|
||||
|
||||
Arguments:
|
||||
""""""""""
|
||||
|
||||
The ``llvm.reloc.none`` intrinsic takes the symbol as a metadata string
|
||||
argument.
|
||||
|
||||
Semantics:
|
||||
""""""""""
|
||||
|
||||
This intrinsic emits a no-op relocation for the symbol at the location of the
|
||||
intrinsic call.
|
||||
|
||||
|
||||
Stack Map Intrinsics
|
||||
--------------------
|
||||
|
||||
@ -1537,6 +1537,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,
|
||||
|
||||
@ -474,6 +474,7 @@ private:
|
||||
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);
|
||||
|
||||
@ -1913,6 +1913,9 @@ def int_threadlocal_address : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [LLVMMatch
|
||||
def int_stepvector : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
|
||||
[], [IntrNoMem]>;
|
||||
|
||||
def int_reloc_none : DefaultAttrsIntrinsic<[], [llvm_metadata_ty],
|
||||
[IntrNoMem, IntrHasSideEffects]>;
|
||||
|
||||
//===---------------- Vector Predication Intrinsics --------------===//
|
||||
// Memory Intrinsics
|
||||
def int_vp_store : DefaultAttrsIntrinsic<[],
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -1554,6 +1554,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 {
|
||||
|
||||
@ -2087,6 +2087,17 @@ 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);
|
||||
const MCExpr *Value = MCSymbolRefExpr::create(
|
||||
OutContext.getOrCreateSymbol(MI.getOperand(0).getSymbolName()),
|
||||
OutContext);
|
||||
OutStreamer->emitRelocDirective(*Dot, "BFD_RELOC_NONE", Value, SMLoc());
|
||||
break;
|
||||
}
|
||||
default:
|
||||
emitInstruction(&MI);
|
||||
|
||||
|
||||
@ -2686,6 +2686,13 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
|
||||
case Intrinsic::experimental_convergence_entry:
|
||||
case Intrinsic::experimental_convergence_loop:
|
||||
return translateConvergenceControlIntrinsic(CI, ID, MIRBuilder);
|
||||
case Intrinsic::reloc_none: {
|
||||
Metadata *MD = cast<MetadataAsValue>(CI.getArgOperand(0))->getMetadata();
|
||||
StringRef SymbolName = cast<MDString>(MD)->getString();
|
||||
MIRBuilder.buildInstr(TargetOpcode::RELOC_NONE)
|
||||
.addExternalSymbol(SymbolName.data());
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -7811,6 +7811,17 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
|
||||
return;
|
||||
}
|
||||
|
||||
case Intrinsic::reloc_none: {
|
||||
Metadata *MD = cast<MetadataAsValue>(I.getArgOperand(0))->getMetadata();
|
||||
StringRef SymbolName = cast<MDString>(MD)->getString();
|
||||
SDValue Ops[2] = {
|
||||
getRoot(),
|
||||
DAG.getTargetExternalSymbol(
|
||||
SymbolName.data(), TLI.getProgramPointerTy(DAG.getDataLayout()))};
|
||||
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.
|
||||
|
||||
@ -472,6 +472,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";
|
||||
|
||||
@ -2550,6 +2550,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
|
||||
@ -3325,6 +3330,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;
|
||||
|
||||
@ -6013,6 +6013,12 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
|
||||
Check(cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue() < 2,
|
||||
"cache type argument to llvm.prefetch must be 0-1", Call);
|
||||
break;
|
||||
case Intrinsic::reloc_none: {
|
||||
Check(isa<MDString>(
|
||||
cast<MetadataAsValue>(Call.getArgOperand(0))->getMetadata()),
|
||||
"llvm.reloc.none argument must be a metadata string", &Call);
|
||||
break;
|
||||
}
|
||||
case Intrinsic::stackprotector:
|
||||
Check(isa<AllocaInst>(Call.getArgOperand(1)->stripPointerCasts()),
|
||||
"llvm.stackprotector parameter #2 must resolve to an alloca.", Call);
|
||||
|
||||
10
llvm/test/CodeGen/Generic/reloc-none.ll
Normal file
10
llvm/test/CodeGen/Generic/reloc-none.ll
Normal file
@ -0,0 +1,10 @@
|
||||
; RUN: llc < %s | FileCheck %s
|
||||
|
||||
; CHECK: .reloc {{.*}}, BFD_RELOC_NONE, foo
|
||||
|
||||
define void @test_reloc_none() {
|
||||
call void @llvm.reloc.none(metadata !"foo")
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.reloc.none(metadata)
|
||||
@ -1531,6 +1531,7 @@ Key: RDSSPQ: [ 0.00 0.00 ]
|
||||
Key: RDTSC: [ 0.00 0.00 ]
|
||||
Key: RDTSCP: [ 0.00 0.00 ]
|
||||
Key: REG_SEQUENCE: [ 0.00 0.00 ]
|
||||
Key: RELOC_NONE: [ 0.00 0.00 ]
|
||||
Key: REPNE_PREFIX: [ 0.00 0.00 ]
|
||||
Key: REP_MOVSB: [ 0.00 0.00 ]
|
||||
Key: REP_MOVSD: [ 0.00 0.00 ]
|
||||
|
||||
@ -1531,6 +1531,7 @@ Key: RDSSPQ: [ 0.00 0.00 ]
|
||||
Key: RDTSC: [ 0.00 0.00 ]
|
||||
Key: RDTSCP: [ 0.00 0.00 ]
|
||||
Key: REG_SEQUENCE: [ 0.00 0.00 ]
|
||||
Key: RELOC_NONE: [ 0.00 0.00 ]
|
||||
Key: REPNE_PREFIX: [ 0.00 0.00 ]
|
||||
Key: REP_MOVSB: [ 0.00 0.00 ]
|
||||
Key: REP_MOVSD: [ 0.00 0.00 ]
|
||||
|
||||
14
llvm/test/CodeGen/X86/GlobalISel/reloc-none.ll
Normal file
14
llvm/test/CodeGen/X86/GlobalISel/reloc-none.ll
Normal file
@ -0,0 +1,14 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
|
||||
; RUN: llc -mtriple=x86_64-linux-gnu -global-isel -verify-machineinstrs < %s -o - | FileCheck %s --check-prefix=CHECK
|
||||
|
||||
define void @test_reloc_none() {
|
||||
; CHECK-LABEL: test_reloc_none:
|
||||
; CHECK: # %bb.0:
|
||||
; CHECK-NEXT: .Lreloc_none0:
|
||||
; CHECK-NEXT: .reloc .Lreloc_none0, BFD_RELOC_NONE, foo
|
||||
; CHECK-NEXT: retq
|
||||
call void @llvm.reloc.none(metadata !"foo")
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.reloc.none(metadata)
|
||||
@ -96,7 +96,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
|
||||
|
||||
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
|
||||
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
|
||||
// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(99), GIMT_Encode2(211), /*)*//*default:*//*Label 5*/ GIMT_Encode4(524),
|
||||
// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(100), GIMT_Encode2(212), /*)*//*default:*//*Label 5*/ GIMT_Encode4(524),
|
||||
// CHECK-NEXT: /* 10 */ /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(458), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
|
||||
// CHECK-NEXT: /* 182 */ /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(476), GIMT_Encode4(0),
|
||||
// CHECK-NEXT: /* 190 */ /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4(488), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0), GIMT_Encode4(0),
|
||||
|
||||
@ -95,7 +95,8 @@ def InstD : InstBase {
|
||||
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2, 0,
|
||||
// CHECK-NEXT: 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 2,
|
||||
// CHECK-NEXT: 0,
|
||||
// CHECK-NEXT: };
|
||||
// CHECK-NEXT: return InstructionIndex[Opcode];
|
||||
// CHECK-NEXT: }
|
||||
|
||||
13
llvm/test/Verifier/reloc-none.ll
Normal file
13
llvm/test/Verifier/reloc-none.ll
Normal file
@ -0,0 +1,13 @@
|
||||
; RUN: not llvm-as -disable-output 2>&1 %s | FileCheck %s
|
||||
|
||||
; CHECK: llvm.reloc.none argument must be a metadata string
|
||||
; CHECK-NEXT: call void @llvm.reloc.none(metadata !0)
|
||||
|
||||
define void @test_reloc_none_bad_arg() {
|
||||
call void @llvm.reloc.none(metadata !0)
|
||||
ret void
|
||||
}
|
||||
|
||||
declare void @llvm.reloc.none(metadata)
|
||||
|
||||
!0 = !{}
|
||||
@ -1,33 +1,33 @@
|
||||
MAX_RELATION=4
|
||||
187 7051 1
|
||||
187 6948 2
|
||||
187 187 0
|
||||
187 7051 1
|
||||
187 7052 1
|
||||
187 6949 2
|
||||
187 187 0
|
||||
187 7052 1
|
||||
187 6950 2
|
||||
187 10 0
|
||||
10 7051 1
|
||||
10 7051 2
|
||||
10 7051 3
|
||||
10 6941 4
|
||||
10 7052 1
|
||||
10 7052 2
|
||||
10 7052 3
|
||||
10 6942 4
|
||||
10 187 0
|
||||
187 6932 1
|
||||
187 7051 2
|
||||
187 1543 0
|
||||
1543 6862 1
|
||||
1543 6932 2
|
||||
187 7051 1
|
||||
187 6948 2
|
||||
187 187 0
|
||||
187 7051 1
|
||||
187 6933 1
|
||||
187 7052 2
|
||||
187 1544 0
|
||||
1544 6863 1
|
||||
1544 6933 2
|
||||
187 7052 1
|
||||
187 6949 2
|
||||
187 187 0
|
||||
187 7052 1
|
||||
187 6950 2
|
||||
187 601 0
|
||||
601 7051 1
|
||||
601 7051 2
|
||||
601 7051 3
|
||||
601 6941 4
|
||||
601 7052 1
|
||||
601 7052 2
|
||||
601 7052 3
|
||||
601 6942 4
|
||||
601 187 0
|
||||
187 6932 1
|
||||
187 7051 2
|
||||
187 1543 0
|
||||
1543 6862 1
|
||||
1543 6932 2
|
||||
187 6933 1
|
||||
187 7052 2
|
||||
187 1544 0
|
||||
1544 6863 1
|
||||
1544 6933 2
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user