Compare commits

...

25 Commits

Author SHA1 Message Date
Daniel Thornburgh
ce0760f8f7 Correct typos 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
cfd33c8c0a Emit the new type arg from format attr 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
f272839e84 Add an example to clang attr doc 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
46a0008948 Update docs to account for clang inferring format attribute 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
4c53b27ac2 [clang] "modular_format" attribute for functions using format strings
This provides a C language version of the new IR modular-format
attribute. This, in concert with the format attribute, allows a library
function to declare that a modular version of its implementation is
available.

See issue #146159 for context.
2025-08-21 15:09:04 -07:00
Daniel Thornburgh
9265309f0c llvm.reloc.none takes a GlobalValue again
This avoids avoid modifying Module in ISel
2025-08-21 15:09:04 -07:00
Daniel Thornburgh
b7f8a9c8b4 Add a type arg 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
68761d9bf3 Describe the semantics of the arguments copied from C format attr 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
d11cfe5d18 Correct modular_format to modular-format in docs 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
435ba3597b Emit reloc.none instinsic with metdata string arg 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
dff521f73d issing -> issuing 2025-08-21 15:09:04 -07:00
Daniel Thornburgh
40bafe2ceb [IR] "modular-format" attribute for functions using format strings
A new InstCombine transform uses this attribute to rewrite calls to a
modular version of the implementation along with llvm.reloc.none
relocations against aspects of the implementation needed by the call.

This change only adds support for the 'float' aspect, but it also builds
the structure needed for others.

See issue #146159
2025-08-21 15:09:04 -07:00
Daniel Thornburgh
341dd6a3ca Update big-filter.td 2025-08-21 15:08:55 -07:00
Daniel Thornburgh
75c4d315dc Take symbol name by GlobalValue again to avoid modifying Module 2025-08-21 14:28:08 -07:00
Daniel Thornburgh
904c996355 Update tests 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
a6220fef9b Remove arg from emitRelocDirective call 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
20f2ad062c Lower reloc.none in Global ISel 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
6fc858761e Rename reloc_none.ll to reloc-none.ll 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
57ba236e87 Use llvm-as for test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
07ccb63a1b Remove unneeded assertion from AsmPrinter 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
dd58f21c9e IR verifier check and test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
bd4dd9ca02 Add a generic reloc_none test 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
5a056672cb Take symbol name by metadata arg rather than ptr to GlobalValue 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
0e830ad120 fake.use -> reloc.none 2025-08-18 11:37:40 -07:00
Daniel Thornburgh
f3fdeff3e3 [IR] llvm.reloc.none intrinsic for no-op symbol references
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.
2025-08-18 11:37:40 -07:00
24 changed files with 308 additions and 7 deletions

View File

@ -5233,3 +5233,14 @@ def NonString : InheritableAttr {
let Subjects = SubjectList<[Var, Field]>; let Subjects = SubjectList<[Var, Field]>;
let Documentation = [NonStringDocs]; let Documentation = [NonStringDocs];
} }
def ModularFormat : InheritableAttr {
let Spellings = [Clang<"modular_format">];
let Args = [
IdentifierArgument<"ModularImplFn">,
StringArgument<"ImplName">,
VariadicStringArgument<"Aspects">
];
let Subjects = SubjectList<[Function]>;
let Documentation = [ModularFormatDocs];
}

View File

@ -9549,3 +9549,37 @@ silence diagnostics with code like:
__attribute__((nonstring)) char NotAStr[3] = "foo"; // Not diagnosed __attribute__((nonstring)) char NotAStr[3] = "foo"; // Not diagnosed
}]; }];
} }
def ModularFormatDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
The ``modular_format`` attribute can be applied to a function that bears the
``format`` attribute (or standard library functions) to indicate that the
implementation is modular on the format string argument. When the format string
for a given call is constant, the compiler may redirect the call to the symbol
given as the first argument to the attribute (the modular implementation
function).
The second argument is a implementation name, and the remaining arguments are
aspects of the format string for the compiler to report. If the compiler does
not understand an aspect, it must summarily report that the format string has
that aspect.
The compiler reports an aspect by issuing a relocation for the symbol
``<impl_name>_<aspect>``. This arranges for code and data needed to support the
aspect of the implementation to be brought into the link to satisfy weak
references in the modular implemenation function.
For example, say ``printf`` is annotated with
``modular_format(__modular_printf, __printf, float)``. Then, a call to
``printf(var, 42)`` would be untouched. A call to ``printf("%d", 42)`` would
become a call to ``__modular_printf`` with the same arguments, as would
``printf("%f", 42.0)``. The latter would be accompanied with a strong
relocation against the symbol ``__printf_float``, which would bring floating
point support for ``printf`` into the link.
The following aspects are currently supported:
- ``float``: The call has a floating point argument
}];
}

