[llvm] [CHERI][RISCV][MC] Add support for aligning and tail-padding globals for precise bounds tracking on CHERI targets. (PR #203872)

Owen Anderson via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 29 02:03:49 PDT 2026


https://github.com/resistor updated https://github.com/llvm/llvm-project/pull/203872

>From f4cb641061554c913382aaeb25fbfe9d9ecc17f5 Mon Sep 17 00:00:00 2001
From: Owen Anderson <resistor at mac.com>
Date: Wed, 10 Jun 2026 14:53:59 +0200
Subject: [PATCH] [CHERI][RISCV][MC] Add support for aligning and tail-padding
 globals for precise bounds tracking on CHERI targets.

On CHERI targets, bounds are generally stored in a compressed format which imposes alignment requirements based on allocation size. When emitting globals, we need to align and tail-pad them as appropriate to ensure that the pointer to the global will have bounds that are precise, i.e. not covering any non-padding bytes that either precede or follow it.

While this patch adds the plumbing necessary to support this feature on arbitrary targets, it only concretely implements it on RISCV for ELF objects, both the RVY base and XCheriot. Support for other targets (such as AArch64/Morello) or other object formats exists in downstreams, but is left as future work here.

Co-authored-by: Alex Richardson <alexrichardson at google.com>
---
 llvm/include/llvm/CodeGen/AsmPrinter.h        |  7 +++-
 .../DWARFCFIFunctionFrameStreamer.h           |  4 +-
 llvm/include/llvm/MC/MCAsmInfo.h              |  5 +++
 llvm/include/llvm/MC/MCDXContainerStreamer.h  |  3 +-
 llvm/include/llvm/MC/MCELFStreamer.h          |  8 ++--
 llvm/include/llvm/MC/MCGOFFStreamer.h         |  4 +-
 llvm/include/llvm/MC/MCSPIRVStreamer.h        |  4 +-
 llvm/include/llvm/MC/MCStreamer.h             | 14 +++++--
 llvm/include/llvm/MC/MCWasmStreamer.h         |  7 ++--
 llvm/include/llvm/MC/MCWinCOFFStreamer.h      |  7 ++--
 llvm/include/llvm/MC/MCXCOFFStreamer.h        |  4 +-
 .../llvm/Support/CHERICapabilityFormat.h      |  9 +++++
 .../llvm/Target/TargetLoweringObjectFile.h    | 22 ++++++++++
 llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp    | 29 ++++++++++----
 llvm/lib/MC/MCAsmStreamer.cpp                 | 32 ++++++++++++---
 llvm/lib/MC/MCELFStreamer.cpp                 | 10 +++--
 llvm/lib/MC/MCMachOStreamer.cpp               | 14 ++++---
 llvm/lib/MC/MCNullStreamer.cpp                |  4 +-
 llvm/lib/MC/MCStreamer.cpp                    |  3 +-
 llvm/lib/MC/MCWasmStreamer.cpp                |  6 ++-
 llvm/lib/MC/MCWinCOFFStreamer.cpp             |  6 ++-
 llvm/lib/MC/MCXCOFFStreamer.cpp               |  5 ++-
 llvm/lib/Object/RecordStreamer.cpp            |  3 +-
 llvm/lib/Object/RecordStreamer.h              |  4 +-
 llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp     |  2 +-
 .../Target/RISCV/MCTargetDesc/RISCVBaseInfo.h | 27 +++++++++++++
 .../RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp     |  5 +++
 llvm/lib/Target/RISCV/RISCVISelLowering.cpp   |  1 +
 .../Target/RISCV/RISCVTargetObjectFile.cpp    | 40 +++++++++++++++++++
 llvm/lib/Target/RISCV/RISCVTargetObjectFile.h |  7 ++++
 .../MCTargetDesc/SystemZHLASMAsmStreamer.h    |  5 ++-
 .../test/CodeGen/RISCV/cheri-global-bounds.ll | 26 ++++++++++++
 llvm/tools/llvm-exegesis/lib/SnippetFile.cpp  |  4 +-
 llvm/tools/llvm-mca/CodeRegionGenerator.h     |  4 +-
 llvm/unittests/CodeGen/TestAsmPrinter.h       |  5 ++-
 35 files changed, 273 insertions(+), 67 deletions(-)
 create mode 100644 llvm/test/CodeGen/RISCV/cheri-global-bounds.ll

diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h
index f6f0f7348836e..484b8f8d224d7 100644
--- a/llvm/include/llvm/CodeGen/AsmPrinter.h
+++ b/llvm/include/llvm/CodeGen/AsmPrinter.h
@@ -27,6 +27,7 @@
 #include "llvm/CodeGen/StackMaps.h"
 #include "llvm/DebugInfo/CodeView/CodeView.h"
 #include "llvm/IR/InlineAsm.h"
+#include "llvm/Support/CHERICapabilityFormat.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <cstdint>
@@ -582,8 +583,10 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass {
   /// On AIX, when an alias refers to a sub-element of a global variable, the
   /// label of that alias needs to be emitted before the corresponding element.
   using AliasMapTy = DenseMap<uint64_t, SmallVector<const GlobalAlias *, 1>>;
-  void emitGlobalConstant(const DataLayout &DL, const Constant *CV,
-                          AliasMapTy *AliasList = nullptr);
+  void
+  emitGlobalConstant(const DataLayout &DL, const Constant *CV,
+                     TailPaddingAmount TailPadding = TailPaddingAmount::None,
+                     AliasMapTy *AliasList = nullptr);
 
   /// Unnamed constant global variables solely contaning a pointer to
   /// another globals variable act like a global variable "proxy", or GOT
diff --git a/llvm/include/llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h b/llvm/include/llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h
index 5a3cf4ab64a1f..cf76027fc3599 100644
--- a/llvm/include/llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h
+++ b/llvm/include/llvm/DWARFCFIChecker/DWARFCFIFunctionFrameStreamer.h
@@ -46,8 +46,8 @@ class LLVM_ABI CFIFunctionFrameStreamer : public MCStreamer {
     return true;
   }
 
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
   void emitSubsectionsViaSymbols() override {};
   void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
   void emitCOFFSymbolStorageClass(int StorageClass) override {}
diff --git a/llvm/include/llvm/MC/MCAsmInfo.h b/llvm/include/llvm/MC/MCAsmInfo.h
index 6b2922593600f..85d590623f415 100644
--- a/llvm/include/llvm/MC/MCAsmInfo.h
+++ b/llvm/include/llvm/MC/MCAsmInfo.h
@@ -215,6 +215,9 @@ class LLVM_ABI MCAsmInfo {
   /// True if full register names are printed.
   bool PPCUseFullRegisterNames = false;
 
+  /// True if a CHERI pure capability ABI is in use.
+  bool IsCheriPureCapabilityABI = false;
+
   //===--- Data Emission Directives -------------------------------------===//
 
   /// This should be set to the directive used to get some number of zero (and
@@ -601,6 +604,8 @@ class LLVM_ABI MCAsmInfo {
   bool useFullRegisterNames() const { return PPCUseFullRegisterNames; }
   void setFullRegisterNames(bool V) { PPCUseFullRegisterNames = V; }
 
+  bool isCheriPureCapabilityABI() const { return IsCheriPureCapabilityABI; }
+
   const char *getZeroDirective() const { return ZeroDirective; }
   const char *getAsciiDirective() const { return AsciiDirective; }
   const char *getAscizDirective() const { return AscizDirective; }
diff --git a/llvm/include/llvm/MC/MCDXContainerStreamer.h b/llvm/include/llvm/MC/MCDXContainerStreamer.h
index 37e3c7ddaad2c..123bfd85f140d 100644
--- a/llvm/include/llvm/MC/MCDXContainerStreamer.h
+++ b/llvm/include/llvm/MC/MCDXContainerStreamer.h
@@ -34,7 +34,8 @@ class MCDXContainerStreamer : public MCObjectStreamer {
                          std::move(Emitter)) {}
 
   bool emitSymbolAttribute(MCSymbol *, MCSymbolAttr) override { return false; }
-  void emitCommonSymbol(MCSymbol *, uint64_t, Align) override {}
+  void emitCommonSymbol(MCSymbol *, uint64_t, Align,
+                        TailPaddingAmount TailPadding) override {}
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCELFStreamer.h b/llvm/include/llvm/MC/MCELFStreamer.h
index e1c86d8b12715..01a7d852d36bb 100644
--- a/llvm/include/llvm/MC/MCELFStreamer.h
+++ b/llvm/include/llvm/MC/MCELFStreamer.h
@@ -54,15 +54,17 @@ class LLVM_ABI MCELFStreamer : public MCObjectStreamer {
                       uint64_t Offset) override;
   void emitWeakReference(MCSymbol *Alias, const MCSymbol *Target) override;
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(
+      MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+      TailPaddingAmount TailPadding = TailPaddingAmount::None) override;
 
   void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
   void emitELFSymverDirective(const MCSymbol *OriginalSym, StringRef Name,
                               bool KeepOriginalSym) override;
 
   void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
+                             Align ByteAlignment,
+                             TailPaddingAmount TailPadding) override;
 
   void emitIdent(StringRef IdentString) override;
 
diff --git a/llvm/include/llvm/MC/MCGOFFStreamer.h b/llvm/include/llvm/MC/MCGOFFStreamer.h
index 756574d1caaf3..b8af787b46d35 100644
--- a/llvm/include/llvm/MC/MCGOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCGOFFStreamer.h
@@ -36,8 +36,8 @@ class LLVM_ABI MCGOFFStreamer : public MCObjectStreamer {
 
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
 
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCSPIRVStreamer.h b/llvm/include/llvm/MC/MCSPIRVStreamer.h
index 42559f7522b50..0babc4c648c5f 100644
--- a/llvm/include/llvm/MC/MCSPIRVStreamer.h
+++ b/llvm/include/llvm/MC/MCSPIRVStreamer.h
@@ -33,8 +33,8 @@ class MCSPIRVStreamer : public MCObjectStreamer {
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
     return false;
   }
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
 };
 
 } // end namespace llvm
diff --git a/llvm/include/llvm/MC/MCStreamer.h b/llvm/include/llvm/MC/MCStreamer.h
index f1479f860e885..ca23ea9c6c0f8 100644
--- a/llvm/include/llvm/MC/MCStreamer.h
+++ b/llvm/include/llvm/MC/MCStreamer.h
@@ -23,6 +23,7 @@
 #include "llvm/MC/MCPseudoProbe.h"
 #include "llvm/MC/MCSection.h"
 #include "llvm/MC/MCWinEH.h"
+#include "llvm/Support/CHERICapabilityFormat.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MD5.h"
@@ -691,16 +692,21 @@ class LLVM_ABI MCStreamer {
   /// \param Symbol - The common symbol to emit.
   /// \param Size - The size of the common symbol.
   /// \param ByteAlignment - The alignment of the symbol.
-  virtual void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                Align ByteAlignment) = 0;
+  /// \param TailPadding - The number of tail padding bytes required to maintain
+  /// precise CHERI bounds.
+  virtual void
+  emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                   TailPaddingAmount TailPadding = TailPaddingAmount::None) = 0;
 
   /// Emit a local common (.lcomm) symbol.
   ///
   /// \param Symbol - The common symbol to emit.
   /// \param Size - The size of the common symbol.
   /// \param ByteAlignment - The alignment of the common symbol in bytes.
-  virtual void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                     Align ByteAlignment);
+  /// \param TailPadding - The number of bytes to pad for precise bounds.
+  virtual void emitLocalCommonSymbol(
+      MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+      TailPaddingAmount TailPadding = TailPaddingAmount::None);
 
   /// Emit the zerofill section and an optional symbol.
   ///
