Skip to content

Commit 9221f3a

Browse files
authored
[RISCV] Support RISCV Atomics ABI attributes (#84597)
This patch adds support for the `atomic_abi` attribute, specifid in https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#tag_riscv_atomic_abi-14-uleb128version. 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 ommited from attribute generation in RISCVTargetStreamer.
1 parent f758bb6 commit 9221f3a

File tree

10 files changed

+314
-2
lines changed

10 files changed

+314
-2
lines changed

lld/ELF/Arch/RISCV.cpp

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,10 +1084,62 @@ static void mergeArch(RISCVISAInfo::OrderedExtensionMap &mergedExts,
10841084
}
10851085
}
10861086

1087+
static void mergeAtomic(DenseMap<unsigned, unsigned>::iterator it,
1088+
const InputSectionBase *oldSection,
1089+
const InputSectionBase *newSection, unsigned int oldTag,
1090+
unsigned int newTag) {
1091+
using RISCVAttrs::RISCVAtomicAbiTag::AtomicABI;
1092+
// Same tags stay the same, and UNKNOWN is compatible with anything
1093+
if (oldTag == newTag || newTag == AtomicABI::UNKNOWN)
1094+
return;
1095+
1096+
switch (oldTag) {
1097+
case AtomicABI::UNKNOWN:
1098+
it->getSecond() = newTag;
1099+
return;
1100+
case AtomicABI::A6C:
1101+
switch (newTag) {
1102+
case AtomicABI::A6S:
1103+
it->getSecond() = AtomicABI::A6C;
1104+
return;
1105+
case AtomicABI::A7:
1106+
error(toString(oldSection) + " has atomic_abi=" + Twine(oldTag) +
1107+
" but " + toString(newSection) +
1108+
" has atomic_abi=" + Twine(newTag));
1109+
return;
1110+
};
1111+
1112+
case AtomicABI::A6S:
1113+
switch (newTag) {
1114+
case AtomicABI::A6C:
1115+
it->getSecond() = AtomicABI::A6C;
1116+
return;
1117+
case AtomicABI::A7:
1118+
it->getSecond() = AtomicABI::A7;
1119+
return;
1120+
};
1121+
1122+
case AtomicABI::A7:
1123+
switch (newTag) {
1124+
case AtomicABI::A6S:
1125+
it->getSecond() = AtomicABI::A7;
1126+
return;
1127+
case AtomicABI::A6C:
1128+
error(toString(oldSection) + " has atomic_abi=" + Twine(oldTag) +
1129+
" but " + toString(newSection) +
1130+
" has atomic_abi=" + Twine(newTag));
1131+
return;
1132+
};
1133+
default:
1134+
llvm_unreachable("unknown AtomicABI");
1135+
};
1136+
}
1137+
10871138
static RISCVAttributesSection *
10881139
mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
10891140
RISCVISAInfo::OrderedExtensionMap exts;
10901141
const InputSectionBase *firstStackAlign = nullptr;
1142+
const InputSectionBase *firstAtomicAbi = nullptr;
10911143
unsigned firstStackAlignValue = 0, xlen = 0;
10921144
bool hasArch = false;
10931145

@@ -1134,6 +1186,17 @@ mergeAttributesSection(const SmallVector<InputSectionBase *, 0> &sections) {
11341186
case RISCVAttrs::PRIV_SPEC_MINOR:
11351187
case RISCVAttrs::PRIV_SPEC_REVISION:
11361188
break;
1189+
1190+
case llvm::RISCVAttrs::AttrType::ATOMIC_ABI:
1191+
if (auto i = parser.getAttributeValue(tag.attr)) {
1192+
auto r = merged.intAttr.try_emplace(tag.attr, *i);
1193+
if (r.second) {
1194+
firstAtomicAbi = sec;
1195+
} else {
1196+
mergeAtomic(r.first, firstAtomicAbi, sec, r.first->getSecond(), *i);
1197+
}
1198+
}
1199+
continue;
11371200
}
11381201

11391202
// Fallback for deprecated priv_spec* and other unknown attributes: retain

