[Metadata] Introduce MD_pcsections
authorMarco Elver <elver@google.com>
Tue, 6 Sep 2022 13:48:23 +0000 (15:48 +0200)
committerMarco Elver <elver@google.com>
Tue, 6 Sep 2022 13:52:44 +0000 (15:52 +0200)
Introduces MD_pcsections metadata kind. See added documentation for
more details.

Subsequent patches enable propagating PC sections metadata through code
generation to the AsmPrinter.

RFC: https://discourse.llvm.org/t/rfc-pc-keyed-metadata-at-runtime/64191

Reviewed By: dvyukov, vitalybuka

Differential Revision: https://reviews.llvm.org/D130875

llvm/docs/PCSectionsMetadata.rst [new file with mode: 0644]
llvm/docs/Reference.rst
llvm/include/llvm/IR/FixedMetadataKinds.def
llvm/include/llvm/IR/MDBuilder.h
llvm/lib/IR/MDBuilder.cpp
llvm/unittests/IR/MDBuilderTest.cpp

diff --git a/llvm/docs/PCSectionsMetadata.rst b/llvm/docs/PCSectionsMetadata.rst
new file mode 100644 (file)
index 0000000..3be8af7
--- /dev/null
@@ -0,0 +1,116 @@
+=========================
+LLVM PC Sections Metadata
+=========================
+
+.. contents::
+   :local:
+
+Introduction
+============
+
+PC Sections Metadata can be attached to instructions and functions, for which
+addresses, viz. program counters (PCs), are to be emitted in specially encoded
+binary sections. Metadata is assigned as an ``MDNode`` of the ``MD_pcsections``
+(``!pcsections``) kind; the following section describes the metadata format.
+
+Metadata Format
+===============
+
+An arbitrary number of interleaved ``MDString`` and constant operators can be
+added, where a new ``MDString`` always denotes a section name, followed by an
+arbitrary number of auxiliary constant data encoded along the PC of the
+instruction or function. The first operator must be a ``MDString`` denoting the
+first section.
+
+.. code-block:: none
+
+  !0 = !{
+    !"<section#1>"
+    [ , !1 ... ]
+    [ !"<section#2">
+      [ , !2 ... ]
+      ... ]
+  }
+  !1 = !{ iXX <aux-consts#1>, ... }
+  !2 = !{ iXX <aux-consts#2>, ... }
+  ...
+
+The occurrence of ``section#1``, ``section#2``, ..., ``section#N`` in the
+metadata causes the backend to emit the PC for the associated instruction or
+function to all named sections. For each emitted PC in a section #N, the
+constants ``aux-consts#N`` in the tuple ``!N`` will be emitted after the PC.
+Multiple tuples with constant data may be provided after a section name string
+(e.g. ``!0 = !{"s1", !1, !2}``), and a single constant tuple may be reused for
+different sections (e.g. ``!0 = !{"s1", !1, "s2", !1}``).
+
+Binary Encoding
+===============
+
+*Instructions* result in emitting a single PC, and *functions* result in
+emission of the start of the function and a 32-bit size. This is followed by
+the auxiliary constants that followed the respective section name in the
+``MD_pcsections`` metadata.
+
+To avoid relocations in the final binary, each PC address stored at ``entry``
+is a relative relocation, computed as ``pc - entry``. To decode, a user has to
+compute ``entry + *entry``.
+
+The size of each entry depends on the code model. With large and medium sized
+code models, the entry size matches pointer size. For any smaller code model
+the entry size is just 32 bits.
+
+Guarantees on Code Generation
+=============================
+
+Attaching ``!pcsections`` metadata to LLVM IR instructions *shall not* affect
+optimizations or code generation outside the requested PC sections.
+
+While relying on LLVM IR metadata to request PC sections makes the above
+guarantee relatively trivial, propagation of metadata through the optimization
+and code generation pipeline has the following guarantees.
+
+Metadata Propagation
+--------------------
+
+In general, LLVM *does not make any guarantees* about preserving IR metadata
+(attached to an ``Instruction``) through IR transformations. When using PC
+sections metadata, this guarantee is unchanged, and ``!pcsections`` metadata is
+remains *optional* until lowering to machine IR (MIR).
+
+Note for Code Generation
+------------------------
+
+As with other LLVM IR metadata, there are no requirements for LLVM IR
+transformation passes to preserve ``!pcsections`` metadata, with the following
+exceptions:
+
+    * The ``AtomicExpandPass`` shall preserve ``!pcsections`` metadata
+      according to the below rules 1-4.
+
+When translating LLVM IR to MIR, the ``!pcsections`` metadata shall be copied
+from the source ``Instruction`` to the target ``MachineInstr`` (set with
+``MachineInstr::setPCSections()``). The instruction selectors and MIR
+optimization passes shall preserve PC sections metadata as follows:
+
+    1. Replacements will preserve PC sections metadata of the replaced
+       instruction.
+
+    2. Duplications will preserve PC sections metadata of the copied
+       instruction.
+
+    3. Merging will preserve PC sections metadata of one of the two
+       instructions (no guarantee on which instruction's metadata is used).
+
+    4. Deletions will loose PC sections metadata.
+
+This is similar to debug info, and the ``BuildMI()`` helper provides a
+convenient way to propagate debug info and ``!pcsections`` metadata in the
+``MIMetadata`` bundle.
+
+Note for Metadata Users
+-----------------------
+
+Use cases for ``!pcsections`` metadata should either be fully tolerant to
+missing metadata, or the passes inserting ``!pcsections`` metadata should run
+*after* all LLVM IR optimization passes to preserve the metadata until being
+translated to MIR.
index f6b80eb..9353eb7 100644 (file)
@@ -33,6 +33,7 @@ LLVM and API reference documentation.
    MarkedUpDisassembly\r
    MIRLangRef\r
    OptBisect\r
+   PCSectionsMetadata\r
    PDB/index\r
    PointerAuth\r
    ScudoHardenedAllocator\r
index 0981066..3d98632 100644 (file)
@@ -48,3 +48,4 @@ LLVM_FIXED_MD_KIND(MD_exclude, "exclude", 33)
 LLVM_FIXED_MD_KIND(MD_memprof, "memprof", 34)
 LLVM_FIXED_MD_KIND(MD_callsite, "callsite", 35)
 LLVM_FIXED_MD_KIND(MD_kcfi_type, "kcfi_type", 36)
+LLVM_FIXED_MD_KIND(MD_pcsections, "pcsections", 37)
index 21d7b8b..f31a769 100644 (file)
@@ -15,6 +15,7 @@
 #define LLVM_IR_MDBUILDER_H
 
 #include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/IR/GlobalValue.h"
 #include "llvm/Support/DataTypes.h"
@@ -113,6 +114,16 @@ public:
   MDNode *createRTTIPointerPrologue(Constant *PrologueSig, Constant *RTTI);
 
   //===------------------------------------------------------------------===//
+  // PC sections metadata.
+  //===------------------------------------------------------------------===//
+
+  /// A pair of PC section name with auxilliary constant data.
+  using PCSection = std::pair<StringRef, SmallVector<Constant *>>;
+
+  /// Return metadata for PC sections.
+  MDNode *createPCSections(ArrayRef<PCSection> Sections);
+
+  //===------------------------------------------------------------------===//
   // AA metadata.
   //===------------------------------------------------------------------===//
 
index fc59fda..d028eb4 100644 (file)
@@ -158,6 +158,27 @@ MDNode *MDBuilder::createRTTIPointerPrologue(Constant *PrologueSig,
   return MDNode::get(Context, Ops);
 }
 
+MDNode *MDBuilder::createPCSections(ArrayRef<PCSection> Sections) {
+  SmallVector<Metadata *, 2> Ops;
+
+  for (const auto &Entry : Sections) {
+    const StringRef &Sec = Entry.first;
+    Ops.push_back(createString(Sec));
+
+    // If auxiliary data for this section exists, append it.
+    const SmallVector<Constant *> &AuxConsts = Entry.second;
+    if (!AuxConsts.empty()) {
+      SmallVector<Metadata *, 1> AuxMDs;
+      AuxMDs.reserve(AuxConsts.size());
+      for (Constant *C : AuxConsts)
+        AuxMDs.push_back(createConstant(C));
+      Ops.push_back(MDNode::get(Context, AuxMDs));
+    }
+  }
+
+  return MDNode::get(Context, Ops);
+}
+
 MDNode *MDBuilder::createAnonymousAARoot(StringRef Name, MDNode *Extra) {
   SmallVector<Metadata *, 3> Args(1, nullptr);
   if (Extra)
index f8d08b5..2b5ab81 100644 (file)
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "llvm/IR/MDBuilder.h"
+#include "llvm/IR/Constants.h"
 #include "llvm/IR/IRBuilder.h"
 #include "llvm/IR/Metadata.h"
 #include "llvm/IR/Operator.h"
@@ -104,4 +105,26 @@ TEST_F(MDBuilderTest, createTBAANode) {
   EXPECT_EQ(mdconst::extract<ConstantInt>(N2->getOperand(2))->getZExtValue(),
             1U);
 }
+TEST_F(MDBuilderTest, createPCSections) {
+  MDBuilder MDHelper(Context);
+  ConstantInt *C1 = ConstantInt::get(Context, APInt(8, 1));
+  ConstantInt *C2 = ConstantInt::get(Context, APInt(8, 2));
+  MDNode *PCS = MDHelper.createPCSections({{"s1", {C1, C2}}, {"s2", {}}});
+  ASSERT_EQ(PCS->getNumOperands(), 3U);
+  const auto *S1 = dyn_cast<MDString>(PCS->getOperand(0));
+  const auto *Aux = dyn_cast<MDNode>(PCS->getOperand(1));
+  const auto *S2 = dyn_cast<MDString>(PCS->getOperand(2));
+  ASSERT_NE(S1, nullptr);
+  ASSERT_NE(Aux, nullptr);
+  ASSERT_NE(S2, nullptr);
+  EXPECT_EQ(S1->getString(), "s1");
+  EXPECT_EQ(S2->getString(), "s2");
+  ASSERT_EQ(Aux->getNumOperands(), 2U);
+  ASSERT_TRUE(isa<ConstantAsMetadata>(Aux->getOperand(0)));
+  ASSERT_TRUE(isa<ConstantAsMetadata>(Aux->getOperand(1)));
+  EXPECT_EQ(mdconst::extract<ConstantInt>(Aux->getOperand(0))->getValue(),
+            C1->getValue());
+  EXPECT_EQ(mdconst::extract<ConstantInt>(Aux->getOperand(1))->getValue(),
+            C2->getValue());
 }
+} // namespace