diff --git a/llvm/include/llvm/MC/MCWasmStreamer.h b/llvm/include/llvm/MC/MCWasmStreamer.h
index fe5cdc4156eb2..3c627c2b96ea8 100644
--- a/llvm/include/llvm/MC/MCWasmStreamer.h
+++ b/llvm/include/llvm/MC/MCWasmStreamer.h
@@ -45,13 +45,14 @@ class LLVM_ABI MCWasmStreamer : public MCObjectStreamer {
   void emitLabelAtPos(MCSymbol *Symbol, SMLoc Loc, MCFragment &F,
                       uint64_t Offset) override;
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override;
 
   void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
 
   void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
+                             Align ByteAlignment,
+                             TailPaddingAmount TailPadding) override;
 
   void emitIdent(StringRef IdentString) override;
 
diff --git a/llvm/include/llvm/MC/MCWinCOFFStreamer.h b/llvm/include/llvm/MC/MCWinCOFFStreamer.h
index c6047cb309dd9..9a374263efd34 100644
--- a/llvm/include/llvm/MC/MCWinCOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCWinCOFFStreamer.h
@@ -58,10 +58,11 @@ class LLVM_ABI MCWinCOFFStreamer : public MCObjectStreamer {
   void emitCOFFImgRel32(MCSymbol const *Symbol, int64_t Offset) override;
   void emitCOFFSecNumber(MCSymbol const *Symbol) override;
   void emitCOFFSecOffset(MCSymbol const *Symbol) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override;
   void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
+                             Align ByteAlignment,
+                             TailPaddingAmount TailPadding) override;
   void emitWeakReference(MCSymbol *Alias, const MCSymbol *Symbol) override;
   void emitIdent(StringRef IdentString) override;
   void emitWinEHHandlerData(SMLoc Loc) override;
