summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/MC/MCObjectStreamer.h4
-rw-r--r--llvm/lib/MC/MCObjectStreamer.cpp11
-rw-r--r--llvm/test/CodeGen/RISCV/fixups-diff.ll46
3 files changed, 56 insertions, 5 deletions
diff --git a/llvm/include/llvm/MC/MCObjectStreamer.h b/llvm/include/llvm/MC/MCObjectStreamer.h
index 035206dce93..c9e577b7e29 100644
--- a/llvm/include/llvm/MC/MCObjectStreamer.h
+++ b/llvm/include/llvm/MC/MCObjectStreamer.h
@@ -179,7 +179,9 @@ public:
///
/// 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,
diff --git a/llvm/lib/MC/MCObjectStreamer.cpp b/llvm/lib/MC/MCObjectStreamer.cpp
index 4b6dad5ce8f..102aa4d4513 100644
--- a/llvm/lib/MC/MCObjectStreamer.cpp
+++ b/llvm/lib/MC/MCObjectStreamer.cpp
@@ -61,9 +61,12 @@ void MCObjectStreamer::flushPendingLabels(MCFragment *F, uint64_t FOffset) {
// 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<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
- const MCSymbol *Lo) {
+static Optional<uint64_t>
+absoluteSymbolDiff(MCAssembler &Asm, const MCSymbol *Hi, const MCSymbol *Lo) {
assert(Hi && Lo);
+ if (Asm.getBackendPtr()->requiresDiffExpressionRelocations())
+ return None;
+
if (!Hi->getFragment() || Hi->getFragment() != Lo->getFragment() ||
Hi->isVariable() || Lo->isVariable())
return None;
@@ -74,7 +77,7 @@ static Optional<uint64_t> absoluteSymbolDiff(const MCSymbol *Hi,
void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
const MCSymbol *Lo,
unsigned Size) {
- if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) {
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
EmitIntValue(*Diff, Size);
return;
}
@@ -83,7 +86,7 @@ void MCObjectStreamer::emitAbsoluteSymbolDiff(const MCSymbol *Hi,
void MCObjectStreamer::emitAbsoluteSymbolDiffAsULEB128(const MCSymbol *Hi,
const MCSymbol *Lo) {
- if (Optional<uint64_t> Diff = absoluteSymbolDiff(Hi, Lo)) {
+ if (Optional<uint64_t> Diff = absoluteSymbolDiff(getAssembler(), Hi, Lo)) {
EmitULEB128IntValue(*Diff);
return;
}
diff --git a/llvm/test/CodeGen/RISCV/fixups-diff.ll b/llvm/test/CodeGen/RISCV/fixups-diff.ll
new file mode 100644
index 00000000000..08dca52a345
--- /dev/null
+++ b/llvm/test/CodeGen/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)
+!8 = !DISubroutineType(types: !9)
+!9 = !{!10}
+!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
+!11 = !DILocation(line: 2, column: 3, scope: !7)
OpenPOWER on IntegriCloud