Skip to content

Commit 526dbc1

Browse files
authored
[lld] Support merging RISC-V Atomics ABI attributes (#97347)
This patch adds support for merging the atomic_abi attribute, specified in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#tag_riscv_atomic_abi-14-uleb128version, to LLD. The atomics_abi tag merging is conducted as follows: UNKNOWN is safe to merge with all other values. A6C is compatible with A6S, and results in the A6C ABI. A6C is incompatible with A7, and results in an error. A6S and A7 are compatible, and merging results in the A7 ABI. Note: the A7 is not yet supported in either LLVM or in any current hardware, and is therefore omitted from attribute generation in RISCVTargetStreamer. LLD support was split from #90266
1 parent acaa4c8 commit 526dbc1

File tree

2 files changed

+305
-1
lines changed

2 files changed

+305
-1
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 93 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1084,10 +1084,94 @@ static void mergeArch(RISCVISAUtils::OrderedExtensionMap &mergedExts,
10841084
}
10851085
}
10861086

1087+
static void mergeAtomic(DenseMap<unsigned, unsigned>::iterator it,
1088+
const InputSectionBase *oldSection,
1089+
const InputSectionBase *newSection,
1090+
RISCVAttrs::RISCVAtomicAbiTag oldTag,
1091+
RISCVAttrs::RISCVAtomicAbiTag newTag) {
1092+
using RISCVAttrs::RISCVAtomicAbiTag;
1093+
// Same tags stay the same, and UNKNOWN is compatible with anything
1094+
if (oldTag == newTag || newTag == RISCVAtomicAbiTag::UNKNOWN)
1095+
return;
1096+
1097+
auto reportAbiError = [&]() {
1098+
errorOrWarn("atomic abi mismatch for " + oldSection->name + "\n>>> " +
1099+
toString(oldSection) +
1100+
": atomic_abi=" + Twine(static_cast<unsigned>(oldTag)) +
1101+
"\n>>> " + toString(newSection) +
1102+
": atomic_abi=" + Twine(static_cast<unsigned>(newTag)));
1103+
};
1104+
1105+
auto reportUnknownAbiError = [](const InputSectionBase *section,
1106+
RISCVAtomicAbiTag tag) {
1107+
switch (tag) {
1108+
case RISCVAtomicAbiTag::UNKNOWN:
1109+
case RISCVAtomicAbiTag::A6C:
1110+
case RISCVAtomicAbiTag::A6S:
1111+
case RISCVAtomicAbiTag::A7:
1112+
return;
1113+
};
1114+
errorOrWarn("unknown atomic abi for " + section->name + "\n>>> " +
1115+
toString(section) +
1116+
": atomic_abi=" + Twine(static_cast<unsigned>(tag)));
1117+
};
1118+
switch (oldTag) {
1119+
case RISCVAtomicAbiTag::UNKNOWN:
1120+
it->getSecond() = static_cast<unsigned>(newTag);
1121+
return;
1122+
case RISCVAtomicAbiTag::A6C:
1123+
switch (newTag) {
1124+
case RISCVAtomicAbiTag::A6S:
1125+
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A6C);
1126+
return;
1127+
case RISCVAtomicAbiTag::A7:
1128+
reportAbiError();
1129+
return;
1130+
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
1131+
case RISCVAttrs::RISCVAtomicAbiTag::A6C:
1132+
return;
1133+
};
1134+
1135+
case RISCVAtomicAbiTag::A6S:
1136+
switch (newTag) {
1137+
case RISCVAtomicAbiTag::A6C:
1138+
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A6C);
1139+
return;
1140+
case RISCVAtomicAbiTag::A7:
1141+
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A7);
1142+
return;
1143+
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
1144+
case RISCVAttrs::RISCVAtomicAbiTag::A6S:
1145+
return;
1146+
};
1147+
1148+
case RISCVAtomicAbiTag::A7:
1149+
switch (newTag) {
1150+
case RISCVAtomicAbiTag::A6S:
1151+
it->getSecond() = static_cast<unsigned>(RISCVAtomicAbiTag::A7);
1152+
return;
1153+
case RISCVAtomicAbiTag::A6C:
1154+
reportAbiError();
1155+
return;
1156+
case RISCVAttrs::RISCVAtomicAbiTag::UNKNOWN:
1157+
case RISCVAttrs::RISCVAtomicAbiTag::A7:
1158+
return;
1159+
};
1160+
};
1161+
1162+
// If we get here, then we have an invalid tag, so report it.
1163+
// Putting these checks at the end allows us to only do these checks when we
1164+
// need to, since this is expected to be a rare occurrence.
1165+
reportUnknownAbiError(oldSection, oldTag);
1166+
reportUnknownAbiError(newSection, newTag);
1167+
}
1168+
10871169
static RISCVAttributesSection *
10881170
mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
1171+
using RISCVAttrs::RISCVAtomicAbiTag;
10891172
RISCVISAUtils::OrderedExtensionMap exts;
10901173
const InputSectionBase *firstStackAlign = nullptr;
1174+
const InputSectionBase *firstAtomicAbi = nullptr;
10911175
unsigned firstStackAlignValue = 0, xlen = 0;
10921176
bool hasArch = false;
10931177