diff --git a/llvm/include/llvm/MC/MCXCOFFStreamer.h b/llvm/include/llvm/MC/MCXCOFFStreamer.h
index 884f6ed69a664..d3882e444aa3b 100644
--- a/llvm/include/llvm/MC/MCXCOFFStreamer.h
+++ b/llvm/include/llvm/MC/MCXCOFFStreamer.h
@@ -24,8 +24,8 @@ class LLVM_ABI MCXCOFFStreamer : public MCObjectStreamer {
 
   void changeSection(MCSection *Section, uint32_t Subsection = 0) override;
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override;
   void emitXCOFFLocalCommonSymbol(MCSymbol *LabelSym, uint64_t Size,
                                   MCSymbol *CsectSym, Align Alignment) override;
   void emitXCOFFSymbolLinkageWithVisibility(MCSymbol *Symbol,
diff --git a/llvm/include/llvm/Support/CHERICapabilityFormat.h b/llvm/include/llvm/Support/CHERICapabilityFormat.h
index bbf589df73339..e3850985b3134 100644
--- a/llvm/include/llvm/Support/CHERICapabilityFormat.h
+++ b/llvm/include/llvm/Support/CHERICapabilityFormat.h
@@ -14,6 +14,8 @@
 
 namespace llvm {
 
+enum class TailPaddingAmount : uint64_t { None = 0u };
+
 template <typename Derived, typename AddressType>
 struct CHERICapabilityFormatBase {
   CHERICapabilityFormatBase() = delete;
@@ -32,6 +34,13 @@ struct CHERICapabilityFormatBase {
     return Align((~getAlignmentMask(Length) + 1) & AddressMask);
   }
 
+  /// Returns the amount of padding bytes required to have precise bounds on an
+  /// allocation of size \p Length.
+  static TailPaddingAmount getRequiredTailPadding(AddressType Length) {
+    return static_cast<TailPaddingAmount>(
+        llvm::alignTo(Length, getRequiredAlignment(Length)) - Length);
+  }
+
   /// Returns \p Length rounded up to the nearest representable allocation
   /// length.
   static AddressType getRepresentableLength(AddressType Length) {
diff --git a/llvm/include/llvm/Target/TargetLoweringObjectFile.h b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
index 800bbe45c6a97..944de2e04d3c7 100644
--- a/llvm/include/llvm/Target/TargetLoweringObjectFile.h
+++ b/llvm/include/llvm/Target/TargetLoweringObjectFile.h
@@ -16,6 +16,7 @@
 
 #include "llvm/MC/MCObjectFileInfo.h"
 #include "llvm/MC/MCRegister.h"
+#include "llvm/Support/CHERICapabilityFormat.h"
 #include "llvm/Support/Compiler.h"
 #include <cstdint>
 
@@ -306,6 +307,27 @@ class LLVM_ABI TargetLoweringObjectFile : public MCObjectFileInfo {
     return nullptr;
   }
 
+  //===--------------------------------------------------------------------===//
+  // CHERI-related hooks
+  //
+
+  /// CHERI targets have compressed bounds, which place requirements on the
+  /// alignment of allocations based on their size. To guarantee non-overlapping
+  /// bounds for all global symbols we must over-align the symbol if the size is
+  /// not precisely representable. We also add padding at the end to ensure that
+  /// we cannot access another variable that happens to be located in the bytes
+  /// that are accessible after the end of the object due to the bounds having
+  /// been rounded up.
+  virtual TailPaddingAmount
+  getTailPaddingForPreciseBounds(uint64_t Size, const TargetMachine &TM) const {
+    return TailPaddingAmount::None;
+  }
+
+  virtual Align getAlignmentForPreciseBounds(uint64_t Size,
+                                             const TargetMachine &TM) const {
+    return {};
+  }
+
 protected:
   virtual MCSection *SelectSectionForGlobal(const GlobalObject *GO,
                                             SectionKind Kind,
diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
index aedc4956f1bd8..97f916117c407 100644
--- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
+++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp
@@ -848,7 +848,17 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   // If the alignment is specified, we *must* obey it.  Overaligning a global
   // with a specified alignment is a prompt way to break globals emitted to
   // sections and expected to be contiguous (e.g. ObjC metadata).
-  const Align Alignment = getGVAlignment(GV, DL);
+  Align Alignment = getGVAlignment(GV, DL);
+
+  const TailPaddingAmount TailPadding =
+      getObjFileLowering().getTailPaddingForPreciseBounds(Size, TM);
+  const Align PreciseAlignment =
+      getObjFileLowering().getAlignmentForPreciseBounds(Size, TM);
+
+  if (PreciseAlignment > Alignment && !GV->hasSection()) {
+    // Don't increase alignment if a custom section has been specified:
+    Alignment = PreciseAlignment;
+  }
 
   for (auto &Handler : Handlers)
     Handler->setSymbolSize(GVSym, Size);
@@ -857,7 +867,7 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   if (GVKind.isCommon()) {
     if (Size == 0) Size = 1;   // .comm Foo, 0 is undefined, avoid it.
     // .comm _foo, 42, 4
-    OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
+    OutStreamer->emitCommonSymbol(GVSym, Size, Alignment, TailPadding);
     return;
   }
 
@@ -890,14 +900,14 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
     // Prefer to simply fall back to .local / .comm in this case.
     if (MAI.getLCOMMDirectiveAlignmentType() != LCOMM::NoAlignment) {
       // .lcomm _foo, 42
-      OutStreamer->emitLocalCommonSymbol(GVSym, Size, Alignment);
+      OutStreamer->emitLocalCommonSymbol(GVSym, Size, Alignment, TailPadding);
       return;
     }
 
     // .local _foo
     OutStreamer->emitSymbolAttribute(GVSym, MCSA_Local);
     // .comm _foo, 42, 4
-    OutStreamer->emitCommonSymbol(GVSym, Size, Alignment);
+    OutStreamer->emitCommonSymbol(GVSym, Size, Alignment, TailPadding);
     return;
   }
 
@@ -925,8 +935,8 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
       emitAlignment(Alignment, GV);
       OutStreamer->emitLabel(MangSym);
 
-      emitGlobalConstant(GV->getDataLayout(),
-                         GV->getInitializer());
+      emitGlobalConstant(GV->getDataLayout(), GV->getInitializer(),
+                         TailPadding);
     }
 
     OutStreamer->addBlankLine();
@@ -965,7 +975,7 @@ void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) {
   if (LocalAlias != EmittedInitSym)
     OutStreamer->emitLabel(LocalAlias);
 
-  emitGlobalConstant(GV->getDataLayout(), GV->getInitializer());
+  emitGlobalConstant(GV->getDataLayout(), GV->getInitializer(), TailPadding);
 
   if (MAI.hasDotTypeDotSizeDirective())
     // .size foo, 42
@@ -4572,6 +4582,7 @@ static void emitGlobalConstantImpl(const DataLayout &DL, const Constant *CV,
 
 /// EmitGlobalConstant - Print a general LLVM constant to the .s file.
 void AsmPrinter::emitGlobalConstant(const DataLayout &DL, const Constant *CV,
+                                    TailPaddingAmount TailPadding,
                                     AliasMapTy *AliasList) {
   uint64_t Size = DL.getTypeAllocSize(CV->getType());
   if (Size)
@@ -4581,6 +4592,10 @@ void AsmPrinter::emitGlobalConstant(const DataLayout &DL, const Constant *CV,
     // look like they are at the same location.
     OutStreamer->emitIntValue(0, 1);
   }
+  if (TailPadding != TailPaddingAmount::None) {
+    OutStreamer->AddComment("Tail padding to ensure precise bounds");
+    OutStreamer->emitZeros(static_cast<uint64_t>(TailPadding));
+  }
   if (!AliasList)
     return;
   // TODO: These remaining aliases are not emitted in the correct location. Need
diff --git a/llvm/lib/MC/MCAsmStreamer.cpp b/llvm/lib/MC/MCAsmStreamer.cpp
index a518daa997945..f623f55b600a8 100644
--- a/llvm/lib/MC/MCAsmStreamer.cpp
+++ b/llvm/lib/MC/MCAsmStreamer.cpp
@@ -238,16 +238,18 @@ class MCAsmStreamer final : public MCAsmBaseStreamer {
   void emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) override;
 
   void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override;
 
   /// Emit a local common (.lcomm) symbol.
   ///
   /// @param Symbol - The common symbol to emit.
   /// @param Size - The size of the common symbol.
   /// @param ByteAlignment - The alignment of the common symbol in bytes.
+  /// @param TailPadding - The number of bytes to pad for precise bounds.
   void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
+                             Align ByteAlignment,
+                             TailPaddingAmount TailPadding) override;
 
   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
                     uint64_t Size = 0, Align ByteAlignment = Align(1),
@@ -1098,10 +1100,11 @@ void MCAsmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
 }
 
 void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                     Align ByteAlignment) {
+                                     Align ByteAlignment,
+                                     TailPaddingAmount TailPadding) {
   OS << "\t.comm\t";
   Symbol->print(OS, MAI);
-  OS << ',' << Size;
+  OS << ',' << (Size + static_cast<uint64_t>(TailPadding));
 
   if (MAI->getCOMMDirectiveAlignmentIsInBytes())
     OS << ',' << ByteAlignment.value();
@@ -1109,6 +1112,14 @@ void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
     OS << ',' << Log2(ByteAlignment);
   EmitEOL();
 
+  if (TailPadding != TailPaddingAmount::None) {
+    // If we added padding, we need to emit an explicit symbol size directive
+    AddComment("explicit size directive required due to " +
+               Twine(static_cast<uint64_t>(TailPadding)) +
+               " bytes of tail padding for precise bounds.");
+    emitELFSize(Symbol, MCConstantExpr::create(Size, getContext()));
+  }
+
   // Print symbol's rename (original name contains invalid character(s)) if
   // there is one.
   if (getContext().isXCOFF()) {
@@ -1119,7 +1130,8 @@ void MCAsmStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
 }
 
 void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                          Align ByteAlign) {
+                                          Align ByteAlign,
+                                          TailPaddingAmount TailPadding) {
   OS << "\t.lcomm\t";
   Symbol->print(OS, MAI);
   OS << ',' << Size;
@@ -1137,6 +1149,14 @@ void MCAsmStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
     }
   }
   EmitEOL();
+
+  if (TailPadding != TailPaddingAmount::None) {
+    // If we added padding, we need to emit an explicit symbol size directive
+    AddComment("explicit size directive required due to " +
+               Twine(static_cast<uint64_t>(TailPadding)) +
+               " bytes of tail padding for precise bounds.");
+    emitELFSize(Symbol, MCConstantExpr::create(Size, getContext()));
+  }
 }
 
 void MCAsmStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
diff --git a/llvm/lib/MC/MCELFStreamer.cpp b/llvm/lib/MC/MCELFStreamer.cpp
index a18b27b2dc132..fa3ccadae6984 100644
--- a/llvm/lib/MC/MCELFStreamer.cpp
+++ b/llvm/lib/MC/MCELFStreamer.cpp
@@ -247,7 +247,8 @@ bool MCELFStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
 }
 
 void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