View File

@ -2560,6 +2560,20 @@ void CodeGenModule::ConstructAttributeList(StringRef Name,
if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>()) if (TargetDecl->hasAttr<ArmLocallyStreamingAttr>())
FuncAttrs.addAttribute("aarch64_pstate_sm_body"); FuncAttrs.addAttribute("aarch64_pstate_sm_body");
if (auto *ModularFormat = TargetDecl->getAttr<ModularFormatAttr>()) {
// TODO: Error checking
FormatAttr *Format = TargetDecl->getAttr<FormatAttr>();
StringRef Type = Format->getType()->getName();
std::string FormatIdx = std::to_string(Format->getFormatIdx());
std::string FirstArg = std::to_string(Format->getFirstArg());
SmallVector<StringRef> Args = {
Type, FormatIdx, FirstArg,
ModularFormat->getModularImplFn()->getName(),
ModularFormat->getImplName()};
llvm::append_range(Args, ModularFormat->aspects());
FuncAttrs.addAttribute("modular-format", llvm::join(Args, ","));
}
} }
// Attach "no-builtins" attributes to: // Attach "no-builtins" attributes to:

View File

@ -6752,6 +6752,29 @@ static void handleVTablePointerAuthentication(Sema &S, Decl *D,
CustomDiscriminationValue)); CustomDiscriminationValue));
} }
static void handleModularFormat(Sema &S, Decl *D, const ParsedAttr &AL) {
StringRef ImplName;
if (!S.checkStringLiteralArgumentAttr(AL, 1, ImplName))
return;
SmallVector<StringRef> Aspects;
for (unsigned I = 2, E = AL.getNumArgs(); I != E; ++I) {
StringRef Aspect;
if (!S.checkStringLiteralArgumentAttr(AL, I, Aspect))
return;
Aspects.push_back(Aspect);
}
// Store aspects sorted and without duplicates.
llvm::sort(Aspects);
Aspects.erase(llvm::unique(Aspects), Aspects.end());
// TODO: Type checking on identifier
// TODO: Merge attributes
D->addAttr(::new (S.Context) ModularFormatAttr(
S.Context, AL, AL.getArgAsIdent(0)->getIdentifierInfo(), ImplName,
Aspects.data(), Aspects.size()));
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Top Level Sema Entry Points // Top Level Sema Entry Points
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -7679,6 +7702,10 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
case ParsedAttr::AT_VTablePointerAuthentication: case ParsedAttr::AT_VTablePointerAuthentication:
handleVTablePointerAuthentication(S, D, AL); handleVTablePointerAuthentication(S, D, AL);
break; break;
case ParsedAttr::AT_ModularFormat:
handleModularFormat(S, D, AL);
break;
} }
} }

View File