@@ -1136,7 +1220,15 @@ mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
11361220
break;
11371221

11381222
case RISCVAttrs::AttrType::ATOMIC_ABI:
1139-
// TODO: Handle ATOMIC_ABI tag merging
1223+
if (auto i = parser.getAttributeValue(tag.attr)) {
1224+
auto r = merged.intAttr.try_emplace(tag.attr, *i);
1225+
if (r.second)
1226+
firstAtomicAbi = sec;
1227+
else
1228+
mergeAtomic(r.first, firstAtomicAbi, sec,
1229+
static_cast<RISCVAtomicAbiTag>(r.first->getSecond()),
1230+
static_cast<RISCVAtomicAbiTag>(*i));
1231+
}
11401232
continue;
11411233
}
11421234

lld/test/ELF/riscv-attributes.s

Lines changed: 212 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,46 @@
4444
# RUN: not ld.lld a.o b.o c.o diff_stack_align.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=STACK_ALIGN --implicit-check-not=error:
4545
# STACK_ALIGN: error: diff_stack_align.o:(.riscv.attributes) has stack_align=32 but a.o:(.riscv.attributes) has stack_align=16
4646

47+
## RISC-V tag merging for atomic_abi values A6C and A7 lead to an error.
48+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A6C.s -o atomic_abi_A6C.o
49+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A7.s -o atomic_abi_A7.o
50+
# RUN: not ld.lld atomic_abi_A6C.o atomic_abi_A7.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ATOMIC_ABI_ERROR --implicit-check-not=error:
51+
# ATOMIC_ABI_ERROR: error: atomic abi mismatch for .riscv.attributes
52+
# ATOMIC_ABI_ERROR-NEXT: >>> atomic_abi_A6C.o:(.riscv.attributes): atomic_abi=1
53+
# ATOMIC_ABI_ERROR-NEXT: >>> atomic_abi_A7.o:(.riscv.attributes): atomic_abi=3
54+
55+
## RISC-V tag merging for atomic_abi values A6C and invalid lead to an error.
56+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_invalid.s -o atomic_abi_invalid.o
57+
# RUN: not ld.lld atomic_abi_A6C.o atomic_abi_invalid.o -o /dev/null 2>&1 | FileCheck %s --check-prefix=ATOMIC_ABI_INVALID --implicit-check-not=error:
58+
# ATOMIC_ABI_INVALID: error: unknown atomic abi for .riscv.attributes
59+
# ATOMIC_ABI_INVALID-NEXT: >>> atomic_abi_invalid.o:(.riscv.attributes): atomic_abi=42
60+
61+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A6S.s -o atomic_abi_A6S.o
62+
# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A6C.o -o atomic_abi_A6C_A6S
63+
# RUN: llvm-readobj -A atomic_abi_A6C_A6S | FileCheck %s --check-prefix=A6C_A6S
64+
65+
# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A7.o -o atomic_abi_A6S_A7
66+
# RUN: llvm-readobj -A atomic_abi_A6S_A7 | FileCheck %s --check-prefix=A6S_A7
67+
68+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_unknown.s -o atomic_abi_unknown.o
69+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6C.o -o atomic_abi_A6C_unknown
70+
# RUN: llvm-readobj -A atomic_abi_A6C_unknown | FileCheck %s --check-prefixes=UNKNOWN_A6C
71+
72+
# RUN: ld.lld atomic_abi_unknown.o diff_stack_align.o -o atomic_abi_none_unknown
73+
# RUN: llvm-readobj -A atomic_abi_none_unknown | FileCheck %s --check-prefixes=UNKNOWN_NONE
74+
75+
# RUN: ld.lld diff_stack_align.o atomic_abi_A6C.o -o atomic_abi_A6C_none
76+
# RUN: llvm-readobj -A atomic_abi_A6C_none | FileCheck %s --check-prefixes=NONE_A6C
77+
78+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6S.o -o atomic_abi_A6S_unknown
79+
# RUN: llvm-readobj -A atomic_abi_A6S_unknown | FileCheck %s --check-prefix=UNKNOWN_A6S
80+
81+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A7.o -o atomic_abi_A7_unknown
82+
# RUN: llvm-readobj -A atomic_abi_A7_unknown | FileCheck %s --check-prefix=UNKNOWN_A7
83+
84+
# RUN: ld.lld diff_stack_align.o atomic_abi_A7.o -o atomic_abi_A7_none
85+
# RUN: llvm-readobj -A atomic_abi_A7_none | FileCheck %s --check-prefix=NONE_A7
86+
4787
## The deprecated priv_spec is not handled as GNU ld does.
4888
## Differing priv_spec attributes lead to an absent attribute.
4989
# RUN: llvm-mc -filetype=obj -triple=riscv64 diff_priv_spec.s -o diff_priv_spec.o
@@ -286,6 +326,178 @@
286326
.attribute priv_spec, 3
287327
.attribute priv_spec_minor, 3
288328