lld/test/ELF/riscv-attributes.s

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,39 @@
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+
## merging atomic_abi values for 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_A6C.o:(.riscv.attributes) has atomic_abi=1 but atomic_abi_A7.o:(.riscv.attributes) has atomic_abi=3
52+
53+
54+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_A6S.s -o atomic_abi_A6S.o
55+
# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A6C.o -o atomic_abi_A6C_A6S
56+
# RUN: llvm-readobj -A atomic_abi_A6C_A6S | FileCheck %s --check-prefix=A6C_A6S
57+
58+
# RUN: ld.lld atomic_abi_A6S.o atomic_abi_A7.o -o atomic_abi_A6S_A7
59+
# RUN: llvm-readobj -A atomic_abi_A6S_A7 | FileCheck %s --check-prefix=A6S_A7
60+
61+
# RUN: llvm-mc -filetype=obj -triple=riscv64 atomic_abi_unknown.s -o atomic_abi_unknown.o
62+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6C.o -o atomic_abi_A6C_unknown
63+
# RUN: llvm-readobj -A atomic_abi_A6C_unknown | FileCheck %s --check-prefixes=UNKNOWN_A6C
64+
65+
# RUN: ld.lld atomic_abi_unknown.o diff_stack_align.o -o atomic_abi_none_unknown
66+
# RUN: llvm-readobj -A atomic_abi_none_unknown | FileCheck %s --check-prefixes=UNKNOWN_NONE
67+
68+
# RUN: ld.lld diff_stack_align.o atomic_abi_A6C.o -o atomic_abi_A6C_none
69+
# RUN: llvm-readobj -A atomic_abi_A6C_none | FileCheck %s --check-prefixes=NONE_A6C
70+
71+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A6S.o -o atomic_abi_A6S_unknown
72+
# RUN: llvm-readobj -A atomic_abi_A6S_unknown | FileCheck %s --check-prefix=UNKNOWN_A6S
73+
74+
# RUN: ld.lld atomic_abi_unknown.o atomic_abi_A7.o -o atomic_abi_A7_unknown
75+
# RUN: llvm-readobj -A atomic_abi_A7_unknown | FileCheck %s --check-prefix=UNKNOWN_A7
76+
77+
# RUN: ld.lld diff_stack_align.o atomic_abi_A7.o -o atomic_abi_A7_none
78+
# RUN: llvm-readobj -A atomic_abi_A7_none | FileCheck %s --check-prefix=NONE_A7
79+
4780
## The deprecated priv_spec is not handled as GNU ld does.
4881
## Differing priv_spec attributes lead to an absent attribute.
4982
# RUN: llvm-mc -filetype=obj -triple=riscv64 diff_priv_spec.s -o diff_priv_spec.o
@@ -286,6 +319,175 @@
286319
.attribute priv_spec, 3
287320
.attribute priv_spec_minor, 3
288321

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

llvm/include/llvm/Support/RISCVAttributeParser.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ class RISCVAttributeParser : public ELFAttributeParser {
2424

2525
Error unalignedAccess(unsigned tag);
2626
Error stackAlign(unsigned tag);
27+
Error atomicAbi(unsigned tag);
2728

2829
public:
2930
RISCVAttributeParser(ScopedPrinter *sw)

llvm/include/llvm/Support/RISCVAttributes.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,21 @@ enum AttrType : unsigned {
3232
PRIV_SPEC = 8,
3333
PRIV_SPEC_MINOR = 10,
3434
PRIV_SPEC_REVISION = 12,
35+
ATOMIC_ABI = 14,
3536
};
3637

38+
namespace RISCVAtomicAbiTag {
39+
enum AtomicABI : unsigned {
40+
// Values for Tag_RISCV_atomic_abi
41+
// Defined at
42+
// https://github.com/riscv-non-isa/riscv-elf-psabi-doc/blob/master/riscv-elf.adoc#tag_riscv_atomic_abi-14-uleb128version
43+
UNKNOWN = 0,
44+
A6C = 1,
45+
A6S = 2,
46+
A7 = 3,
47+
};
48+
} // namespace RISCVAtomicAbiTag
49+
3750
enum { NOT_ALLOWED = 0, ALLOWED = 1 };
3851

3952
} // namespace RISCVAttrs