@ -2635,6 +2635,28 @@ For example:
This attribute indicates that outlining passes should not modify the This attribute indicates that outlining passes should not modify the
function. function.
``"modular-format"="<type>,<string_idx>,<first_idx_to_check>,<modular_impl_fn>,<impl_name>,<aspects...>"``
This attribute indicates that the implementation is modular on a particular
format string argument . When the argument for a given call is constant, the
compiler may redirect the call to a modular implementation function
instead.
The compiler also emits relocations to report various aspects of the format
string and arguments that were present. The compiler reports an aspect by
issuing a relocation for the symbol `<impl_name>_<aspect>``. This arranges
for code and data needed to support the aspect of the implementation to be
brought into the link to satisfy weak references in the modular
implemenation function.
The first three arguments have the same semantics as the arguments to the C
``format`` attribute.
The following aspects are currently supported:
- ``float``: The call has a floating point argument
Call Site Attributes Call Site Attributes
---------------------- ----------------------
@ -30630,6 +30652,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 operand and should try to preserve the intrinsic and its position in the
function. 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.
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 Stack Map Intrinsics
-------------------- --------------------

View File

@ -1531,6 +1531,9 @@ enum NodeType {
#define BEGIN_REGISTER_VP_SDNODE(VPSDID, ...) VPSDID, #define BEGIN_REGISTER_VP_SDNODE(VPSDID, ...) VPSDID,
#include "llvm/IR/VPIntrinsics.def" #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. // The `llvm.experimental.convergence.*` intrinsics.
CONVERGENCECTRL_ANCHOR, CONVERGENCECTRL_ANCHOR,
CONVERGENCECTRL_ENTRY, CONVERGENCECTRL_ENTRY,

View File

@ -473,6 +473,7 @@ private:
void Select_WRITE_REGISTER(SDNode *Op); void Select_WRITE_REGISTER(SDNode *Op);
void Select_UNDEF(SDNode *N); void Select_UNDEF(SDNode *N);
void Select_FAKE_USE(SDNode *N); void Select_FAKE_USE(SDNode *N);
void Select_RELOC_NONE(SDNode *N);
void CannotYetSelect(SDNode *N); void CannotYetSelect(SDNode *N);
void Select_FREEZE(SDNode *N); void Select_FREEZE(SDNode *N);

View File

@ -1913,6 +1913,9 @@ def int_threadlocal_address : DefaultAttrsIntrinsic<[llvm_anyptr_ty], [LLVMMatch
def int_stepvector : DefaultAttrsIntrinsic<[llvm_anyvector_ty], def int_stepvector : DefaultAttrsIntrinsic<[llvm_anyvector_ty],
[], [IntrNoMem]>; [], [IntrNoMem]>;
def int_reloc_none : DefaultAttrsIntrinsic<[], [llvm_ptr_ty],
[IntrHasSideEffects, IntrInaccessibleMemOnly, IntrWillReturn]>;
//===---------------- Vector Predication Intrinsics --------------===// //===---------------- Vector Predication Intrinsics --------------===//
// Memory Intrinsics // Memory Intrinsics
def int_vp_store : DefaultAttrsIntrinsic<[], def int_vp_store : DefaultAttrsIntrinsic<[],

View File

@ -233,6 +233,9 @@ HANDLE_TARGET_OPCODE(MEMBARRIER)
// using. // using.
HANDLE_TARGET_OPCODE(JUMP_TABLE_DEBUG_INFO) 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_ENTRY)
HANDLE_TARGET_OPCODE(CONVERGENCECTRL_ANCHOR) HANDLE_TARGET_OPCODE(CONVERGENCECTRL_ANCHOR)
HANDLE_TARGET_OPCODE(CONVERGENCECTRL_LOOP) HANDLE_TARGET_OPCODE(CONVERGENCECTRL_LOOP)

View File

@ -1532,6 +1532,11 @@ def JUMP_TABLE_DEBUG_INFO : StandardPseudoInstruction {
let Size = 0; let Size = 0;
let isMeta = true; 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 { let hasSideEffects = false, isMeta = true, isConvergent = true in {
def CONVERGENCECTRL_ANCHOR : StandardPseudoInstruction { def CONVERGENCECTRL_ANCHOR : StandardPseudoInstruction {

View File

@ -2039,6 +2039,16 @@ void AsmPrinter::emitFunctionBody() {
// This is only used to influence register allocation behavior, no // This is only used to influence register allocation behavior, no
// actual initialization is needed. // actual initialization is needed.
break; 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(
getSymbol(MI.getOperand(0).getGlobal()), OutContext);
OutStreamer->emitRelocDirective(*Dot, "BFD_RELOC_NONE", Value, SMLoc());
break;
}
default: default:
emitInstruction(&MI); emitInstruction(&MI);

View File

@ -2669,6 +2669,11 @@ bool IRTranslator::translateKnownIntrinsic(const CallInst &CI, Intrinsic::ID ID,
case Intrinsic::experimental_convergence_entry: case Intrinsic::experimental_convergence_entry:
case Intrinsic::experimental_convergence_loop: case Intrinsic::experimental_convergence_loop:
return translateConvergenceControlIntrinsic(CI, ID, MIRBuilder); return translateConvergenceControlIntrinsic(CI, ID, MIRBuilder);
case Intrinsic::reloc_none: {
MIRBuilder.buildInstr(TargetOpcode::RELOC_NONE)
.addGlobalAddress(cast<GlobalValue>(CI.getArgOperand(0)));
return true;
}
} }
return false; return false;
} }

View File

@ -7751,6 +7751,17 @@ void SelectionDAGBuilder::visitIntrinsicCall(const CallInst &I,
return; return;
} }
case Intrinsic::reloc_none: {
SDValue V = getValue(I.getArgOperand(0));
const auto *GA = cast<GlobalAddressSDNode>(V);
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_exceptionpointer:
case Intrinsic::eh_exceptioncode: { case Intrinsic::eh_exceptioncode: {
// Get the exception pointer vreg, copy from it, and resize it to fit. // Get the exception pointer vreg, copy from it, and resize it to fit.

View File

@ -471,6 +471,8 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
case ISD::LIFETIME_END: return "lifetime.end"; case ISD::LIFETIME_END: return "lifetime.end";
case ISD::FAKE_USE: case ISD::FAKE_USE:
return "fake_use"; return "fake_use";
case ISD::RELOC_NONE:
return "reloc_none";
case ISD::PSEUDO_PROBE: case ISD::PSEUDO_PROBE:
return "pseudoprobe"; return "pseudoprobe";
case ISD::GC_TRANSITION_START: return "gc_transition.start"; case ISD::GC_TRANSITION_START: return "gc_transition.start";

View File

@ -2521,6 +2521,11 @@ void SelectionDAGISel::Select_FAKE_USE(SDNode *N) {
N->getOperand(1), N->getOperand(0)); 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) { void SelectionDAGISel::Select_FREEZE(SDNode *N) {
// TODO: We don't have FREEZE pseudo-instruction in MachineInstr-level now. // 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 // If FREEZE instruction is added later, the code below must be changed as
@ -3296,6 +3301,9 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
case ISD::FAKE_USE: case ISD::FAKE_USE:
Select_FAKE_USE(NodeToMatch); Select_FAKE_USE(NodeToMatch);
return; return;
case ISD::RELOC_NONE:
Select_RELOC_NONE(NodeToMatch);
return;
case ISD::FREEZE: case ISD::FREEZE:
Select_FREEZE(NodeToMatch); Select_FREEZE(NodeToMatch);
return; return;

View File

@ -5921,6 +5921,11 @@ void Verifier::visitIntrinsicCall(Intrinsic::ID ID, CallBase &Call) {
Check(cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue() < 2, Check(cast<ConstantInt>(Call.getArgOperand(3))->getZExtValue() < 2,
"cache type argument to llvm.prefetch must be 0-1", Call); "cache type argument to llvm.prefetch must be 0-1", Call);
break; break;
case Intrinsic::reloc_none: {
Check(isa<GlobalValue>(Call.getArgOperand(0)),
"llvm.reloc.none argument must be a global value", &Call);
break;
}
case Intrinsic::stackprotector: case Intrinsic::stackprotector:
Check(isa<AllocaInst>(Call.getArgOperand(1)->stripPointerCasts()), Check(isa<AllocaInst>(Call.getArgOperand(1)->stripPointerCasts()),
"llvm.stackprotector parameter #2 must resolve to an alloca.", Call); "llvm.stackprotector parameter #2 must resolve to an alloca.", Call);

View File

@ -19,6 +19,7 @@
#include "llvm/ADT/SmallBitVector.h" #include "llvm/ADT/SmallBitVector.h"
#include "llvm/ADT/SmallVector.h" #include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h" #include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Analysis/AliasAnalysis.h" #include "llvm/Analysis/AliasAnalysis.h"
#include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/AssumeBundleQueries.h"
#include "llvm/Analysis/AssumptionCache.h" #include "llvm/Analysis/AssumptionCache.h"
@ -4001,6 +4002,63 @@ Instruction *InstCombinerImpl::visitCallBrInst(CallBrInst &CBI) {
return visitCallBase(CBI); return visitCallBase(CBI);
} }
static Value *optimizeModularFormat(CallInst *CI, IRBuilderBase &B) {
if (!CI->hasFnAttr("modular-format"))
return nullptr;
SmallVector<StringRef> Args(
llvm::split(CI->getFnAttr("modular-format").getValueAsString(), ','));
// TODO: Make use of the first two arguments
// TODO: Error handling
unsigned FirstArgIdx;
if (!llvm::to_integer(Args[2], FirstArgIdx))
return nullptr;
if (FirstArgIdx == 0)
return nullptr;
--FirstArgIdx;
StringRef FnName = Args[3];
StringRef ImplName = Args[4];
DenseSet<StringRef> Aspects(llvm::from_range,
ArrayRef<StringRef>(Args).drop_front(5));
Module *M = CI->getModule();
Function *Callee = CI->getCalledFunction();
FunctionCallee ModularFn =
M->getOrInsertFunction(FnName, Callee->getFunctionType(),
Callee->getAttributes().removeFnAttribute(
M->getContext(), "modular-format"));
CallInst *New = cast<CallInst>(CI->clone());
New->setCalledFunction(ModularFn);
New->removeFnAttr("modular-format");
B.Insert(New);
const auto ReferenceAspect = [&](StringRef Aspect) {
SmallString<20> Name = ImplName;
Name += '_';
Name += Aspect;
Constant *Sym =
M->getOrInsertGlobal(Name, Type::getInt8Ty(M->getContext()));
Function *RelocNoneFn =
Intrinsic::getOrInsertDeclaration(M, Intrinsic::reloc_none);
B.CreateCall(RelocNoneFn, {Sym});
};
if (Aspects.contains("float")) {
Aspects.erase("float");
if (llvm::any_of(
llvm::make_range(std::next(CI->arg_begin(), FirstArgIdx),
CI->arg_end()),
[](Value *V) { return V->getType()->isFloatingPointTy(); }))
ReferenceAspect("float");
}
SmallVector<StringRef> UnknownAspects(Aspects.begin(), Aspects.end());
llvm::sort(UnknownAspects);
for (StringRef Request : UnknownAspects)
ReferenceAspect(Request);
return New;
}
Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) { Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) {
if (!CI->getCalledFunction()) return nullptr; if (!CI->getCalledFunction()) return nullptr;
@ -4022,6 +4080,10 @@ Instruction *InstCombinerImpl::tryOptimizeCall(CallInst *CI) {
++NumSimplified; ++NumSimplified;
return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With); return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With);
} }
if (Value *With = optimizeModularFormat(CI, Builder)) {
++NumSimplified;
return CI->use_empty() ? CI : replaceInstUsesWith(*CI, With);
}
return nullptr; return nullptr;
} }

View File

@ -70,11 +70,11 @@
# DEBUG-NEXT: .. the first uncovered type index: 1, OK # DEBUG-NEXT: .. the first uncovered type index: 1, OK
# DEBUG-NEXT: .. the first uncovered imm index: 0, OK # DEBUG-NEXT: .. the first uncovered imm index: 0, OK
# #
# DEBUG-NEXT: G_ABDS (opcode 65): 1 type index, 0 imm indices # DEBUG-NEXT: G_ABDS (opcode 66): 1 type index, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# #
# DEBUG-NEXT: G_ABDU (opcode 66): 1 type index, 0 imm indices # DEBUG-NEXT: G_ABDU (opcode 67): 1 type index, 0 imm indices
# DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}} # DEBUG-NEXT: .. opcode {{[0-9]+}} is aliased to {{[0-9]+}}
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected

View File

@ -0,0 +1,13 @@
; RUN: llc < %s | FileCheck %s
; CHECK: .reloc {{.*}}, BFD_RELOC_NONE, foo
%1 = type opaque
@foo = external global %1
define void @test_reloc_none() {
call void @llvm.reloc.none(ptr @foo)
ret void
}
declare void @llvm.reloc.none(ptr)

View File

@ -72,11 +72,11 @@
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected # DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# #
# DEBUG-NEXT: G_ABDS (opcode 65): 1 type index, 0 imm indices # DEBUG-NEXT: G_ABDS (opcode 66): 1 type index, 0 imm indices
# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
# #
# DEBUG-NEXT:G_ABDU (opcode 66): 1 type index, 0 imm indices # DEBUG-NEXT:G_ABDU (opcode 67): 1 type index, 0 imm indices
# DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined # DEBUG-NEXT:.. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined # DEBUG-NEXT:.. imm index coverage check SKIPPED: no rules defined
# #

View File

@ -0,0 +1,17 @@
; 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
%1 = type opaque
@foo = external global %1
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(ptr @foo)
ret void
}
declare void @llvm.reloc.none(ptr)

View File

@ -15,10 +15,10 @@ class I : Instruction {
// CHECK-NEXT: MCD::OPC_ExtractField, 0, 64, // CHECK-NEXT: MCD::OPC_ExtractField, 0, 64,
// CHECK-NEXT: MCD::OPC_FilterValue, 1, 8, 0, // CHECK-NEXT: MCD::OPC_FilterValue, 1, 8, 0,
// CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 1, // CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 1,
// CHECK-NEXT: MCD::OPC_Decode, 187, 2, 0, // CHECK-NEXT: MCD::OPC_Decode, 188, 2, 0,
// CHECK-NEXT: MCD::OPC_FilterValueOrFail, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1, // CHECK-NEXT: MCD::OPC_FilterValueOrFail, 255, 255, 255, 255, 255, 255, 255, 255, 255, 1,
// CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 0, // CHECK-NEXT: MCD::OPC_CheckFieldOrFail, 127, 1, 0,
// CHECK-NEXT: MCD::OPC_Decode, 186, 2, 0, // CHECK-NEXT: MCD::OPC_Decode, 187, 2, 0,
// CHECK-NEXT: MCD::OPC_Fail, // CHECK-NEXT: MCD::OPC_Fail,
// CHECK-NEXT: 0 // CHECK-NEXT: 0
// CHECK-NEXT: }; // CHECK-NEXT: };

View File

@ -96,7 +96,7 @@ def MyCombiner: GICombiner<"GenMyCombiner", [
// CHECK: const uint8_t *GenMyCombiner::getMatchTable() const { // CHECK: const uint8_t *GenMyCombiner::getMatchTable() const {
// CHECK-NEXT: constexpr static uint8_t MatchTable0[] = { // CHECK-NEXT: constexpr static uint8_t MatchTable0[] = {
// CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(99), GIMT_Encode2(210), /*)*//*default:*//*Label 5*/ GIMT_Encode4(520), // CHECK-NEXT: /* 0 */ GIM_SwitchOpcode, /*MI*/0, /*[*/GIMT_Encode2(100), GIMT_Encode2(211), /*)*//*default:*//*Label 5*/ GIMT_Encode4(520),
// CHECK-NEXT: /* 10 */ /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(454), 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: /* 10 */ /*TargetOpcode::G_STORE*//*Label 0*/ GIMT_Encode4(454), 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(472), GIMT_Encode4(0), // CHECK-NEXT: /* 182 */ /*TargetOpcode::G_SEXT*//*Label 1*/ GIMT_Encode4(472), GIMT_Encode4(0),
// CHECK-NEXT: /* 190 */ /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4(484), 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), // CHECK-NEXT: /* 190 */ /*TargetOpcode::G_ZEXT*//*Label 2*/ GIMT_Encode4(484), 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),

View File

@ -0,0 +1,13 @@
; RUN: not llvm-as -disable-output 2>&1 %s | FileCheck %s
; CHECK: llvm.reloc.none argument must be a global value
; CHECK-NEXT: call void @llvm.reloc.none(ptr %foo)
define void @test_reloc_none_bad_arg(ptr %foo) {
call void @llvm.reloc.none(ptr %foo)
ret void
}
declare void @llvm.reloc.none(ptr)
!0 = !{}