Index: include/llvm/MC/MCObjectStreamer.h =================================================================== --- include/llvm/MC/MCObjectStreamer.h +++ include/llvm/MC/MCObjectStreamer.h @@ -169,11 +169,18 @@ void FinishImpl() override; +private: + Optional absoluteSymbolDiff(const MCSymbol *hi, + const MCSymbol *Lo); + +public: /// Emit the absolute difference between two symbols if possible. /// /// Emit the absolute difference between \c Hi and \c Lo, as long as we can /// compute it. Currently, that requires that both symbols are in the same - /// data fragment. Otherwise, do nothing and return \c false. + /// data fragment and that the target has not specified that diff expressions + /// require relocations to be emitted. Otherwise, do nothing and return + /// \c false. /// /// \pre Offset of \c Hi is greater than the offset \c Lo. void emitAbsoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo, Index: lib/MC/MCObjectStreamer.cpp =================================================================== --- lib/MC/MCObjectStreamer.cpp +++ lib/MC/MCObjectStreamer.cpp @@ -53,9 +53,12 @@ // As a compile-time optimization, avoid allocating and evaluating an MCExpr // tree for (Hi - Lo) when Hi and Lo are offsets into the same fragment. -static Optional absoluteSymbolDiff(const MCSymbol *Hi, - const MCSymbol *Lo) { +Optional +MCObjectStreamer::absoluteSymbolDiff(const MCSymbol *Hi, const MCSymbol *Lo) { assert(Hi && Lo); + if (TAB->requiresDiffExpressionRelocations()) + return None; + if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() || Hi->isVariable() || Lo->isVariable()) return None; Index: test/MC/RISCV/fixups-diff.ll =================================================================== --- /dev/null +++ test/MC/RISCV/fixups-diff.ll @@ -0,0 +1,46 @@ +; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=+relax %s -o - \ +; RUN: | llvm-readobj -r | FileCheck -check-prefix=RELAX %s +; RUN: llc -filetype=obj -mtriple=riscv32 -mattr=-relax %s -o - \ +; RUN: | llvm-readobj -r | FileCheck -check-prefix=NORELAX %s + +; Check that a difference between two symbols in the same fragment +; causes relocations to be emitted if and only if relaxation is enabled. +; +; This specific test is checking that the size of the function in +; the debug information is represented by a relocation. This isn't +; an assembly test as the assembler takes a different path through +; LLVM, which is already covered by the fixups-expr.s test. + +source_filename = "tmp.c" +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32" + +define i32 @main() !dbg !7 { +entry: + %retval = alloca i32, align 4 + store i32 0, i32* %retval, align 4 + ret i32 0 +} + +; RELAX: 0x22 R_RISCV_ADD32 - 0x0 +; RELAX: 0x22 R_RISCV_SUB32 - 0x0 +; RELAX: 0x2B R_RISCV_ADD32 - 0x0 +; RELAX: 0x2B R_RISCV_SUB32 - 0x0 +; NORELAX-NOT: R_RISCV_ADD32 + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2) +!1 = !DIFile(filename: "fixups-diff.ll", directory: "test/MC/RISCV") +!2 = !{} +!3 = !{i32 2, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang"} +!7 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 1, type: !8, isLocal: false, isDefinition: true, scopeLine: 1, flags: DIFlagPrototyped, isOptimized: false, unit: !0, variables: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 3, scope: !7)