-                                     Align ByteAlignment) {
+                                     Align ByteAlignment,
+                                     TailPaddingAmount TailPadding) {
   auto *Symbol = static_cast<MCSymbolELF *>(S);
   getAssembler().registerSymbol(*Symbol);
 
@@ -264,7 +265,7 @@ void MCELFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
 
     emitValueToAlignment(ByteAlignment, 0, 1, 0);
     emitLabel(Symbol);
-    emitZeros(Size);
+    emitZeros(Size + static_cast<uint64_t>(TailPadding));
 
     switchSection(P.first, P.second);
   } else {
@@ -288,12 +289,13 @@ void MCELFStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
 }
 
 void MCELFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
-                                          Align ByteAlignment) {
+                                          Align ByteAlignment,
+                                          TailPaddingAmount TailPadding) {
   auto *Symbol = static_cast<MCSymbolELF *>(S);
   // FIXME: Should this be caught and done earlier?
   getAssembler().registerSymbol(*Symbol);
   Symbol->setBinding(ELF::STB_LOCAL);
-  emitCommonSymbol(Symbol, Size, ByteAlignment);
+  emitCommonSymbol(Symbol, Size, ByteAlignment, TailPadding);
 }
 
 void MCELFStreamer::emitCGProfileEntry(const MCSymbolRefExpr *From,
diff --git a/llvm/lib/MC/MCMachOStreamer.cpp b/llvm/lib/MC/MCMachOStreamer.cpp
index dbb5dd79d1eb5..ed5051834f490 100644
--- a/llvm/lib/MC/MCMachOStreamer.cpp
+++ b/llvm/lib/MC/MCMachOStreamer.cpp
@@ -97,11 +97,13 @@ class MCMachOStreamer : public MCObjectStreamer {
                                            VersionTuple SDKVersion) override;
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
   void emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(
+      MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+      TailPaddingAmount TailPadding = TailPaddingAmount::None) override;
 
   void emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                             Align ByteAlignment) override;