llvm/lib/Support/RISCVAttributeParser.cpp

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,18 @@ const RISCVAttributeParser::DisplayHandler
3636
{
3737
RISCVAttrs::UNALIGNED_ACCESS,
3838
&RISCVAttributeParser::unalignedAccess,
39-
}};
39+
},
40+
{
41+
RISCVAttrs::ATOMIC_ABI,
42+
&RISCVAttributeParser::atomicAbi,
43+
},
44+
};
45+
46+
Error RISCVAttributeParser::atomicAbi(unsigned Tag) {
47+
uint64_t Value = de.getULEB128(cursor);
48+
printAttribute(Tag, Value, "Atomic ABI is " + utostr(Value));
49+
return Error::success();
50+
}
4051

4152
Error RISCVAttributeParser::unalignedAccess(unsigned tag) {
4253
static const char *strings[] = {"No unaligned access", "Unaligned access"};

llvm/lib/Support/RISCVAttributes.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ static constexpr TagNameItem tagData[] = {
1818
{PRIV_SPEC, "Tag_priv_spec"},
1919
{PRIV_SPEC_MINOR, "Tag_priv_spec_minor"},
2020
{PRIV_SPEC_REVISION, "Tag_priv_spec_revision"},
21+
{ATOMIC_ABI, "Tag_atomic_abi"},
2122
};
2223

2324
constexpr TagNameMap RISCVAttributeTags{tagData};

llvm/lib/Target/RISCV/MCTargetDesc/RISCVTargetStreamer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,13 @@ void RISCVTargetStreamer::emitTargetAttributes(const MCSubtargetInfo &STI,
7575
auto &ISAInfo = *ParseResult;
7676
emitTextAttribute(RISCVAttrs::ARCH, ISAInfo->toString());
7777
}
78+
79+
if (STI.hasFeature(RISCV::FeatureStdExtA)) {
80+
unsigned AtomicABITag = STI.hasFeature(RISCV::FeatureTrailingSeqCstFence)
81+
? RISCVAttrs::RISCVAtomicAbiTag::AtomicABI::A6S
82+
: RISCVAttrs::RISCVAtomicAbiTag::AtomicABI::A6C;
83+
emitAttribute(RISCVAttrs::ATOMIC_ABI, AtomicABITag);
84+
}
7885
}
7986

8087
// This part is for ascii assembly output

llvm/test/CodeGen/RISCV/attributes.ll

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,8 @@
129129
; RUN: llc -mtriple=riscv64 -mattr=+m %s -o - | FileCheck --check-prefixes=CHECK,RV64M %s
130130
; RUN: llc -mtriple=riscv64 -mattr=+zmmul %s -o - | FileCheck --check-prefixes=CHECK,RV64ZMMUL %s
131131
; RUN: llc -mtriple=riscv64 -mattr=+m,+zmmul %s -o - | FileCheck --check-prefixes=CHECK,RV64MZMMUL %s
132-
; RUN: llc -mtriple=riscv64 -mattr=+a %s -o - | FileCheck --check-prefixes=CHECK,RV64A %s
132+
; RUN: llc -mtriple=riscv64 -mattr=+a %s -o - | FileCheck --check-prefixes=CHECK,RV64A,A6C %s
133+
; RUN: llc -mtriple=riscv64 -mattr=+a,+seq-cst-trailing-fence %s -o - | FileCheck --check-prefixes=CHECK,RV64A,A6S %s
133134
; RUN: llc -mtriple=riscv64 -mattr=+f %s -o - | FileCheck --check-prefixes=CHECK,RV64F %s
134135
; RUN: llc -mtriple=riscv64 -mattr=+d %s -o - | FileCheck --check-prefixes=CHECK,RV64D %s
135136
; RUN: llc -mtriple=riscv64 -mattr=+c %s -o - | FileCheck --check-prefixes=CHECK,RV64C %s
@@ -516,3 +517,10 @@ define i32 @addi(i32 %a) {
516517
%1 = add i32 %a, 1
517518
ret i32 %1
518519
}
520+
521+
define i8 @atomic_load_i8_seq_cst(ptr %a) nounwind {
522+
%1 = load atomic i8, ptr %a seq_cst, align 1
523+
ret i8 %1
524+
; A6S: .attribute 14, 2
525+
; A6C: .attribute 14, 1
526+
}

llvm/test/MC/RISCV/attribute.s

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,3 +24,6 @@
2424

2525
.attribute priv_spec_revision, 0
2626
# CHECK: attribute 12, 0
27+
28+
.attribute atomic_abi, 0
29+
# CHECK: attribute 14, 0

0 commit comments

Comments
 (0)