329+
#--- atomic_abi_unknown.s
330+
.attribute atomic_abi, 0
331+
332+
#--- atomic_abi_A6C.s
333+
.attribute atomic_abi, 1
334+
335+
#--- atomic_abi_A6S.s
336+
.attribute atomic_abi, 2
337+
338+
#--- atomic_abi_A7.s
339+
.attribute atomic_abi, 3
340+
341+
#--- atomic_abi_invalid.s
342+
.attribute atomic_abi, 42
343+
344+
# UNKNOWN_NONE: BuildAttributes {
345+
# UNKNOWN_NONE-NEXT: FormatVersion: 0x41
346+
# UNKNOWN_NONE-NEXT: Section 1 {
347+
# UNKNOWN_NONE-NEXT: SectionLength: 17
348+
# UNKNOWN_NONE-NEXT: Vendor: riscv
349+
# UNKNOWN_NONE-NEXT: Tag: Tag_File (0x1)
350+
# UNKNOWN_NONE-NEXT: Size: 7
351+
# UNKNOWN_NONE-NEXT: FileAttributes {
352+
# UNKNOWN_NONE-NEXT: Attribute {
353+
# UNKNOWN_NONE-NEXT: Tag: 4
354+
# UNKNOWN_NONE-NEXT: Value: 32
355+
# UNKNOWN_NONE-NEXT: TagName: stack_align
356+
# UNKNOWN_NONE-NEXT: Description: Stack alignment is 32-bytes
357+
# UNKNOWN_NONE-NEXT: }
358+
# UNKNOWN_NONE-NEXT: }
359+
# UNKNOWN_NONE-NEXT: }
360+
# UNKNOWN_NONE-NEXT: }
361+
362+
# NONE_A6C: BuildAttributes {
363+
# NONE_A6C-NEXT: FormatVersion: 0x41
364+
# NONE_A6C-NEXT: Section 1 {
365+
# NONE_A6C-NEXT: SectionLength: 19
366+
# NONE_A6C-NEXT: Vendor: riscv
367+
# NONE_A6C-NEXT: Tag: Tag_File (0x1)
368+
# NONE_A6C-NEXT: Size: 9
369+
# NONE_A6C-NEXT: FileAttributes {
370+
# NONE_A6C-NEXT: Attribute {
371+
# NONE_A6C-NEXT: Tag: 14
372+
# NONE_A6C-NEXT: Value: 1
373+
# NONE_A6C-NEXT: TagName: atomic_abi
374+
# NONE_A6C-NEXT: Description: Atomic ABI is 1
375+
# NONE_A6C-NEXT: }
376+
# NONE_A6C-NEXT: Attribute {
377+
# NONE_A6C-NEXT: Tag: 4
378+
# NONE_A6C-NEXT: Value: 32
379+
# NONE_A6C-NEXT: TagName: stack_align
380+
# NONE_A6C-NEXT: Description: Stack alignment is 32-bytes
381+
# NONE_A6C-NEXT: }
382+
# NONE_A6C-NEXT: }
383+
# NONE_A6C-NEXT: }
384+
# NONE_A6C-NEXT: }
385+
386+
# UNKNOWN_A6C: BuildAttributes {
387+
# UNKNOWN_A6C-NEXT: FormatVersion: 0x41
388+
# UNKNOWN_A6C-NEXT: Section 1 {
389+
# UNKNOWN_A6C-NEXT: SectionLength: 17
390+
# UNKNOWN_A6C-NEXT: Vendor: riscv
391+
# UNKNOWN_A6C-NEXT: Tag: Tag_File (0x1)
392+
# UNKNOWN_A6C-NEXT: Size: 7
393+
# UNKNOWN_A6C-NEXT: FileAttributes {
394+
# UNKNOWN_A6C-NEXT: Attribute {
395+
# UNKNOWN_A6C-NEXT: Tag: 14
396+
# UNKNOWN_A6C-NEXT: Value: 1
397+
# UNKNOWN_A6C-NEXT: TagName: atomic_abi
398+
# UNKNOWN_A6C-NEXT: Description: Atomic ABI is 1
399+
# UNKNOWN_A6C-NEXT: }
400+
# UNKNOWN_A6C-NEXT: }
401+
# UNKNOWN_A6C-NEXT: }
402+
# UNKNOWN_A6C-NEXT: }
403+
404+
# UNKNOWN_A6S: BuildAttributes {
405+
# UNKNOWN_A6S-NEXT: FormatVersion: 0x41
406+
# UNKNOWN_A6S-NEXT: Section 1 {
407+
# UNKNOWN_A6S-NEXT: SectionLength:
408+
# UNKNOWN_A6S-NEXT: Vendor: riscv
409+
# UNKNOWN_A6S-NEXT: Tag: Tag_File (0x1)
410+
# UNKNOWN_A6S-NEXT: Size: 7
411+
# UNKNOWN_A6S-NEXT: FileAttributes {
412+
# UNKNOWN_A6S-NEXT: Attribute {
413+
# UNKNOWN_A6S-NEXT: Tag: 14
414+
# UNKNOWN_A6S-NEXT: Value: 2
415+
# UNKNOWN_A6S-NEXT: TagName: atomic_abi
416+
# UNKNOWN_A6S-NEXT: Description: Atomic ABI is 2
417+
# UNKNOWN_A6S-NEXT: }
418+
# UNKNOWN_A6S-NEXT: }
419+
# UNKNOWN_A6S-NEXT: }
420+
# UNKNOWN_A6S-NEXT: }
421+
422+
# NONE_A7: BuildAttributes {
423+
# NONE_A7-NEXT: FormatVersion: 0x41
424+
# NONE_A7-NEXT: Section 1 {
425+
# NONE_A7-NEXT: SectionLength: 19
426+
# NONE_A7-NEXT: Vendor: riscv
427+
# NONE_A7-NEXT: Tag: Tag_File (0x1)
428+
# NONE_A7-NEXT: Size: 9
429+
# NONE_A7-NEXT: FileAttributes {
430+
# NONE_A7-NEXT: Attribute {
431+
# NONE_A7-NEXT: Tag: 14
432+
# NONE_A7-NEXT: Value: 3
433+
# NONE_A7-NEXT: TagName: atomic_abi
434+
# NONE_A7-NEXT: Description: Atomic ABI is 3
435+
# NONE_A7-NEXT: }
436+
# NONE_A7-NEXT: Attribute {
437+
# NONE_A7-NEXT: Tag: 4
438+
# NONE_A7-NEXT: Value: 32
439+
# NONE_A7-NEXT: TagName: stack_align
440+
# NONE_A7-NEXT: Description: Stack alignment is 32-bytes
441+
# NONE_A7-NEXT: }
442+
# NONE_A7-NEXT: }
443+
# NONE_A7-NEXT: }
444+
# NONE_A7-NEXT: }
445+
446+
447+
# UNKNOWN_A7: BuildAttributes {
448+
# UNKNOWN_A7-NEXT: FormatVersion: 0x41
449+
# UNKNOWN_A7-NEXT: Section 1 {
450+
# UNKNOWN_A7-NEXT: SectionLength: 17
451+
# UNKNOWN_A7-NEXT: Vendor: riscv
452+
# UNKNOWN_A7-NEXT: Tag: Tag_File (0x1)
453+
# UNKNOWN_A7-NEXT: Size: 7
454+
# UNKNOWN_A7-NEXT: FileAttributes {
455+
# UNKNOWN_A7-NEXT: Attribute {
456+
# UNKNOWN_A7-NEXT: Tag: 14
457+
# UNKNOWN_A7-NEXT: Value: 3
458+
# UNKNOWN_A7-NEXT: TagName: atomic_abi
459+
# UNKNOWN_A7-NEXT: Description: Atomic ABI is 3
460+
# UNKNOWN_A7-NEXT: }
461+
# UNKNOWN_A7-NEXT: }
462+
# UNKNOWN_A7-NEXT: }
463+
# UNKNOWN_A7-NEXT: }
464+
465+
# A6C_A6S: BuildAttributes {
466+
# A6C_A6S-NEXT: FormatVersion: 0x41
467+
# A6C_A6S-NEXT: Section 1 {
468+
# A6C_A6S-NEXT: SectionLength: 17
469+
# A6C_A6S-NEXT: Vendor: riscv
470+
# A6C_A6S-NEXT: Tag: Tag_File (0x1)
471+
# A6C_A6S-NEXT: Size: 7
472+
# A6C_A6S-NEXT: FileAttributes {
473+
# A6C_A6S-NEXT: Attribute {
474+
# A6C_A6S-NEXT: Tag: 14
475+
# A6C_A6S-NEXT: Value: 1
476+
# A6C_A6S-NEXT: TagName: atomic_abi
477+
# A6C_A6S-NEXT: Description: Atomic ABI is 1
478+
# A6C_A6S-NEXT: }
479+
# A6C_A6S-NEXT: }
480+
# A6C_A6S-NEXT: }
481+
# A6C_A6S-NEXT: }
482+
483+
# A6S_A7: BuildAttributes {
484+
# A6S_A7-NEXT: FormatVersion: 0x41
485+
# A6S_A7-NEXT: Section 1 {
486+
# A6S_A7-NEXT: SectionLength: 17
487+
# A6S_A7-NEXT: Vendor: riscv
488+
# A6S_A7-NEXT: Tag: Tag_File (0x1)
489+
# A6S_A7-NEXT: Size: 7
490+
# A6S_A7-NEXT: FileAttributes {
491+
# A6S_A7-NEXT: Attribute {
492+
# A6S_A7-NEXT: Tag: 14
493+
# A6S_A7-NEXT: Value: 3
494+
# A6S_A7-NEXT: TagName: atomic_abi
495+
# A6S_A7-NEXT: Description: Atomic ABI is 3
496+
# A6S_A7-NEXT: }
497+
# A6S_A7-NEXT: }
498+
# A6S_A7-NEXT: }
499+
# A6S_A7-NEXT: }
500+
289501
#--- unknown13.s
290502
.attribute 13, "0"
291503
#--- unknown13a.s

0 commit comments

Comments
 (0)