+                             Align ByteAlignment,
+                             TailPaddingAmount TailPadding) override;
   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
                     uint64_t Size = 0, Align ByteAlignment = Align(1),
                     SMLoc Loc = SMLoc()) override;
@@ -373,7 +375,8 @@ void MCMachOStreamer::emitSymbolDesc(MCSymbol *Symbol, unsigned DescValue) {
 }
 
 void MCMachOStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                       Align ByteAlignment) {
+                                       Align ByteAlignment,
+                                       TailPaddingAmount TailPadding) {
   auto &Sym = static_cast<MCSymbolMachO &>(*Symbol);
   // FIXME: Darwin 'as' does appear to allow redef of a .comm by itself.
   assert(Symbol->isUndefined() && "Cannot define a symbol twice!");
@@ -384,7 +387,8 @@ void MCMachOStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
 }
 
 void MCMachOStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                            Align ByteAlignment) {
+                                            Align ByteAlignment,
+                                            TailPaddingAmount TailPadding) {
   // '.lcomm' is equivalent to '.zerofill'.
   return emitZerofill(getContext().getObjectFileInfo()->getDataBSSSection(),
                       Symbol, Size, ByteAlignment);
diff --git a/llvm/lib/MC/MCNullStreamer.cpp b/llvm/lib/MC/MCNullStreamer.cpp
index 651d4b8f37791..d932ae03f4daa 100644
--- a/llvm/lib/MC/MCNullStreamer.cpp
+++ b/llvm/lib/MC/MCNullStreamer.cpp
@@ -34,8 +34,8 @@ class MCNullStreamer : public MCStreamer {
     return true;
   }
 
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
   void emitSubsectionsViaSymbols() override {};
   void beginCOFFSymbolDef(const MCSymbol *Symbol) override {}
   void emitCOFFSymbolStorageClass(int StorageClass) override {}
diff --git a/llvm/lib/MC/MCStreamer.cpp b/llvm/lib/MC/MCStreamer.cpp
index 1cd94715b2592..9ef299b8609df 100644
--- a/llvm/lib/MC/MCStreamer.cpp
+++ b/llvm/lib/MC/MCStreamer.cpp
@@ -1490,7 +1490,8 @@ void MCStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {}
 void MCStreamer::emitELFSymverDirective(const MCSymbol *OriginalSym,
                                         StringRef Name, bool KeepOriginalSym) {}
 void MCStreamer::emitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                       Align ByteAlignment) {}
