diff --git a/llvm/include/llvm/CodeGen/AsmPrinter.h b/llvm/include/llvm/CodeGen/AsmPrinter.h index 335bf9de9a071..f6c19280030a9 100644 --- a/llvm/include/llvm/CodeGen/AsmPrinter.h +++ b/llvm/include/llvm/CodeGen/AsmPrinter.h @@ -534,6 +534,11 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { /// Emit the specified global variable to the .s file. virtual void emitGlobalVariable(const GlobalVariable *GV); + /// Emit the specified global variable to the .s file, with an explicit + /// alignment granule applied to both address and size. + virtual void emitGlobalVariable(const GlobalVariable *GV, + MaybeAlign AlignmentGranule); + /// Check to see if the specified global is a special global used by LLVM. If /// so, emit it and return true, otherwise do nothing and return false. bool emitSpecialLLVMGlobal(const GlobalVariable *GV); @@ -1021,6 +1026,15 @@ class LLVM_ABI AsmPrinter : public MachineFunctionPass { virtual bool shouldEmitWeakSwiftAsyncExtendedFramePointerFlags() const { return false; } + + /// Returns a optional minimum alignment that applies to both the address and + /// the allocation size of the global. This is used for systems like CHERI and + /// MTE that impose a minimum alignment, and require globals to be padded to + /// that alignment. + virtual MaybeAlign + getRequiredGlobalAlignmentGranule(const GlobalVariable &GV) { + return std::nullopt; + }; }; LLVM_ABI void setupModuleAsmPrinter(Module &M, ModuleAnalysisManager &MAM, diff --git a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp index 65be7a7846a71..cbd8f1932a285 100644 --- a/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ b/llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -788,6 +788,14 @@ MCSymbol *AsmPrinter::getSymbolPreferLocal(const GlobalValue &GV) const { /// EmitGlobalVariable - Emit the specified global variable to the .s file. void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV) { + MaybeAlign AlignmentGranule = getRequiredGlobalAlignmentGranule(*GV); + emitGlobalVariable(GV, AlignmentGranule); + if (AlignmentGranule) + OutStreamer->emitValueToAlignment(*AlignmentGranule); +} + +void AsmPrinter::emitGlobalVariable(const GlobalVariable *GV, + MaybeAlign AlignmentGranule) { bool IsEmuTLSVar = TM.useEmulatedTLS() && GV->isThreadLocal(); assert(!(IsEmuTLSVar && GV->hasCommonLinkage()) && "No emulated TLS variables in the common section"); @@ -853,7 +861,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); + // + // If we get passed in an explicit alignment granule, it is up to the caller + // to ensure that is not the case (i.e. that the GV is not in a section). + Align Alignment = getGVAlignment(GV, DL); + + if (AlignmentGranule) { + assert(!GV->hasSection()); + Size = alignTo(Size, *AlignmentGranule); + if (Alignment < *AlignmentGranule) + Alignment = *AlignmentGranule; + } for (auto &Handler : Handlers) Handler->setSymbolSize(GVSym, Size); diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp index 6dee7fb37ef4c..a0a42ea1fbb8f 100644 --- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp +++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp @@ -42,6 +42,7 @@ #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/TargetRegistry.h" +#include "llvm/Support/CHERICapabilityFormat.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/raw_ostream.h" #include "llvm/TargetParser/RISCVISAInfo.h" @@ -135,6 +136,9 @@ class RISCVAsmPrinter : public AsmPrinter { void emitSled(const MachineInstr *MI, SledKind Kind); void lowerToMCInst(const MachineInstr *MI, MCInst &OutMI); + + MaybeAlign + getRequiredGlobalAlignmentGranule(const GlobalVariable &GV) override; }; } // namespace @@ -1323,6 +1327,23 @@ void RISCVAsmPrinter::emitMachineConstantPoolValue( OutStreamer->emitValue(Expr, Size); } +MaybeAlign +RISCVAsmPrinter::getRequiredGlobalAlignmentGranule(const GlobalVariable &GV) { + const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo(); + uint64_t Size = GV.getGlobalSize(getDataLayout()); + if (MCSTI.hasFeature(RISCV::FeatureVendorXCheriot)) + return CHERIoTCapabilityFormat::getRequiredAlignment(Size); + + if (MCSTI.hasFeature(RISCV::FeatureStdExtY)) { + if (MCSTI.hasFeature(RISCV::Feature64Bit)) + return RV64YCapabilityFormat::getRequiredAlignment(Size); + else + return RV32YCapabilityFormat::getRequiredAlignment(Size); + } + + return std::nullopt; +} + char RISCVAsmPrinter::ID = 0; INITIALIZE_PASS(RISCVAsmPrinter, "riscv-asm-printer", "RISC-V Assembly Printer", 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..0443338855e62 --- /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 + +@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: .size global1, 7040 +; RVY32: .p2align 7, 0x0 + +; RVY64-LABEL: .globl global1 +; RVY64-NEXT: .p2align 3, 0x0 +; RVY64-NEXT: global1: +; RVY64-NEXT: .zero 6995 +; RVY64-NEXT: .size global1, 7000 +; RVY64: .p2align 3, 0x0 + +; CHERIOT-LABEL: .globl global1 +; CHERIOT-NEXT: .p2align 4, 0x0 +; CHERIOT-NEXT: global1: +; CHERIOT-NEXT: .zero 6995 +; CHERIOT-NEXT: .size global1, 7008 +; CHERIOT: .p2align 4, 0x0