Compare commits
25 Commits
main
...
users/myst
Author | SHA1 | Date | |
---|---|---|---|
![]() |
ce0760f8f7 | ||
![]() |
cfd33c8c0a | ||
![]() |
f272839e84 | ||
![]() |
46a0008948 | ||
![]() |
4c53b27ac2 | ||
![]() |
9265309f0c | ||
![]() |
b7f8a9c8b4 | ||
![]() |
68761d9bf3 | ||
![]() |
d11cfe5d18 | ||
![]() |
435ba3597b | ||
![]() |
dff521f73d | ||
![]() |
40bafe2ceb | ||
![]() |
341dd6a3ca | ||
![]() |
75c4d315dc | ||
![]() |
904c996355 | ||
![]() |
a6220fef9b | ||
![]() |
20f2ad062c | ||
![]() |
6fc858761e | ||
![]() |
57ba236e87 | ||
![]() |
07ccb63a1b | ||
![]() |
dd58f21c9e | ||
![]() |
bd4dd9ca02 | ||
![]() |
5a056672cb | ||
![]() |
0e830ad120 | ||
![]() |
f3fdeff3e3 |
@ -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];
|
||||||
|
}
|
||||||
|
@ -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
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
@ -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:
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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
|
||||||
--------------------
|
--------------------
|
||||||
|
@ -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,
|
||||||
|
@ -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);
|
||||||
|
@ -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<[],
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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.
|
||||||
|
@ -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";
|
||||||
|
@ -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;
|
||||||
|
@ -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);
|
||||||
|
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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
|
||||||
|
13
llvm/test/CodeGen/Generic/reloc-none.ll
Normal file
13
llvm/test/CodeGen/Generic/reloc-none.ll
Normal 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)
|
@ -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
|
||||||
#
|
#
|
||||||
|
17
llvm/test/CodeGen/X86/GlobalISel/reloc-none.ll
Normal file
17
llvm/test/CodeGen/X86/GlobalISel/reloc-none.ll
Normal 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)
|
@ -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: };
|
||||||
|
@ -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),
|
||||||
|
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 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 = !{}
|
Loading…
x
Reference in New Issue
Block a user