+                                       Align ByteAlignment,
+                                       TailPaddingAmount TailPadding) {}
 void MCStreamer::emitZerofill(MCSection *, MCSymbol *, uint64_t, Align, SMLoc) {
 }
 void MCStreamer::emitTBSSSymbol(MCSection *Section, MCSymbol *Symbol,
diff --git a/llvm/lib/MC/MCWasmStreamer.cpp b/llvm/lib/MC/MCWasmStreamer.cpp
index 8b4ae4cee3e79..b1b0c8544b194 100644
--- a/llvm/lib/MC/MCWasmStreamer.cpp
+++ b/llvm/lib/MC/MCWasmStreamer.cpp
@@ -129,7 +129,8 @@ bool MCWasmStreamer::emitSymbolAttribute(MCSymbol *S, MCSymbolAttr Attribute) {
 }
 
 void MCWasmStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
-                                      Align ByteAlignment) {
+                                      Align ByteAlignment,
+                                      TailPaddingAmount TailPadding) {
   getContext().reportError(getStartTokLoc(),
                            "common symbols are not yet implemented for Wasm: " +
                                S->getName());
@@ -140,7 +141,8 @@ void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
 }
 
 void MCWasmStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
-                                           Align ByteAlignment) {
+                                           Align ByteAlignment,
+                                           TailPaddingAmount TailPadding) {
   getContext().reportError(getStartTokLoc(),
                            "local common symbols are not yet implemented "
                            "for Wasm: " +
diff --git a/llvm/lib/MC/MCWinCOFFStreamer.cpp b/llvm/lib/MC/MCWinCOFFStreamer.cpp
index 467b8e634f03e..8978c35f14587 100644
--- a/llvm/lib/MC/MCWinCOFFStreamer.cpp
+++ b/llvm/lib/MC/MCWinCOFFStreamer.cpp
@@ -335,7 +335,8 @@ void MCWinCOFFStreamer::emitCOFFSecOffset(MCSymbol const *Symbol) {
 }
 
 void MCWinCOFFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
-                                         Align ByteAlignment) {
+                                         Align ByteAlignment,
+                                         TailPaddingAmount TailPadding) {
   auto *Symbol = static_cast<MCSymbolCOFF *>(S);
 
   const Triple &T = getContext().getTargetTriple();
@@ -367,7 +368,8 @@ void MCWinCOFFStreamer::emitCommonSymbol(MCSymbol *S, uint64_t Size,
 }
 
 void MCWinCOFFStreamer::emitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
-                                              Align ByteAlignment) {
+                                              Align ByteAlignment,
+                                              TailPaddingAmount TailPadding) {
   auto *Symbol = static_cast<MCSymbolCOFF *>(S);
 
   MCSection *Section = getContext().getObjectFileInfo()->getBSSSection();
diff --git a/llvm/lib/MC/MCXCOFFStreamer.cpp b/llvm/lib/MC/MCXCOFFStreamer.cpp
index b459b26045ae7..02f8d67dc1d8c 100644
--- a/llvm/lib/MC/MCXCOFFStreamer.cpp
+++ b/llvm/lib/MC/MCXCOFFStreamer.cpp
@@ -130,8 +130,9 @@ void MCXCOFFStreamer::emitXCOFFCInfoSym(StringRef Name, StringRef Metadata) {
   getWriter().addCInfoSymEntry(Name, Metadata);
 }
 
-void MCXCOFFStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                       Align ByteAlignment) {
+void MCXCOFFStreamer::emitCommonSymbol(
+    MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+    TailPaddingAmount TailPadding = TailPaddingAmount::None) {
   auto &Sym = static_cast<MCSymbolXCOFF &>(*Symbol);
   getAssembler().registerSymbol(*Symbol);
   Sym.setExternal(Sym.getStorageClass() != XCOFF::C_HIDEXT);
diff --git a/llvm/lib/Object/RecordStreamer.cpp b/llvm/lib/Object/RecordStreamer.cpp
index 6e8d0c477803e..35e2597c941c4 100644
--- a/llvm/lib/Object/RecordStreamer.cpp
+++ b/llvm/lib/Object/RecordStreamer.cpp
@@ -107,7 +107,8 @@ void RecordStreamer::emitZerofill(MCSection *Section, MCSymbol *Symbol,
 }
 
 void RecordStreamer::emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                                      Align ByteAlignment) {
+                                      Align ByteAlignment,
+                                      TailPaddingAmount TailPadding) {
   markDefined(*Symbol);
 }
 
diff --git a/llvm/lib/Object/RecordStreamer.h b/llvm/lib/Object/RecordStreamer.h
index edb6e3ae118bf..52421969a8fd6 100644
--- a/llvm/lib/Object/RecordStreamer.h
+++ b/llvm/lib/Object/RecordStreamer.h
@@ -51,8 +51,8 @@ class RecordStreamer : public MCStreamer {
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
   void emitZerofill(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
                     Align ByteAlignment, SMLoc Loc = SMLoc()) override;
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override;
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override;
 
   // Ignore format-specific directives; we do not need any information from
   // them, but the default implementation of these methods crashes, so we
diff --git a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
index 51f2ff4a68be7..d36ab6151ce58 100644
--- a/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
+++ b/llvm/lib/Target/PowerPC/PPCAsmPrinter.cpp
@@ -2881,7 +2881,7 @@ void PPCAIXAsmPrinter::emitGlobalVariableHelper(const GlobalVariable *GV) {
 
   // Emit alias label and element value for global variable.
   emitGlobalConstant(GV->getDataLayout(), GV->getInitializer(),
-                     &AliasList);
+                     TailPaddingAmount::None, &AliasList);
 }
 
 void PPCAIXAsmPrinter::emitFunctionDescriptor() {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
index adf5d5d8b3759..246ffe52247bd 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVBaseInfo.h
@@ -701,6 +701,33 @@ MCRegister getBPReg();
 // Returns the register holding shadow call stack pointer.
 MCRegister getSCSPReg();
 
+// Returns whether the ABI is "pure capability", without non-capability
+// pointers.
+inline static bool isCHERIPureCapabilityABI(ABI TargetABI) {
+  switch (TargetABI) {
+  case ABI_ILP32:
+  case ABI_ILP32F:
+  case ABI_ILP32D:
+  case ABI_ILP32E:
+  case ABI_LP64:
+  case ABI_LP64F:
+  case ABI_LP64D:
+  case ABI_LP64E:
+    return false;
+  case ABI_IL32PC64:
+  case ABI_IL32PC64F:
+  case ABI_IL32PC64D:
+  case ABI_IL32PC64E:
+  case ABI_L64PC128:
+  case ABI_L64PC128F:
+  case ABI_L64PC128D:
+  case ABI_CHERIOT:
+    return true;
+  default:
+    llvm_unreachable("Improperly initialised target ABI");
+  }
+}
+
 } // namespace RISCVABI
 
 namespace RISCVFeatures {
diff --git a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
index 9ab46a91a2a97..ce3ed254df17b 100644
--- a/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
+++ b/llvm/lib/Target/RISCV/MCTargetDesc/RISCVMCAsmInfo.cpp
@@ -11,6 +11,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "RISCVMCAsmInfo.h"
+#include "MCTargetDesc/RISCVBaseInfo.h"
 #include "llvm/BinaryFormat/Dwarf.h"
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/MC/MCExpr.h"
@@ -30,6 +31,10 @@ RISCVMCAsmInfo::RISCVMCAsmInfo(const Triple &TT, const MCTargetOptions &Options)
   ExceptionsType = ExceptionHandling::DwarfCFI;
   Data16bitsDirective = "\t.half\t";
   Data32bitsDirective = "\t.word\t";
+
+  RISCVABI::ABI ABI = RISCVABI::getTargetABI(Options.getABIName());
+  IsCheriPureCapabilityABI =
+      ABI != RISCVABI::ABI_Unknown && RISCVABI::isCHERIPureCapabilityABI(ABI);
 }
 
 const MCExpr *RISCVMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index e5ce36afb7b2f..949675fbac56e 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -43,6 +43,7 @@
 #include "llvm/IR/IntrinsicsRISCV.h"
 #include "llvm/MC/MCCodeEmitter.h"
 #include "llvm/MC/MCInstBuilder.h"
+#include "llvm/Support/CHERICapabilityFormat.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/Debug.h"
 #include "llvm/Support/ErrorHandling.h"
diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
index 9f3666f1a2ff6..17bdde901c273 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.cpp
@@ -12,9 +12,11 @@
 #include "llvm/BinaryFormat/ELF.h"
 #include "llvm/IR/Mangler.h"
 #include "llvm/IR/Module.h"
+#include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCSectionELF.h"
 #include "llvm/MC/MCValue.h"
+#include "llvm/Support/CHERICapabilityFormat.h"
 
 using namespace llvm;
 
@@ -193,6 +195,44 @@ MCSection *RISCVELFTargetObjectFile::getSectionForConstant(
                                                             Alignment, F);
 }
 
+TailPaddingAmount RISCVELFTargetObjectFile::getTailPaddingForPreciseBounds(
+    uint64_t Size, const TargetMachine &TM) const {
+  if (!TM.getMCAsmInfo().isCheriPureCapabilityABI())
+    return TailPaddingAmount::None;
+
+  const auto &STI = TM.getMCSubtargetInfo();
+  if (STI.hasFeature(RISCV::FeatureVendorXCheriot))
+    return CHERIoTCapabilityFormat::getRequiredTailPadding(Size);
+
+  if (STI.hasFeature(RISCV::FeatureStdExtY)) {
+    if (STI.hasFeature(RISCV::Feature64Bit))
+      return RV64YCapabilityFormat::getRequiredTailPadding(Size);
+    else
+      return RV32YCapabilityFormat::getRequiredTailPadding(Size);
+  }
+
+  return TargetLoweringObjectFile::getTailPaddingForPreciseBounds(Size, TM);
+}
+
+Align RISCVELFTargetObjectFile::getAlignmentForPreciseBounds(
+    uint64_t Size, const TargetMachine &TM) const {
+  if (!TM.getMCAsmInfo().isCheriPureCapabilityABI())
+    return Align();
+
+  const auto &STI = TM.getMCSubtargetInfo();
+  if (STI.hasFeature(RISCV::FeatureVendorXCheriot))
+    return CHERIoTCapabilityFormat::getRequiredAlignment(Size);
+
+  if (STI.hasFeature(RISCV::FeatureStdExtY)) {
+    if (STI.hasFeature(RISCV::Feature64Bit))
+      return RV64YCapabilityFormat::getRequiredAlignment(Size);
+    else
+      return RV32YCapabilityFormat::getRequiredAlignment(Size);
+  }
+
+  return TargetLoweringObjectFile::getAlignmentForPreciseBounds(Size, TM);
+}
+
 void RISCVMachOTargetObjectFile::getNameWithPrefix(
     SmallVectorImpl<char> &OutName, const GlobalValue *GV,
     const TargetMachine &TM) const {
diff --git a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h
index db03a0546079d..e17fb2a3c019f 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h
+++ b/llvm/lib/Target/RISCV/RISCVTargetObjectFile.h
@@ -53,6 +53,13 @@ class RISCVELFTargetObjectFile : public TargetLoweringObjectFileELF {
                                           const MCValue &MV, int64_t Offset,
                                           MachineModuleInfo *MMI,
                                           MCStreamer &Streamer) const override;
+
+  TailPaddingAmount
+  getTailPaddingForPreciseBounds(uint64_t Size,
+                                 const TargetMachine &TM) const override;
+
+  Align getAlignmentForPreciseBounds(uint64_t Size,
+                                     const TargetMachine &TM) const override;
 };
 
 class RISCVMachOTargetObjectFile : public TargetLoweringObjectFileMachO {
diff --git a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
index d3fe8d791dd0f..43b2e8916908c 100644
--- a/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
+++ b/llvm/lib/Target/SystemZ/MCTargetDesc/SystemZHLASMAsmStreamer.h
@@ -106,8 +106,9 @@ class SystemZHLASMAsmStreamer final : public MCStreamer {
   void emitLabel(MCSymbol *Symbol, SMLoc Loc) override;
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override;
 
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(
+      MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+      TailPaddingAmount TailPadding = TailPaddingAmount::None) override {}
 
   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
                     uint64_t Size = 0, Align ByteAlignment = Align(1),
diff --git a/llvm/test/CodeGen/RISCV/cheri-global-bounds.ll b/llvm/test/CodeGen/RISCV/cheri-global-bounds.ll
new file mode 100644
index 0000000000000..a131cdb5e9b16
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cheri-global-bounds.ll
@@ -0,0 +1,26 @@
+; RUN: llc -mtriple riscv32 -mattr=+experimental-y -target-abi il32pc64 %s -o - | FileCheck -check-prefix=RVY32 %s
+; RUN: llc -mtriple riscv64 -mattr=+experimental-y -target-abi l64pc128 %s -o - | FileCheck -check-prefix=RVY64 %s
+; RUN: llc -mtriple riscv64 -mattr=+xcheriot -target-abi cheriot %s -o - | FileCheck -check-prefix=CHERIOT %s
+
+ at global1 = global [6995 x i8] zeroinitializer, align 1
+
+; RVY32-LABEL: .globl global1
+; RVY32-NEXT:  .p2align 7, 0x0
+; RVY32-NEXT:  global1:
+; RVY32-NEXT:  .zero 6995
+; RVY32-NEXT:  .zero   45   # Tail padding to ensure precise bounds
+; RVY32-NEXT:  .size global1, 6995
+
+; RVY64-LABEL: .globl global1
+; RVY64-NEXT:  .p2align 3, 0x0
+; RVY64-NEXT:  global1:
+; RVY64-NEXT:  .zero 6995
+; RVY64-NEXT:  .zero   5   # Tail padding to ensure precise bounds
+; RVY64-NEXT:  .size global1, 6995
+
+; CHERIOT-LABEL: .globl global1
+; CHERIOT-NEXT:  .p2align 4, 0x0
+; CHERIOT-NEXT:  global1:
+; CHERIOT-NEXT:  .zero 6995
+; CHERIOT-NEXT:  .zero   13   # Tail padding to ensure precise bounds
+; CHERIOT-NEXT:  .size global1, 6995
diff --git a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
index 250b6c7429266..b7c1170826771 100644
--- a/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
+++ b/llvm/tools/llvm-exegesis/lib/SnippetFile.cpp
@@ -197,8 +197,8 @@ class BenchmarkCodeStreamer : public MCStreamer, public AsmCommentConsumer {
 
 private:
   // We only care about instructions, we don't implement this part of the API.
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
   bool emitSymbolAttribute(MCSymbol *Symbol, MCSymbolAttr Attribute) override {
     return false;
   }
diff --git a/llvm/tools/llvm-mca/CodeRegionGenerator.h b/llvm/tools/llvm-mca/CodeRegionGenerator.h
index 7083ba363081a..55206e83cc302 100644
--- a/llvm/tools/llvm-mca/CodeRegionGenerator.h
+++ b/llvm/tools/llvm-mca/CodeRegionGenerator.h
@@ -101,8 +101,8 @@ class MCStreamerWrapper : public MCStreamer {
     return true;
   }
 
-  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size,
-                        Align ByteAlignment) override {}
+  void emitCommonSymbol(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                        TailPaddingAmount TailPadding) override {}
   void emitZerofill(MCSection *Section, MCSymbol *Symbol = nullptr,
                     uint64_t Size = 0, Align ByteAlignment = Align(1),
                     SMLoc Loc = SMLoc()) override {}
diff --git a/llvm/unittests/CodeGen/TestAsmPrinter.h b/llvm/unittests/CodeGen/TestAsmPrinter.h
index 372214a55fcfe..d7a72b00e614e 100644
--- a/llvm/unittests/CodeGen/TestAsmPrinter.h
+++ b/llvm/unittests/CodeGen/TestAsmPrinter.h
@@ -30,8 +30,9 @@ class MockMCStreamer : public MCStreamer {
 
   MOCK_METHOD2(emitSymbolAttribute,
                bool(MCSymbol *Symbol, MCSymbolAttr Attribute));
-  MOCK_METHOD3(emitCommonSymbol,
-               void(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment));
+  MOCK_METHOD4(emitCommonSymbol,
+               void(MCSymbol *Symbol, uint64_t Size, Align ByteAlignment,
+                    TailPaddingAmount TailPadding));
   MOCK_METHOD5(emitZerofill,
                void(MCSection *Section, MCSymbol *Symbol, uint64_t Size,
                     Align ByteAlignment, SMLoc Loc));



More information about the llvm-commits mailing list