14 changes: 4 additions & 10 deletions lld/ELF/SyntheticSections.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3205,10 +3205,10 @@ template <class ELFT> DebugNamesSection<ELFT>::DebugNamesSection() {
template <class ELFT>
template <class RelTy>
void DebugNamesSection<ELFT>::getNameRelocs(
InputSection *sec, Relocs<RelTy> rels,
DenseMap<uint32_t, uint32_t> &relocs) {
const InputFile &file, DenseMap<uint32_t, uint32_t> &relocs,
Relocs<RelTy> rels) {
for (const RelTy &rel : rels) {
Symbol &sym = sec->file->getRelocTargetSym(rel);
Symbol &sym = file.getRelocTargetSym(rel);
relocs[rel.r_offset] = sym.getVA(getAddend<ELFT>(rel));
}
}
Expand All @@ -3218,13 +3218,7 @@ template <class ELFT> void DebugNamesSection<ELFT>::finalizeContents() {
auto relocs = std::make_unique<DenseMap<uint32_t, uint32_t>[]>(numChunks);
parallelFor(0, numChunks, [&](size_t i) {
InputSection *sec = inputSections[i];
auto rels = sec->template relsOrRelas<ELFT>();
if (rels.areRelocsCrel())
getNameRelocs(sec, rels.crels, relocs.get()[i]);
else if (rels.areRelocsRel())
getNameRelocs(sec, rels.rels, relocs.get()[i]);
else
getNameRelocs(sec, rels.relas, relocs.get()[i]);
invokeOnRelocs(*sec, getNameRelocs, *sec->file, relocs.get()[i]);

// Relocate CU offsets with .debug_info + X relocations.
OutputChunk &chunk = chunks.get()[i];
Expand Down
5 changes: 3 additions & 2 deletions lld/ELF/SyntheticSections.h
Original file line number Diff line number Diff line change
Expand Up @@ -916,8 +916,9 @@ class DebugNamesSection final : public DebugNamesBaseSection {
void writeTo(uint8_t *buf) override;

template <class RelTy>
void getNameRelocs(InputSection *sec, Relocs<RelTy> rels,
llvm::DenseMap<uint32_t, uint32_t> &relocs);
void getNameRelocs(const InputFile &file,
llvm::DenseMap<uint32_t, uint32_t> &relocs,
Relocs<RelTy> rels);

private:
static void readOffsets(InputChunk &inputChunk, OutputChunk &chunk,
Expand Down
15 changes: 0 additions & 15 deletions lld/test/ELF/linkerscript/header-phdr.test

This file was deleted.

2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript/invalid.test
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

# RUN: echo foobar > %t1
# RUN: not ld.lld %t1 no-such-file 2>&1 | FileCheck -check-prefix=ERR1 %s
# ERR1: unexpected EOF
# ERR1: error: {{.*}}1:1: unknown directive: foobar
# ERR1: cannot open no-such-file:

# RUN: echo "foo \"bar" > %t2
Expand Down
22 changes: 11 additions & 11 deletions lld/test/ELF/linkerscript/map-file.test
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,17 @@
# RUN: FileCheck -strict-whitespace %s < %t.map

SECTIONS {
. = 0x1000;
. = 0x1000; # tabs
.foo : {
BYTE(0x11)
SHORT(0x1122)
BYTE ( 0x11 )
SHORT (0x1122)
LONG(0x11223344)
QUAD(0x1122334455667788)
PROVIDE_HIDDEN(sym4 = .);
. += 0x1000;
*(.foo.1)
PROVIDE(unused1 = 0xff);
HIDDEN(sym6 = .);
HIDDEN( sym6 = . );
. += 0x123 *
(1 + 1);
foo = .;
Expand All @@ -34,20 +34,20 @@ SECTIONS {
# CHECK-NEXT: 0 0 1000 1 . = 0x1000
# CHECK-NEXT: 1000 1000 125d 1 .foo
# CHECK-NEXT: 1000 1000 1 1 BYTE ( 0x11 )
# CHECK-NEXT: 1001 1001 2 1 SHORT ( 0x1122 )
# CHECK-NEXT: 1003 1003 4 1 LONG ( 0x11223344 )
# CHECK-NEXT: 1007 1007 8 1 QUAD ( 0x1122334455667788 )
# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN ( sym4 = . )
# CHECK-NEXT: 1001 1001 2 1 SHORT (0x1122)
# CHECK-NEXT: 1003 1003 4 1 LONG(0x11223344)
# CHECK-NEXT: 1007 1007 8 1 QUAD(0x1122334455667788)
# CHECK-NEXT: 100f 100f 0 1 PROVIDE_HIDDEN(sym4 = .)
# CHECK-NEXT: 100f 100f 1000 1 . += 0x1000
# CHECK-NEXT: 200f 200f 8 1 {{.*}}{{/|\\}}map-file.test.tmp.o:(.foo.1)
# CHECK-NEXT: 2017 2017 0 1 HIDDEN ( sym6 = . )
# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * ( 1 + 1 )
# CHECK-NEXT: 2017 2017 0 1 HIDDEN( sym6 = . )
# CHECK-NEXT: 2017 2017 246 1 . += 0x123 * (1 + 1)
# CHECK-NEXT: 225d 225d 0 1 foo = .
# CHECK-NEXT: 225d 225d 0 1 bar = 0x42 - 0x26
# CHECK-NEXT: 225d 225d 0 1 sym1 = .
# CHECK-NEXT: 225d 225d 500 1 . += 0x500
# CHECK-NEXT: 275d 275d 0 1 sym2 = .
# CHECK-NEXT: 275d 275d 0 1 PROVIDE ( sym3 = 42 )
# CHECK-NEXT: 275d 275d 0 1 PROVIDE(sym3 = 42)
# CHECK-NEXT: 2760 2760 10 4 .text
# CHECK-NEXT: 2760 2760 10 4 {{.*}}{{/|\\}}map-file.test.tmp.o:(.text)
# CHECK-NEXT: 0 0 8 1 .comment
Expand Down
2 changes: 1 addition & 1 deletion lld/test/ELF/linkerscript/map-file2.test
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ SECTIONS {
# CHECK-NEXT: 1010 3000 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ccc)
# CHECK-NEXT: 1018 3008 100 1 . += 0x100
# CHECK-NEXT: 1118 3108 109 1 .ddd
# CHECK-NEXT: 1118 3108 1 1 BYTE ( 0x11 )
# CHECK-NEXT: 1118 3108 1 1 BYTE(0x11)
# CHECK-NEXT: 1119 3109 100 1 . += 0x100
# CHECK-NEXT: 1219 3209 8 1 {{.*}}{{/|\\}}map-file2.test.tmp.o:(.ddd)
# CHECK-NEXT: 1228 3218 34 8 .eh_frame
Expand Down
4 changes: 4 additions & 0 deletions lld/test/ELF/linkerscript/memory-err.s
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,10 @@
# RUN: not ld.lld -T %t.script %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=NOT_CONVERGE %s
# NOT_CONVERGE: error: address (0x14) of section '.text' does not converge

# RUN: echo 'MEMORY { ram : ORIGIN = symbol, LENGTH = 4094 ' > %t.script
# RUN: not ld.lld -T %t.script %t.o -o /dev/null 2>&1 | FileCheck --check-prefix=UNCLOSED %s
# UNCLOSED: error: {{.*}}:1: unexpected EOF

nop

.data
Expand Down
8 changes: 8 additions & 0 deletions lld/test/ELF/linkerscript/overlay.test
Original file line number Diff line number Diff line change
Expand Up @@ -92,3 +92,11 @@ SECTIONS {
.out.aaa { *(.aaa) } > AX AT>FLASH
}
}

#--- unclosed.lds
SECTIONS {
OVERLAY 0x1000 : AT ( 0x2000 ) {

# RUN: not ld.lld a.o -T unclosed.lds 2>&1 | FileCheck %s --check-prefix=UNCLOSED
# UNCLOSED: error: unclosed.lds:1: unexpected EOF
# UNCLOSED-NOT: {{.}}
15 changes: 0 additions & 15 deletions lld/test/ELF/linkerscript/phdr-check.s

This file was deleted.

225 changes: 96 additions & 129 deletions lld/test/ELF/linkerscript/phdrs.s
Original file line number Diff line number Diff line change
@@ -1,143 +1,110 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
# RUN: SECTIONS { \
# RUN: . = 0x10000200; \
# RUN: .text : {*(.text*)} :all \
# RUN: .foo : {*(.foo.*)} :all \
# RUN: .data : {*(.data.*)} :all}" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -l %t1 | FileCheck %s

# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o

#--- 1.lds
PHDRS {all PT_LOAD FILEHDR PHDRS ;}
SECTIONS {
. = 0x10000200;
.text : {*(.text*)} :all
.foo : {*(.foo.*)} :all
.data : {*(.data.*)} :all}

# RUN: ld.lld -o 1 -T 1.lds a.o
# RUN: llvm-readelf -Sl 1 | FileCheck %s
# CHECK: [Nr] Name Type Address Off Size ES Flg Lk Inf Al
# CHECK: [ 1] .text PROGBITS 0000000010000200 000200 000001 00 AX 0 0 4
# CHECK-NEXT: [ 2] .foo PROGBITS 0000000010000201 000201 000008 00 WA 0 0 1

# CHECK: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# CHECK-NEXT: LOAD 0x000000 0x0000000010000000 0x0000000010000000 0x000209 0x000209 RWE 0x1000

#--- 2.lds
## Check that program headers are not written, unless we explicitly tell
## lld to do this.
# RUN: echo "PHDRS {all PT_LOAD;} \
# RUN: SECTIONS { \
# RUN: . = 0x10000200; \
# RUN: /DISCARD/ : {*(.text*)} \
# RUN: .foo : {*(.foo.*)} :all \
# RUN: }" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=NOPHDR %s

PHDRS {all PT_LOAD;}
SECTIONS {
. = 0x10000200;
/DISCARD/ : {*(.text*)}
.foo : {*(.foo.*)} :all
}

# RUN: ld.lld -o 2 -T 2.lds a.o
# RUN: llvm-readelf -l 2 | FileCheck --check-prefix=NOPHDR %s
# NOPHDR: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# NOPHDR-NEXT: LOAD 0x000200 0x0000000010000200 0x0000000010000200 0x000008 0x000008 RW 0x1000

#--- 3.lds
PHDRS {all PT_LOAD FILEHDR PHDRS ;}
SECTIONS {
. = 0x10000200;
.text : {*(.text*)} :all
.foo : {*(.foo.*)}
.data : {*(.data.*)} }

# RUN: ld.lld -o 3 -T 3.lds a.o
# RUN: llvm-readelf -l 3 | FileCheck --check-prefix=DEFHDR %s
# DEFHDR: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# DEFHDR-NEXT: LOAD 0x000000 0x0000000010000000 0x0000000010000000 0x000209 0x000209 RWE 0x1000

#--- at.lds
## Check the AT(expr)
# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;} \
# RUN: SECTIONS { \
# RUN: . = 0x10000200; \
# RUN: .text : {*(.text*)} :all \
# RUN: .foo : {*(.foo.*)} :all \
# RUN: .data : {*(.data.*)} :all}" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=AT %s

# RUN: echo "PHDRS {all PT_LOAD FILEHDR PHDRS ;} \
# RUN: SECTIONS { \
# RUN: . = 0x10000200; \
# RUN: .text : {*(.text*)} :all \
# RUN: .foo : {*(.foo.*)} \
# RUN: .data : {*(.data.*)} }" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-readobj -l %t1 | FileCheck --check-prefix=DEFHDR %s
PHDRS {all PT_LOAD FILEHDR PHDRS AT(0x500 + 0x500) ;}
SECTIONS {
. = 0x10000200;
.text : {*(.text*)} :all
.foo : {*(.foo.*)} :all
.data : {*(.data.*)} :all}

# RUN: ld.lld -o at -T at.lds a.o
# RUN: llvm-readelf -l at | FileCheck --check-prefix=AT %s
# AT: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# AT-NEXT: LOAD 0x000000 0x0000000010000000 0x0000000000000a00 0x000209 0x000209 RWE 0x1000

#--- int.lds
## Check the numetic values for PHDRS.
PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; }
SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.foo* .text*) } : text : foo}

# RUN: ld.lld -o int -T int.lds a.o
# RUN: llvm-readelf -l int | FileCheck --check-prefix=INT-PHDRS %s
# INT-PHDRS: Type Offset VirtAddr PhysAddr FileSiz MemSiz Flg Align
# INT-PHDRS-NEXT: LOAD 0x000000 0x0000000000000000 0x0000000000000000 0x0000b9 0x0000b9 RWE 0x1000
# INT-PHDRS-NEXT: <unknown>: 0x11223344 0x0000b0 0x00000000000000b0 0x00000000000000b0 0x000009 0x000009 RWE 0x4

#--- unspecified.lds
## Check that error is reported when trying to use phdr which is not listed
## inside PHDRS {} block
## TODO: If script doesn't contain PHDRS {} block then default phdr is always
## created and error is not reported.
# RUN: echo "PHDRS { all PT_LOAD; } \
# RUN: SECTIONS { .baz : {*(.foo.*)} :bar }" > %t.script
# RUN: not ld.lld -o /dev/null --script %t.script %t 2>&1 | FileCheck --check-prefix=BADHDR %s

# CHECK: ProgramHeaders [
# CHECK-NEXT: ProgramHeader {
# CHECK-NEXT: Type: PT_LOAD (0x1)
# CHECK-NEXT: Offset: 0x0
# CHECK-NEXT: VirtualAddress: 0x10000000
# CHECK-NEXT: PhysicalAddress: 0x10000000
# CHECK-NEXT: FileSize: 521
# CHECK-NEXT: MemSize: 521
# CHECK-NEXT: Flags [ (0x7)
# CHECK-NEXT: PF_R (0x4)
# CHECK-NEXT: PF_W (0x2)
# CHECK-NEXT: PF_X (0x1)
# CHECK-NEXT: ]

# NOPHDR: ProgramHeaders [
# NOPHDR-NEXT: ProgramHeader {
# NOPHDR-NEXT: Type: PT_LOAD (0x1)
# NOPHDR-NEXT: Offset: 0x200
# NOPHDR-NEXT: VirtualAddress: 0x10000200
# NOPHDR-NEXT: PhysicalAddress: 0x10000200
# NOPHDR-NEXT: FileSize: 8
# NOPHDR-NEXT: MemSize: 8
# NOPHDR-NEXT: Flags [ (0x6)
# NOPHDR-NEXT: PF_R (0x4)
# NOPHDR-NEXT: PF_W (0x2)
# NOPHDR-NEXT: ]
# NOPHDR-NEXT: Alignment: 4096
# NOPHDR-NEXT: }
# NOPHDR-NEXT: ]

# AT: ProgramHeaders [
# AT-NEXT: ProgramHeader {
# AT-NEXT: Type: PT_LOAD (0x1)
# AT-NEXT: Offset: 0x0
# AT-NEXT: VirtualAddress: 0x10000000
# AT-NEXT: PhysicalAddress: 0xA00
# AT-NEXT: FileSize: 521
# AT-NEXT: MemSize: 521
# AT-NEXT: Flags [ (0x7)
# AT-NEXT: PF_R (0x4)
# AT-NEXT: PF_W (0x2)
# AT-NEXT: PF_X (0x1)
# AT-NEXT: ]
PHDRS { all PT_LOAD; }
SECTIONS { .baz : {*(.foo.*)} :bar }

## Check the numetic values for PHDRS.
# RUN: echo "PHDRS {text PT_LOAD FILEHDR PHDRS; foo 0x11223344; } \
# RUN: SECTIONS { . = SIZEOF_HEADERS; .foo : { *(.foo* .text*) } : text : foo}" > %t1.script
# RUN: ld.lld -o %t2 --script %t1.script %t
# RUN: llvm-readobj -l %t2 | FileCheck --check-prefix=INT-PHDRS %s

# INT-PHDRS: ProgramHeaders [
# INT-PHDRS: ProgramHeader {
# INT-PHDRS: Type: Unknown (0x11223344)
# INT-PHDRS-NEXT: Offset: 0xB0
# INT-PHDRS-NEXT: VirtualAddress: 0xB0
# INT-PHDRS-NEXT: PhysicalAddress: 0xB0
# INT-PHDRS-NEXT: FileSize:
# INT-PHDRS-NEXT: MemSize:
# INT-PHDRS-NEXT: Flags [
# INT-PHDRS-NEXT: PF_R
# INT-PHDRS-NEXT: PF_W
# INT-PHDRS-NEXT: PF_X
# INT-PHDRS-NEXT: ]
# INT-PHDRS-NEXT: Alignment:
# INT-PHDRS-NEXT: }
# INT-PHDRS-NEXT: ]

# DEFHDR: ProgramHeaders [
# DEFHDR-NEXT: ProgramHeader {
# DEFHDR-NEXT: Type: PT_LOAD (0x1)
# DEFHDR-NEXT: Offset: 0x0
# DEFHDR-NEXT: VirtualAddress: 0x10000000
# DEFHDR-NEXT: PhysicalAddress: 0x10000000
# DEFHDR-NEXT: FileSize: 521
# DEFHDR-NEXT: MemSize: 521
# DEFHDR-NEXT: Flags [ (0x7)
# DEFHDR-NEXT: PF_R (0x4)
# DEFHDR-NEXT: PF_W (0x2)
# DEFHDR-NEXT: PF_X (0x1)
# DEFHDR-NEXT: ]

# BADHDR: {{.*}}.script:1: program header 'bar' is not listed in PHDRS

# RUN: echo "PHDRS { text PT_LOAD FOOHDR; }" > %t1.script
# RUN: not ld.lld -o /dev/null --script %t1.script %t 2>&1 | FileCheck --check-prefix=FOOHDR %s
# FOOHDR: error: {{.*}}.script:1: unexpected header attribute: FOOHDR

# RUN: echo "PHDRS { text PT_FOO FOOHDR; }" > %t1.script
# RUN: not ld.lld -o /dev/null --script %t1.script %t 2>&1 | FileCheck --check-prefix=PTFOO %s
# PTFOO: invalid program header type: PT_FOO
# RUN: not ld.lld -T unspecified.lds a.o 2>&1 | FileCheck --check-prefix=UNSPECIFIED %s
# UNSPECIFIED: unspecified.lds:6: program header 'bar' is not listed in PHDRS

#--- foohdr.lds
PHDRS { text PT_LOAD FOOHDR; }

# RUN: not ld.lld -T foohdr.lds a.o 2>&1 | FileCheck --check-prefix=FOOHDR %s
# FOOHDR: error: foohdr.lds:1: unexpected header attribute: FOOHDR

#--- pt_foo.lds
PHDRS { text PT_FOO FOOHDR; }

# RUN: not ld.lld -T pt_foo.lds a.o 2>&1 | FileCheck --check-prefix=PTFOO %s --strict-whitespace
# PTFOO:{{.*}}error: pt_foo.lds:1: invalid program header type: PT_FOO
# PTFOO-NEXT:>>> PHDRS { text PT_FOO FOOHDR; }
# PTFOO-NEXT:>>> ^

#--- unclosed.lds
PHDRS { text PT_LOAD ;

# RUN: not ld.lld -T unclosed.lds a.o 2>&1 | FileCheck --check-prefix=UNCLOSED %s
# UNCLOSED:error: unclosed.lds:1: unexpected EOF
# UNCLOSED-NOT:{{.}}

#--- a.s
.global _start
_start:
nop
Expand Down
53 changes: 36 additions & 17 deletions lld/test/ELF/linkerscript/sections.s
Original file line number Diff line number Diff line change
@@ -1,18 +1,22 @@
# REQUIRES: x86
# RUN: llvm-mc -filetype=obj -triple=x86_64-unknown-linux %s -o %t
# RUN: rm -rf %t && split-file %s %t && cd %t
# RUN: llvm-mc -filetype=obj -triple=x86_64 a.s -o a.o

# Empty SECTIONS command.
# RUN: echo "SECTIONS {}" > %t.script
# RUN: ld.lld -o %t1 --script %t.script %t
# RUN: llvm-objdump --section-headers %t1 | \
#--- empty.lds
SECTIONS {}

# RUN: ld.lld -o empty -T empty.lds a.o
# RUN: llvm-objdump --section-headers empty | \
# RUN: FileCheck -check-prefix=SEC-DEFAULT %s

#--- 1.lds
# SECTIONS command with the same order as default.
# RUN: echo "SECTIONS { \
# RUN: .text : { *(.text) } \
# RUN: .data : { *(.data) } }" > %t.script
# RUN: ld.lld -o %t2 --script %t.script %t
# RUN: llvm-objdump --section-headers %t2 | \
SECTIONS {
.text : { *(.text) }
.data : { *(.data) } }

# RUN: ld.lld -o 1 -T 1.lds a.o
# RUN: llvm-objdump --section-headers 1 | \
# RUN: FileCheck -check-prefix=SEC-DEFAULT %s

# Idx Name Size
Expand All @@ -28,8 +32,8 @@
# .text and .data have swapped names but proper sizes and types.
# RUN: echo "SECTIONS { \
# RUN: .data : { *(.text) } \
# RUN: .text : { *(.data) } }" > %t.script
# RUN: ld.lld -o %t4 --script %t.script %t
# RUN: .text : { *(.data) } }" > t.lds
# RUN: ld.lld -o %t4 --script t.lds a.o
# RUN: llvm-objdump --section-headers %t4 | \
# RUN: FileCheck -check-prefix=SEC-SWAP-NAMES %s

Expand All @@ -50,8 +54,8 @@
# RUN: .text : { *(.text) } \
# RUN: .data : { *(.data) } } \
# RUN: SECTIONS { \
# RUN: .data : { *(other) } }" > %t.script
# RUN: ld.lld -o %t6 --script %t.script %t
# RUN: .data : { *(other) } }" > t.lds
# RUN: ld.lld -o %t6 --script t.lds a.o
# RUN: llvm-objdump --section-headers %t6 | \
# RUN: FileCheck -check-prefix=SEC-MULTI %s

Expand All @@ -72,7 +76,7 @@
# RUN: .data : { *(.data) } \
# RUN: .comment : { *(.comment) } \
# RUN: other : { *(other) } }' > %t5.lds
# RUN: ld.lld -o %t5 -T %t5.lds %t
# RUN: ld.lld -o %t5 -T %t5.lds a.o
# RUN: llvm-readelf -S -l %t5 | FileCheck --check-prefix=SEP-BY-NONALLOC %s

# SEP-BY-NONALLOC: [Nr] Name Type Address Off Size ES Flg
Expand All @@ -87,11 +91,26 @@
# SEP-BY-NONALLOC-NEXT: LOAD 0x00100e 0x000000000000000e 0x000000000000000e 0x000023 0x000025 RW 0x1000
# SEP-BY-NONALLOC-NEXT: GNU_STACK 0x000000 0x0000000000000000 0x0000000000000000 0x000000 0x000000 RW 0

#--- semi.lds
# Input section pattern contains additional semicolon.
# Case found in linux kernel script. Check we are able to parse it.
# RUN: echo "SECTIONS { .text : { ;;*(.text);;S = 0;; } }" > %t.script
# RUN: ld.lld -o /dev/null --script %t.script %t
SECTIONS { .text : { ;;*(.text);;S = 0;; } }

# RUN: ld.lld -T semi.lds a.o

#--- unclosed.lds
SECTIONS {
.text : { *(.text) }

# RUN: not ld.lld -T unclosed.lds a.o 2>&1 | FileCheck --check-prefix=UNCLOSED %s
# UNCLOSED:error: unclosed.lds:1: unexpected EOF
# UNCLOSED-NOT:{{.}}

#--- unclosed-out.lds
SECTIONS {
.text : { *(.text)

#--- a.s
.globl _start
_start:
mov $60, %rax
Expand Down
9 changes: 4 additions & 5 deletions lld/test/ELF/linkerscript/unquoted.test
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,10 @@ INCLUDE "empty.lds"
INCLUDE "1.lds"

# RUN: not ld.lld -shared 0.o -T 1.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
# RUN: not ld.lld -shared 0.o -T 1a.lds 2>&1 | FileCheck %s --check-prefix=CHECK1A --match-full-lines --strict-whitespace
# CHECK1:{{.*}}error: 1.lds:1: unclosed comment in a linker script
# CHECK1A:{{.*}}error: 1a.lds:3: unclosed comment in a linker script
#CHECK1A-NEXT:>>> INCLUDE "1.lds"
#CHECK1A-NEXT:>>> ^
# RUN: not ld.lld -shared 0.o -T 1a.lds 2>&1 | FileCheck %s --check-prefix=CHECK1 --match-full-lines --strict-whitespace
# CHECK1:{{.*}}error: 1.lds:2: unclosed comment in a linker script
# CHECK1-NEXT:>>> SECTIONS /*
# CHECK1-NEXT:>>> ^

#--- 2.lds
INCLUDE "empty.lds"
Expand Down
10 changes: 3 additions & 7 deletions lldb/packages/Python/lldbsuite/test/lldbplatformutil.py
Original file line number Diff line number Diff line change
Expand Up @@ -266,17 +266,13 @@ def getCompiler():
return module.getCompiler()


def getCompilerBinary():
"""Returns the compiler binary the test suite is running with."""
return getCompiler().split()[0]


def getCompilerVersion():
"""Returns a string that represents the compiler version.
Supports: llvm, clang.
"""
compiler = getCompilerBinary()
version_output = subprocess.check_output([compiler, "--version"], errors="replace")
version_output = subprocess.check_output(
[getCompiler(), "--version"], errors="replace"
)
m = re.search("version ([0-9.]+)", version_output)
if m:
return m.group(1)
Expand Down
4 changes: 0 additions & 4 deletions lldb/packages/Python/lldbsuite/test/lldbtest.py
Original file line number Diff line number Diff line change
Expand Up @@ -1379,10 +1379,6 @@ def getCompiler(self):
"""Returns the compiler in effect the test suite is running with."""
return lldbplatformutil.getCompiler()

def getCompilerBinary(self):
"""Returns the compiler binary the test suite is running with."""
return lldbplatformutil.getCompilerBinary()

def getCompilerVersion(self):
"""Returns a string that represents the compiler version.
Supports: llvm, clang.
Expand Down
2 changes: 1 addition & 1 deletion lldb/source/Commands/CommandObjectTarget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ static void DumpTargetInfo(uint32_t target_idx, Target *target,

uint32_t properties = 0;
if (target_arch.IsValid()) {
strm.Printf("%sarch=", properties++ > 0 ? ", " : " ( ");
strm.Printf(" ( arch=");
target_arch.DumpTriple(strm.AsRawOstream());
properties++;
}
Expand Down
4 changes: 3 additions & 1 deletion llvm/docs/GettingStarted.rst
Original file line number Diff line number Diff line change
Expand Up @@ -291,10 +291,11 @@ uses the package and provides other details.
=========================================================== ============ ==========================================
Package Version Notes
=========================================================== ============ ==========================================
`CMake <http://cmake.org/>`__ >=3.20.0 Makefile/workspace generator
`CMake <http://cmake.org/>`_ >=3.20.0 Makefile/workspace generator
`python <http://www.python.org/>`_ >=3.8 Automated test suite\ :sup:`1`
`zlib <http://zlib.net>`_ >=1.2.3.4 Compression library\ :sup:`2`
`GNU Make <http://savannah.gnu.org/projects/make>`_ 3.79, 3.79.1 Makefile/build processor\ :sup:`3`
`PyYAML <https://pypi.org/project/PyYAML/>`_ >=5.1 Header generator\ :sup:`4`
=========================================================== ============ ==========================================

.. note::
Expand All @@ -305,6 +306,7 @@ Package Version Notes
#. Optional, adds compression / uncompression capabilities to selected LLVM
tools.
#. Optional, you can use any other build tool supported by CMake.
#. Only needed when building libc with New Headergen. Mainly used by libc.

Additionally, your compilation host is expected to have the usual plethora of
Unix utilities. Specifically:
Expand Down
2 changes: 2 additions & 0 deletions llvm/docs/ProgrammersManual.rst
Original file line number Diff line number Diff line change
Expand Up @@ -1392,6 +1392,7 @@ How to use reduce-chunk-list:
First, Figure out the number of calls to the debug counter you want to minimize.
To do so, run the compilation command causing you want to minimize with `-print-debug-counter` adding a `-mllvm` if needed.
Than find the line with the counter of interest. it should look like:

.. code-block:: none
my-counter : {5678,empty}
Expand All @@ -1400,6 +1401,7 @@ The number of calls to `my-counter` is 5678

Than Find the minimum set of chunks that is interesting, with `reduce-chunk-list`.
Build a reproducer script like:

.. code-block:: bash
#! /bin/bash
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm-c/Target.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,7 +244,7 @@ LLVMTypeRef LLVMIntPtrTypeInContext(LLVMContextRef C, LLVMTargetDataRef TD);
LLVMTypeRef LLVMIntPtrTypeForASInContext(LLVMContextRef C, LLVMTargetDataRef TD,
unsigned AS);

/** Computes the size of a type in bytes for a target.
/** Computes the size of a type in bits for a target.
See the method llvm::DataLayout::getTypeSizeInBits. */
unsigned long long LLVMSizeOfTypeInBits(LLVMTargetDataRef TD, LLVMTypeRef Ty);

Expand Down
297 changes: 285 additions & 12 deletions llvm/include/llvm/SandboxIR/SandboxIR.h

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions llvm/include/llvm/SandboxIR/SandboxIRValues.def
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ DEF_INSTR(Br, OP(Br), BranchInst)
DEF_INSTR(Load, OP(Load), LoadInst)
DEF_INSTR(Store, OP(Store), StoreInst)
DEF_INSTR(Ret, OP(Ret), ReturnInst)
DEF_INSTR(Call, OP(Call), CallInst)
DEF_INSTR(Invoke, OP(Invoke), InvokeInst)
DEF_INSTR(CallBr, OP(CallBr), CallBrInst)

#ifdef DEF_VALUE
#undef DEF_VALUE
Expand Down
2 changes: 2 additions & 0 deletions llvm/include/llvm/SandboxIR/Use.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace llvm::sandboxir {
class Context;
class Value;
class User;
class CallBase;

/// Represents a Def-use/Use-def edge in SandboxIR.
/// NOTE: Unlike llvm::Use, this is not an integral part of the use-def chains.
Expand All @@ -40,6 +41,7 @@ class Use {
friend class User; // For constructor
friend class OperandUseIterator; // For constructor
friend class UserUseIterator; // For accessing members
friend class CallBase; // For LLVMUse

public:
operator Value *() const { return get(); }
Expand Down
8 changes: 8 additions & 0 deletions llvm/include/llvm/Support/MathExtras.h
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,14 @@ std::enable_if_t<std::is_signed_v<T>, T> MulOverflow(T X, T Y, T &Result) {
#endif
}

/// Type to force float point values onto the stack, so that x86 doesn't add
/// hidden precision, avoiding rounding differences on various platforms.
#if defined(__i386__) || defined(_M_IX86)
using stack_float_t = volatile float;
#else
using stack_float_t = float;
#endif

} // namespace llvm

#endif
11 changes: 6 additions & 5 deletions llvm/lib/CodeGen/CalcSpillWeights.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "llvm/CodeGen/TargetSubtargetInfo.h"
#include "llvm/CodeGen/VirtRegMap.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
#include "llvm/Support/raw_ostream.h"
#include <cassert>
#include <tuple>
Expand Down Expand Up @@ -257,7 +258,9 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start,
return -1.0f;
}

float Weight = 1.0f;
// Force Weight onto the stack so that x86 doesn't add hidden precision,
// similar to HWeight below.
stack_float_t Weight = 1.0f;
if (IsSpillable) {
// Get loop info for mi.
if (MI->getParent() != MBB) {
Expand All @@ -284,11 +287,9 @@ float VirtRegAuxInfo::weightCalcHelper(LiveInterval &LI, SlotIndex *Start,
Register HintReg = copyHint(MI, LI.reg(), TRI, MRI);
if (!HintReg)
continue;
// Force hweight onto the stack so that x86 doesn't add hidden precision,
// Force HWeight onto the stack so that x86 doesn't add hidden precision,
// making the comparison incorrectly pass (i.e., 1 > 1 == true??).
//
// FIXME: we probably shouldn't use floats at all.
volatile float HWeight = Hint[HintReg] += Weight;
stack_float_t HWeight = Hint[HintReg] += Weight;
if (HintReg.isVirtual() || MRI.isAllocatable(HintReg))
CopyHints.insert(CopyHint(HintReg, HWeight));
}
Expand Down
38 changes: 36 additions & 2 deletions llvm/lib/CodeGen/SelectionDAG/TargetLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8556,11 +8556,12 @@ static std::optional<bool> isFCmpEqualZero(FPClassTest Test,
}

SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
FPClassTest Test, SDNodeFlags Flags,
const SDLoc &DL,
const FPClassTest OrigTestMask,
SDNodeFlags Flags, const SDLoc &DL,
SelectionDAG &DAG) const {
EVT OperandVT = Op.getValueType();
assert(OperandVT.isFloatingPoint());
FPClassTest Test = OrigTestMask;

// Degenerated cases.
if (Test == fcNone)
Expand Down Expand Up @@ -8594,9 +8595,21 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
// exceptions are ignored.
if (Flags.hasNoFPExcept() &&
isOperationLegalOrCustom(ISD::SETCC, OperandVT.getScalarType())) {
FPClassTest FPTestMask = Test;

ISD::CondCode OrderedCmpOpcode = IsInverted ? ISD::SETUNE : ISD::SETOEQ;
ISD::CondCode UnorderedCmpOpcode = IsInverted ? ISD::SETONE : ISD::SETUEQ;

// See if we can fold an | fcNan into an unordered compare.
FPClassTest OrderedFPTestMask = FPTestMask & ~fcNan;

// Can't fold the ordered check if we're only testing for snan or qnan
// individually.
if ((FPTestMask & fcNan) != fcNan)
OrderedFPTestMask = FPTestMask;

const bool IsOrdered = FPTestMask == OrderedFPTestMask;

if (std::optional<bool> IsCmp0 =
isFCmpEqualZero(Test, Semantics, DAG.getMachineFunction());
IsCmp0 && (isCondCodeLegalOrCustom(
Expand Down Expand Up @@ -8628,6 +8641,27 @@ SDValue TargetLowering::expandIS_FPCLASS(EVT ResultVT, SDValue Op,
return DAG.getSetCC(DL, ResultVT, Abs, Inf,
IsInverted ? ISD::SETUNE : ISD::SETOEQ);
}

if (OrderedFPTestMask == (fcSubnormal | fcZero) && !IsOrdered) {
// TODO: Could handle ordered case, but it produces worse code for
// x86. Maybe handle ordered if fabs is free?

ISD::CondCode OrderedOp = IsInverted ? ISD::SETUGE : ISD::SETOLT;
ISD::CondCode UnorderedOp = IsInverted ? ISD::SETOGE : ISD::SETULT;

if (isCondCodeLegalOrCustom(IsOrdered ? OrderedOp : UnorderedOp,
OperandVT.getScalarType().getSimpleVT())) {
// (issubnormal(x) || iszero(x)) --> fabs(x) < smallest_normal

// TODO: Maybe only makes sense if fabs is free. Integer test of
// exponent bits seems better for x86.
SDValue Abs = DAG.getNode(ISD::FABS, DL, OperandVT, Op);
SDValue SmallestNormal = DAG.getConstantFP(
APFloat::getSmallestNormalized(Semantics), DL, OperandVT);
return DAG.getSetCC(DL, ResultVT, Abs, SmallestNormal,
IsOrdered ? OrderedOp : UnorderedOp);
}
}
}

// In the general case use integer operations.
Expand Down
200 changes: 197 additions & 3 deletions llvm/lib/SandboxIR/SandboxIR.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,12 @@ using namespace llvm::sandboxir;

Value *Use::get() const { return Ctx->getValue(LLVMUse->get()); }

void Use::set(Value *V) { LLVMUse->set(V->Val); }
void Use::set(Value *V) {
auto &Tracker = Ctx->getTracker();
if (Tracker.isTracking())
Tracker.track(std::make_unique<UseSet>(*this, Tracker));
LLVMUse->set(V->Val);
}

unsigned Use::getOperandNo() const { return Usr->getUseOperandNo(*this); }

Expand Down Expand Up @@ -84,6 +89,25 @@ UserUseIterator &UserUseIterator::operator++() {
return *this;
}

OperandUseIterator OperandUseIterator::operator+(unsigned Num) const {
sandboxir::Use U = Use.getUser()->getOperandUseInternal(
Use.getOperandNo() + Num, /*Verify=*/true);
return OperandUseIterator(U);
}

OperandUseIterator OperandUseIterator::operator-(unsigned Num) const {
assert(Use.getOperandNo() >= Num && "Out of bounds!");
sandboxir::Use U = Use.getUser()->getOperandUseInternal(
Use.getOperandNo() - Num, /*Verify=*/true);
return OperandUseIterator(U);
}

int OperandUseIterator::operator-(const OperandUseIterator &Other) const {
int ThisOpNo = Use.getOperandNo();
int OtherOpNo = Other.Use.getOperandNo();
return ThisOpNo - OtherOpNo;
}

Value::Value(ClassID SubclassID, llvm::Value *Val, Context &Ctx)
: SubclassID(SubclassID), Val(Val), Ctx(Ctx) {
#ifndef NDEBUG
Expand Down Expand Up @@ -713,6 +737,153 @@ void ReturnInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG

Value *CallBase::getCalledOperand() const {
return Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledOperand());
}

Use CallBase::getCalledOperandUse() const {
llvm::Use *LLVMUse = &cast<llvm::CallBase>(Val)->getCalledOperandUse();
return Use(LLVMUse, cast<User>(Ctx.getValue(LLVMUse->getUser())), Ctx);
}

Function *CallBase::getCalledFunction() const {
return cast_or_null<Function>(
Ctx.getValue(cast<llvm::CallBase>(Val)->getCalledFunction()));
}
Function *CallBase::getCaller() {
return cast<Function>(Ctx.getValue(cast<llvm::CallBase>(Val)->getCaller()));
}

void CallBase::setCalledFunction(Function *F) {
// F's function type is private, so we rely on `setCalledFunction()` to update
// it. But even though we are calling `setCalledFunction()` we also need to
// track this change at the SandboxIR level, which is why we call
// `setCalledOperand()` here.
// Note: This may break if `setCalledFunction()` early returns if `F`
// is already set, but we do have a unit test for it.
setCalledOperand(F);
cast<llvm::CallBase>(Val)->setCalledFunction(F->getFunctionType(),
cast<llvm::Function>(F->Val));
}

CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, BasicBlock::iterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::Value *> LLVMArgs;
LLVMArgs.reserve(Args.size());
for (Value *Arg : Args)
LLVMArgs.push_back(Arg->Val);
llvm::CallInst *NewCI = Builder.CreateCall(FTy, Func->Val, LLVMArgs, NameStr);
return Ctx.createCallInst(NewCI);
}

CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, Instruction *InsertBefore,
Context &Ctx, const Twine &NameStr) {
return CallInst::create(FTy, Func, Args, InsertBefore->getIterator(),
InsertBefore->getParent(), Ctx, NameStr);
}

CallInst *CallInst::create(FunctionType *FTy, Value *Func,
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
Context &Ctx, const Twine &NameStr) {
return CallInst::create(FTy, Func, Args, InsertAtEnd->end(), InsertAtEnd, Ctx,
NameStr);
}

#ifndef NDEBUG
void CallInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}

void CallInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}
#endif // NDEBUG

InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args, BBIterator WhereIt,
BasicBlock *WhereBB, Context &Ctx,
const Twine &NameStr) {
auto &Builder = Ctx.getLLVMIRBuilder();
if (WhereIt != WhereBB->end())
Builder.SetInsertPoint((*WhereIt).getTopmostLLVMInstruction());
else
Builder.SetInsertPoint(cast<llvm::BasicBlock>(WhereBB->Val));
SmallVector<llvm::Value *> LLVMArgs;
LLVMArgs.reserve(Args.size());
for (Value *Arg : Args)
LLVMArgs.push_back(Arg->Val);
llvm::InvokeInst *Invoke = Builder.CreateInvoke(
FTy, Func->Val, cast<llvm::BasicBlock>(IfNormal->Val),
cast<llvm::BasicBlock>(IfException->Val), LLVMArgs, NameStr);
return Ctx.createInvokeInst(Invoke);
}

InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args,
Instruction *InsertBefore, Context &Ctx,
const Twine &NameStr) {
return create(FTy, Func, IfNormal, IfException, Args,
InsertBefore->getIterator(), InsertBefore->getParent(), Ctx,
NameStr);
}

InvokeInst *InvokeInst::create(FunctionType *FTy, Value *Func,
BasicBlock *IfNormal, BasicBlock *IfException,
ArrayRef<Value *> Args, BasicBlock *InsertAtEnd,
Context &Ctx, const Twine &NameStr) {
return create(FTy, Func, IfNormal, IfException, Args, InsertAtEnd->end(),
InsertAtEnd, Ctx, NameStr);
}

BasicBlock *InvokeInst::getNormalDest() const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getNormalDest()));
}
BasicBlock *InvokeInst::getUnwindDest() const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getUnwindDest()));
}
void InvokeInst::setNormalDest(BasicBlock *BB) {
setOperand(1, BB);
assert(getNormalDest() == BB && "LLVM IR uses a different operan index!");
}
void InvokeInst::setUnwindDest(BasicBlock *BB) {
setOperand(2, BB);
assert(getUnwindDest() == BB && "LLVM IR uses a different operan index!");
}
Instruction *InvokeInst::getLandingPadInst() const {
return cast<Instruction>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getLandingPadInst()));
;
}
BasicBlock *InvokeInst::getSuccessor(unsigned SuccIdx) const {
return cast<BasicBlock>(
Ctx.getValue(cast<llvm::InvokeInst>(Val)->getSuccessor(SuccIdx)));
}

#ifndef NDEBUG
void InvokeInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
dumpCommonSuffix(OS);
}
void InvokeInst::dump() const {
dump(dbgs());
dbgs() << "\n";
}

void OpaqueInst::dump(raw_ostream &OS) const {
dumpCommonPrefix(OS);
Expand Down Expand Up @@ -819,7 +990,10 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
return It->second.get();

if (auto *C = dyn_cast<llvm::Constant>(LLVMV)) {
It->second = std::unique_ptr<Constant>(new Constant(C, *this));
if (auto *F = dyn_cast<llvm::Function>(LLVMV))
It->second = std::unique_ptr<Function>(new Function(F, *this));
else
It->second = std::unique_ptr<Constant>(new Constant(C, *this));
auto *NewC = It->second.get();
for (llvm::Value *COp : C->operands())
getOrCreateValueInternal(COp, C);
Expand Down Expand Up @@ -864,6 +1038,16 @@ Value *Context::getOrCreateValueInternal(llvm::Value *LLVMV, llvm::User *U) {
It->second = std::unique_ptr<ReturnInst>(new ReturnInst(LLVMRet, *this));
return It->second.get();
}
case llvm::Instruction::Call: {
auto *LLVMCall = cast<llvm::CallInst>(LLVMV);
It->second = std::unique_ptr<CallInst>(new CallInst(LLVMCall, *this));
return It->second.get();
}
case llvm::Instruction::Invoke: {
auto *LLVMInvoke = cast<llvm::InvokeInst>(LLVMV);
It->second = std::unique_ptr<InvokeInst>(new InvokeInst(LLVMInvoke, *this));
return It->second.get();
}
default:
break;
}
Expand Down Expand Up @@ -907,6 +1091,16 @@ ReturnInst *Context::createReturnInst(llvm::ReturnInst *I) {
return cast<ReturnInst>(registerValue(std::move(NewPtr)));
}

CallInst *Context::createCallInst(llvm::CallInst *I) {
auto NewPtr = std::unique_ptr<CallInst>(new CallInst(I, *this));
return cast<CallInst>(registerValue(std::move(NewPtr)));
}

InvokeInst *Context::createInvokeInst(llvm::InvokeInst *I) {
auto NewPtr = std::unique_ptr<InvokeInst>(new InvokeInst(I, *this));
return cast<InvokeInst>(registerValue(std::move(NewPtr)));
}

Value *Context::getValue(llvm::Value *V) const {
auto It = LLVMValueToValueMap.find(V);
if (It != LLVMValueToValueMap.end())
Expand All @@ -917,13 +1111,13 @@ Value *Context::getValue(llvm::Value *V) const {
Function *Context::createFunction(llvm::Function *F) {
assert(getValue(F) == nullptr && "Already exists!");
auto NewFPtr = std::unique_ptr<Function>(new Function(F, *this));
auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
// Create arguments.
for (auto &Arg : F->args())
getOrCreateArgument(&Arg);
// Create BBs.
for (auto &BB : *F)
createBasicBlock(&BB);
auto *SBF = cast<Function>(registerValue(std::move(NewFPtr)));
return SBF;
}

Expand Down
3 changes: 2 additions & 1 deletion llvm/lib/Target/AMDGPU/AMDGPUPrintfRuntimeBinding.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,8 @@ bool AMDGPUPrintfRuntimeBindingImpl::run(Module &M) {
return false;

auto PrintfFunction = M.getFunction("printf");
if (!PrintfFunction || !PrintfFunction->isDeclaration())
if (!PrintfFunction || !PrintfFunction->isDeclaration() ||
M.getModuleFlag("openmp"))
return false;

for (auto &U : PrintfFunction->uses()) {
Expand Down
22 changes: 21 additions & 1 deletion llvm/lib/Target/RISCV/RISCVISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1473,7 +1473,7 @@ RISCVTargetLowering::RISCVTargetLowering(const TargetMachine &TM,
setTargetDAGCombine(ISD::SRA);

if (Subtarget.hasStdExtFOrZfinx())
setTargetDAGCombine({ISD::FADD, ISD::FMAXNUM, ISD::FMINNUM});
setTargetDAGCombine({ISD::FADD, ISD::FMAXNUM, ISD::FMINNUM, ISD::FMUL});

if (Subtarget.hasStdExtZbb())
setTargetDAGCombine({ISD::UMAX, ISD::UMIN, ISD::SMAX, ISD::SMIN});
Expand Down Expand Up @@ -16682,6 +16682,25 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
if (SDValue V = combineBinOpOfZExt(N, DAG))
return V;
break;
case ISD::FMUL: {
// fmul X, (copysign 1.0, Y) -> fsgnjx X, Y
SDValue N0 = N->getOperand(0);
SDValue N1 = N->getOperand(1);
if (N0->getOpcode() != ISD::FCOPYSIGN)
std::swap(N0, N1);
if (N0->getOpcode() != ISD::FCOPYSIGN)
return SDValue();
ConstantFPSDNode *C = dyn_cast<ConstantFPSDNode>(N0->getOperand(0));
if (!C || !C->getValueAPF().isExactlyValue(+1.0))
return SDValue();
EVT VT = N->getValueType(0);
if (VT.isVector() || !isOperationLegal(ISD::FCOPYSIGN, VT))
return SDValue();
SDValue Sign = N0->getOperand(1);
if (Sign.getValueType() != VT)
return SDValue();
return DAG.getNode(RISCVISD::FSGNJX, SDLoc(N), VT, N1, N0->getOperand(1));
}
case ISD::FADD:
case ISD::UMAX:
case ISD::UMIN:
Expand Down Expand Up @@ -20232,6 +20251,7 @@ const char *RISCVTargetLowering::getTargetNodeName(unsigned Opcode) const {
NODE_NAME_CASE(FP_EXTEND_BF16)
NODE_NAME_CASE(FROUND)
NODE_NAME_CASE(FCLASS)
NODE_NAME_CASE(FSGNJX)
NODE_NAME_CASE(FMAX)
NODE_NAME_CASE(FMIN)
NODE_NAME_CASE(READ_COUNTER_WIDE)
Expand Down
1 change: 1 addition & 0 deletions llvm/lib/Target/RISCV/RISCVISelLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,7 @@ enum NodeType : unsigned {
FROUND,

FCLASS,
FSGNJX,

// Floating point fmax and fmin matching the RISC-V instruction semantics.
FMAX, FMIN,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoD.td
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ def : Pat<(fabs FPR64:$rs1), (FSGNJX_D $rs1, $rs1)>;
def : Pat<(riscv_fclass FPR64:$rs1), (FCLASS_D $rs1)>;

def : PatFprFpr<fcopysign, FSGNJ_D, FPR64, f64>;
def : PatFprFpr<riscv_fsgnjx, FSGNJX_D, FPR64, f64>;
def : Pat<(fcopysign FPR64:$rs1, (fneg FPR64:$rs2)), (FSGNJN_D $rs1, $rs2)>;
def : Pat<(fcopysign FPR64:$rs1, FPR32:$rs2), (FSGNJ_D $rs1, (FCVT_D_S $rs2,
FRM_RNE))>;
Expand Down Expand Up @@ -318,6 +319,7 @@ def : Pat<(fabs FPR64INX:$rs1), (FSGNJX_D_INX $rs1, $rs1)>;
def : Pat<(riscv_fclass FPR64INX:$rs1), (FCLASS_D_INX $rs1)>;

def : PatFprFpr<fcopysign, FSGNJ_D_INX, FPR64INX, f64>;
def : PatFprFpr<riscv_fsgnjx, FSGNJX_D_INX, FPR64INX, f64>;
def : Pat<(fcopysign FPR64INX:$rs1, (fneg FPR64INX:$rs2)),
(FSGNJN_D_INX $rs1, $rs2)>;
def : Pat<(fcopysign FPR64INX:$rs1, FPR32INX:$rs2),
Expand Down Expand Up @@ -355,6 +357,7 @@ def : Pat<(fabs FPR64IN32X:$rs1), (FSGNJX_D_IN32X $rs1, $rs1)>;
def : Pat<(riscv_fclass FPR64IN32X:$rs1), (FCLASS_D_IN32X $rs1)>;

def : PatFprFpr<fcopysign, FSGNJ_D_IN32X, FPR64IN32X, f64>;
def : PatFprFpr<riscv_fsgnjx, FSGNJX_D_IN32X, FPR64IN32X, f64>;
def : Pat<(fcopysign FPR64IN32X:$rs1, (fneg FPR64IN32X:$rs2)),
(FSGNJN_D_IN32X $rs1, $rs2)>;
def : Pat<(fcopysign FPR64IN32X:$rs1, FPR32INX:$rs2),
Expand Down
9 changes: 8 additions & 1 deletion llvm/lib/Target/RISCV/RISCVInstrInfoF.td
Original file line number Diff line number Diff line change
Expand Up @@ -31,13 +31,18 @@ def SDT_RISCVFROUND
SDTCisVT<3, XLenVT>]>;
def SDT_RISCVFCLASS
: SDTypeProfile<1, 1, [SDTCisVT<0, XLenVT>, SDTCisFP<1>]>;
def SDT_RISCVFSGNJX
: SDTypeProfile<1, 2, [SDTCisFP<0>, SDTCisSameAs<0, 1>, SDTCisSameAs<0, 2>]>;

def riscv_fclass
: SDNode<"RISCVISD::FCLASS", SDT_RISCVFCLASS>;

def riscv_fround
: SDNode<"RISCVISD::FROUND", SDT_RISCVFROUND>;

def riscv_fsgnjx
: SDNode<"RISCVISD::FSGNJX", SDT_RISCVFSGNJX>;

def riscv_fmv_w_x_rv64
: SDNode<"RISCVISD::FMV_W_X_RV64", SDT_RISCVFMV_W_X_RV64>;
def riscv_fmv_x_anyextw_rv64
Expand Down Expand Up @@ -539,8 +544,10 @@ def : Pat<(fabs FPR32INX:$rs1), (FSGNJX_S_INX $rs1, $rs1)>;
def : Pat<(riscv_fclass FPR32INX:$rs1), (FCLASS_S_INX $rs1)>;
} // Predicates = [HasStdExtZfinx]

foreach Ext = FExts in
foreach Ext = FExts in {
defm : PatFprFpr_m<fcopysign, FSGNJ_S, Ext>;
defm : PatFprFpr_m<riscv_fsgnjx, FSGNJX_S, Ext>;
}

let Predicates = [HasStdExtF] in {
def : Pat<(fcopysign FPR32:$rs1, (fneg FPR32:$rs2)), (FSGNJN_S $rs1, $rs2)>;
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfoZfh.td
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,7 @@ def : Pat<(f16 (fabs FPR16:$rs1)), (FSGNJX_H $rs1, $rs1)>;
def : Pat<(riscv_fclass (f16 FPR16:$rs1)), (FCLASS_H $rs1)>;

def : PatFprFpr<fcopysign, FSGNJ_H, FPR16, f16>;
def : PatFprFpr<riscv_fsgnjx, FSGNJX_H, FPR16, f16>;
def : Pat<(f16 (fcopysign FPR16:$rs1, (f16 (fneg FPR16:$rs2)))), (FSGNJN_H $rs1, $rs2)>;
def : Pat<(f16 (fcopysign FPR16:$rs1, FPR32:$rs2)),
(FSGNJ_H $rs1, (FCVT_H_S $rs2, FRM_DYN))>;
Expand Down Expand Up @@ -314,6 +315,7 @@ def : Pat<(fabs FPR16INX:$rs1), (FSGNJX_H_INX $rs1, $rs1)>;
def : Pat<(riscv_fclass FPR16INX:$rs1), (FCLASS_H_INX $rs1)>;

def : PatFprFpr<fcopysign, FSGNJ_H_INX, FPR16INX, f16>;
def : PatFprFpr<riscv_fsgnjx, FSGNJX_H_INX, FPR16INX, f16>;
def : Pat<(fcopysign FPR16INX:$rs1, (fneg FPR16INX:$rs2)), (FSGNJN_H_INX $rs1, $rs2)>;
def : Pat<(fcopysign FPR16INX:$rs1, FPR32INX:$rs2),
(FSGNJ_H_INX $rs1, (FCVT_H_S_INX $rs2, FRM_DYN))>;
Expand Down
10 changes: 9 additions & 1 deletion llvm/lib/Target/RISCV/RISCVMergeBaseOffset.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -429,8 +429,16 @@ bool RISCVMergeBaseOffsetOpt::foldIntoMemoryOps(MachineInstr &Hi,
NumOps = Flags.getNumOperandRegisters();

// Memory constraints have two operands.
if (NumOps != 2 || !Flags.isMemKind())
if (NumOps != 2 || !Flags.isMemKind()) {
// If the register is used by something other than a memory contraint,
// we should not fold.
for (unsigned J = 0; J < NumOps; ++J) {
const MachineOperand &MO = UseMI.getOperand(I + 1 + J);
if (MO.isReg() && MO.getReg() == DestReg)
return false;
}
continue;
}

// We can't do this for constraint A because AMO instructions don't have
// an immediate offset field.
Expand Down
28 changes: 23 additions & 5 deletions llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1390,14 +1390,32 @@ InstructionCost RISCVTTIImpl::getMemoryOpCost(unsigned Opcode, Type *Src,
InstructionCost Cost = 0;
if (Opcode == Instruction::Store && OpInfo.isConstant())
Cost += getStoreImmCost(Src, OpInfo, CostKind);
InstructionCost BaseCost =
BaseT::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace,
CostKind, OpInfo, I);

std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Src);

InstructionCost BaseCost = [&]() {
InstructionCost Cost = LT.first;
if (CostKind != TTI::TCK_RecipThroughput)
return Cost;

// Our actual lowering for the case where a wider legal type is available
// uses the a VL predicated load on the wider type. This is reflected in
// the result of getTypeLegalizationCost, but BasicTTI assumes the
// widened cases are scalarized.
const DataLayout &DL = this->getDataLayout();
if (Src->isVectorTy() && LT.second.isVector() &&
TypeSize::isKnownLT(DL.getTypeStoreSizeInBits(Src),
LT.second.getSizeInBits()))
return Cost;

return BaseT::getMemoryOpCost(Opcode, Src, Alignment, AddressSpace,
CostKind, OpInfo, I);
}();

// Assume memory ops cost scale with the number of vector registers
// possible accessed by the instruction. Note that BasicTTI already
// handles the LT.first term for us.
if (std::pair<InstructionCost, MVT> LT = getTypeLegalizationCost(Src);
LT.second.isVector() && CostKind != TTI::TCK_CodeSize)
if (LT.second.isVector() && CostKind != TTI::TCK_CodeSize)
BaseCost *= TLI->getLMULCost(LT.second);
return Cost + BaseCost;

Expand Down
17 changes: 11 additions & 6 deletions llvm/lib/Transforms/Instrumentation/HWAddressSanitizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1528,11 +1528,7 @@ static void emitRemark(const Function &F, OptimizationRemarkEmitter &ORE,

bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
Function &F, FunctionAnalysisManager &FAM) const {
bool Skip = [&]() {
if (ClRandomSkipRate.getNumOccurrences()) {
std::bernoulli_distribution D(ClRandomSkipRate);
return !D(*Rng);
}
auto SkipHot = [&]() {
if (!ClHotPercentileCutoff.getNumOccurrences())
return false;
auto &MAMProxy = FAM.getResult<ModuleAnalysisManagerFunctionProxy>(F);
Expand All @@ -1544,7 +1540,16 @@ bool HWAddressSanitizer::selectiveInstrumentationShouldSkip(
}
return PSI->isFunctionHotInCallGraphNthPercentile(
ClHotPercentileCutoff, &F, FAM.getResult<BlockFrequencyAnalysis>(F));
}();
};

auto SkipRandom = [&]() {
if (!ClRandomSkipRate.getNumOccurrences())
return false;
std::bernoulli_distribution D(ClRandomSkipRate);
return !D(*Rng);
};

bool Skip = SkipRandom() || SkipHot();
emitRemark(F, FAM.getResult<OptimizationRemarkEmitterAnalysis>(F), Skip);
return Skip;
}
Expand Down
30 changes: 18 additions & 12 deletions llvm/lib/Transforms/Instrumentation/LowerAllowCheckPass.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,13 +76,25 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
SmallVector<std::pair<IntrinsicInst *, bool>, 16> ReplaceWithValue;
std::unique_ptr<RandomNumberGenerator> Rng;

auto ShouldRemove = [&](bool IsHot) {
if (!RandomRate.getNumOccurrences())
return IsHot;
auto GetRng = [&]() -> RandomNumberGenerator & {
if (!Rng)
Rng = F.getParent()->createRNG(F.getName());
std::bernoulli_distribution D(RandomRate);
return !D(*Rng);
return *Rng;
};

auto ShouldRemoveHot = [&](const BasicBlock &BB) {
return HotPercentileCutoff.getNumOccurrences() && PSI &&
PSI->isHotCountNthPercentile(
HotPercentileCutoff, BFI.getBlockProfileCount(&BB).value_or(0));
};

auto ShouldRemoveRandom = [&]() {
return RandomRate.getNumOccurrences() &&
!std::bernoulli_distribution(RandomRate)(GetRng());
};

auto ShouldRemove = [&](const BasicBlock &BB) {
return ShouldRemoveRandom() || ShouldRemoveHot(BB);
};

for (BasicBlock &BB : F) {
Expand All @@ -96,13 +108,7 @@ static bool removeUbsanTraps(Function &F, const BlockFrequencyInfo &BFI,
case Intrinsic::allow_runtime_check: {
++NumChecksTotal;

bool IsHot = false;
if (PSI) {
uint64_t Count = BFI.getBlockProfileCount(&BB).value_or(0);
IsHot = PSI->isHotCountNthPercentile(HotPercentileCutoff, Count);
}

bool ToRemove = ShouldRemove(IsHot);
bool ToRemove = ShouldRemove(BB);
ReplaceWithValue.push_back({
II,
ToRemove,
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Transforms/Vectorize/LoopVectorizationPlanner.h
Original file line number Diff line number Diff line change
Expand Up @@ -411,6 +411,9 @@ class LoopVectorizationPlanner {
VectorizationFactor
selectEpilogueVectorizationFactor(const ElementCount MaxVF, unsigned IC);

/// Emit remarks for recipes with invalid costs in the available VPlans.
void emitInvalidCostRemarks(OptimizationRemarkEmitter *ORE);

protected:
/// Build VPlans for power-of-2 VF's between \p MinVF and \p MaxVF inclusive,
/// according to the information gathered by Legal when it checked if it is
Expand Down
159 changes: 95 additions & 64 deletions llvm/lib/Transforms/Vectorize/LoopVectorize.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Twine.h"
#include "llvm/ADT/TypeSwitch.h"
#include "llvm/ADT/iterator_range.h"
#include "llvm/Analysis/AssumptionCache.h"
#include "llvm/Analysis/BasicAliasAnalysis.h"
Expand Down Expand Up @@ -889,20 +890,18 @@ static void debugVectorizationMessage(const StringRef Prefix,
/// \p PassName is the name of the pass (e.g. can be AlwaysPrint). \p
/// RemarkName is the identifier for the remark. If \p I is passed it is an
/// instruction that prevents vectorization. Otherwise \p TheLoop is used for
/// the location of the remark. \return the remark object that can be
/// streamed to.
static OptimizationRemarkAnalysis createLVAnalysis(const char *PassName,
StringRef RemarkName, Loop *TheLoop, Instruction *I) {
Value *CodeRegion = TheLoop->getHeader();
DebugLoc DL = TheLoop->getStartLoc();

if (I) {
CodeRegion = I->getParent();
// If there is no debug location attached to the instruction, revert back to
// using the loop's.
if (I->getDebugLoc())
DL = I->getDebugLoc();
}
/// the location of the remark. If \p DL is passed, use it as debug location for
/// the remark. \return the remark object that can be streamed to.
static OptimizationRemarkAnalysis
createLVAnalysis(const char *PassName, StringRef RemarkName, Loop *TheLoop,
Instruction *I, DebugLoc DL = {}) {
Value *CodeRegion = I ? I->getParent() : TheLoop->getHeader();
// If debug location is attached to the instruction, use it. Otherwise if DL
// was not provided, use the loop's.
if (I && I->getDebugLoc())
DL = I->getDebugLoc();
else if (!DL)
DL = TheLoop->getStartLoc();

return OptimizationRemarkAnalysis(PassName, RemarkName, DL, CodeRegion);
}
Expand Down Expand Up @@ -943,15 +942,17 @@ void reportVectorizationFailure(const StringRef DebugMsg,

/// Reports an informative message: print \p Msg for debugging purposes as well
/// as an optimization remark. Uses either \p I as location of the remark, or
/// otherwise \p TheLoop.
/// otherwise \p TheLoop. If \p DL is passed, use it as debug location for the
/// remark. If \p DL is passed, use it as debug location for the remark.
static void reportVectorizationInfo(const StringRef Msg, const StringRef ORETag,
OptimizationRemarkEmitter *ORE, Loop *TheLoop,
Instruction *I = nullptr) {
OptimizationRemarkEmitter *ORE,
Loop *TheLoop, Instruction *I = nullptr,
DebugLoc DL = {}) {
LLVM_DEBUG(debugVectorizationMessage("", Msg, I));
LoopVectorizeHints Hints(TheLoop, true /* doesn't matter */, *ORE);
ORE->emit(
createLVAnalysis(Hints.vectorizeAnalysisPassName(), ORETag, TheLoop, I)
<< Msg);
ORE->emit(createLVAnalysis(Hints.vectorizeAnalysisPassName(), ORETag, TheLoop,
I, DL)
<< Msg);
}

/// Report successful vectorization of the loop. In case an outer loop is
Expand Down Expand Up @@ -1538,12 +1539,8 @@ class LoopVectorizationCostModel {
/// Returns the expected execution cost. The unit of the cost does
/// not matter because we use the 'cost' units to compare different
/// vector widths. The cost that is returned is *not* normalized by
/// the factor width. If \p Invalid is not nullptr, this function
/// will add a pair(Instruction*, ElementCount) to \p Invalid for
/// each instruction that has an Invalid cost for the given VF.
InstructionCost
expectedCost(ElementCount VF,
SmallVectorImpl<InstructionVFPair> *Invalid = nullptr);
/// the factor width.
InstructionCost expectedCost(ElementCount VF);

bool hasPredStores() const { return NumPredStores > 0; }

Expand Down Expand Up @@ -4350,24 +4347,38 @@ bool LoopVectorizationPlanner::isMoreProfitable(
return CmpFn(RTCostA, RTCostB);
}

static void emitInvalidCostRemarks(SmallVector<InstructionVFPair> InvalidCosts,
OptimizationRemarkEmitter *ORE,
Loop *TheLoop) {
void LoopVectorizationPlanner::emitInvalidCostRemarks(
OptimizationRemarkEmitter *ORE) {
using RecipeVFPair = std::pair<VPRecipeBase *, ElementCount>;
LLVMContext &LLVMCtx = OrigLoop->getHeader()->getContext();
SmallVector<RecipeVFPair> InvalidCosts;
for (const auto &Plan : VPlans) {
for (ElementCount VF : Plan->vectorFactors()) {
VPCostContext CostCtx(CM.TTI, Legal->getWidestInductionType(), LLVMCtx,
CM);
auto Iter = vp_depth_first_deep(Plan->getVectorLoopRegion()->getEntry());
for (VPBasicBlock *VPBB : VPBlockUtils::blocksOnly<VPBasicBlock>(Iter)) {
for (auto &R : *VPBB) {
if (!R.cost(VF, CostCtx).isValid())
InvalidCosts.emplace_back(&R, VF);
}
}
}
}
if (InvalidCosts.empty())
return;

// Emit a report of VFs with invalid costs in the loop.

// Group the remarks per instruction, keeping the instruction order from
// InvalidCosts.
std::map<Instruction *, unsigned> Numbering;
// Group the remarks per recipe, keeping the recipe order from InvalidCosts.
DenseMap<VPRecipeBase *, unsigned> Numbering;
unsigned I = 0;
for (auto &Pair : InvalidCosts)
if (!Numbering.count(Pair.first))
Numbering[Pair.first] = I++;

// Sort the list, first on instruction(number) then on VF.
sort(InvalidCosts, [&Numbering](InstructionVFPair &A, InstructionVFPair &B) {
// Sort the list, first on recipe(number) then on VF.
sort(InvalidCosts, [&Numbering](RecipeVFPair &A, RecipeVFPair &B) {
if (Numbering[A.first] != Numbering[B.first])
return Numbering[A.first] < Numbering[B.first];
const auto &LHS = A.second;
Expand All @@ -4376,38 +4387,64 @@ static void emitInvalidCostRemarks(SmallVector<InstructionVFPair> InvalidCosts,
std::make_tuple(RHS.isScalable(), RHS.getKnownMinValue());
});

// For a list of ordered instruction-vf pairs:
// [(load, vf1), (load, vf2), (store, vf1)]
// Group the instructions together to emit separate remarks for:
// load (vf1, vf2)
// store (vf1)
auto Tail = ArrayRef<InstructionVFPair>(InvalidCosts);
auto Subset = ArrayRef<InstructionVFPair>();
// For a list of ordered recipe-VF pairs:
// [(load, VF1), (load, VF2), (store, VF1)]
// group the recipes together to emit separate remarks for:
// load (VF1, VF2)
// store (VF1)
auto Tail = ArrayRef<RecipeVFPair>(InvalidCosts);
auto Subset = ArrayRef<RecipeVFPair>();
do {
if (Subset.empty())
Subset = Tail.take_front(1);

Instruction *I = Subset.front().first;

// If the next instruction is different, or if there are no other pairs,
VPRecipeBase *R = Subset.front().first;

unsigned Opcode =
TypeSwitch<const VPRecipeBase *, unsigned>(R)
.Case<VPHeaderPHIRecipe>(
[](const auto *R) { return Instruction::PHI; })
.Case<VPWidenSelectRecipe>(
[](const auto *R) { return Instruction::Select; })
.Case<VPWidenStoreRecipe>(
[](const auto *R) { return Instruction::Store; })
.Case<VPWidenLoadRecipe>(
[](const auto *R) { return Instruction::Load; })
.Case<VPWidenCallRecipe>(
[](const auto *R) { return Instruction::Call; })
.Case<VPInstruction, VPWidenRecipe, VPReplicateRecipe,
VPWidenCastRecipe>(
[](const auto *R) { return R->getOpcode(); })
.Case<VPInterleaveRecipe>([](const VPInterleaveRecipe *R) {
return R->getStoredValues().empty() ? Instruction::Load
: Instruction::Store;
});

// If the next recipe is different, or if there are no other pairs,
// emit a remark for the collated subset. e.g.
// [(load, vf1), (load, vf2))]
// [(load, VF1), (load, VF2))]
// to emit:
// remark: invalid costs for 'load' at VF=(vf, vf2)
if (Subset == Tail || Tail[Subset.size()].first != I) {
// remark: invalid costs for 'load' at VF=(VF1, VF2)
if (Subset == Tail || Tail[Subset.size()].first != R) {
std::string OutString;
raw_string_ostream OS(OutString);
assert(!Subset.empty() && "Unexpected empty range");
OS << "Instruction with invalid costs prevented vectorization at VF=(";
OS << "Recipe with invalid costs prevented vectorization at VF=(";
for (const auto &Pair : Subset)
OS << (Pair.second == Subset.front().second ? "" : ", ") << Pair.second;
OS << "):";
if (auto *CI = dyn_cast<CallInst>(I))
OS << " call to " << CI->getCalledFunction()->getName();
else
OS << " " << I->getOpcodeName();
if (Opcode == Instruction::Call) {
auto *WidenCall = dyn_cast<VPWidenCallRecipe>(R);
Function *CalledFn =
WidenCall ? WidenCall->getCalledScalarFunction()
: cast<Function>(R->getOperand(R->getNumOperands() - 1)
->getLiveInIRValue());
OS << " call to " << CalledFn->getName();
} else
OS << " " << Instruction::getOpcodeName(Opcode);
OS.flush();
reportVectorizationInfo(OutString, "InvalidCost", ORE, TheLoop, I);
reportVectorizationInfo(OutString, "InvalidCost", ORE, OrigLoop, nullptr,
R->getDebugLoc());
Tail = Tail.drop_front(Subset.size());
Subset = {};
} else
Expand Down Expand Up @@ -4536,14 +4573,13 @@ VectorizationFactor LoopVectorizationPlanner::selectVectorizationFactor() {
ChosenFactor.Cost = InstructionCost::getMax();
}

SmallVector<InstructionVFPair> InvalidCosts;
for (auto &P : VPlans) {
for (ElementCount VF : P->vectorFactors()) {
// The cost for scalar VF=1 is already calculated, so ignore it.
if (VF.isScalar())
continue;

InstructionCost C = CM.expectedCost(VF, &InvalidCosts);
InstructionCost C = CM.expectedCost(VF);
VectorizationFactor Candidate(VF, C, ScalarCost.ScalarCost);

#ifndef NDEBUG
Expand Down Expand Up @@ -4578,8 +4614,6 @@ VectorizationFactor LoopVectorizationPlanner::selectVectorizationFactor() {
}
}

emitInvalidCostRemarks(InvalidCosts, ORE, OrigLoop);

if (!EnableCondStoresVectorization && CM.hasPredStores()) {
reportVectorizationFailure(
"There are conditional stores.",
Expand Down Expand Up @@ -5484,8 +5518,7 @@ InstructionCost LoopVectorizationCostModel::computePredInstDiscount(
return Discount;
}

InstructionCost LoopVectorizationCostModel::expectedCost(
ElementCount VF, SmallVectorImpl<InstructionVFPair> *Invalid) {
InstructionCost LoopVectorizationCostModel::expectedCost(ElementCount VF) {
InstructionCost Cost;

// For each block.
Expand All @@ -5505,10 +5538,6 @@ InstructionCost LoopVectorizationCostModel::expectedCost(
if (C.isValid() && ForceTargetInstructionCost.getNumOccurrences() > 0)
C = InstructionCost(ForceTargetInstructionCost);

// Keep a list of instructions with invalid costs.
if (Invalid && !C.isValid())
Invalid->emplace_back(&I, VF);

BlockCost += C;
LLVM_DEBUG(dbgs() << "LV: Found an estimated cost of " << C << " for VF "
<< VF << " For instruction: " << I << '\n');
Expand Down Expand Up @@ -9867,6 +9896,9 @@ bool LoopVectorizePass::processLoop(Loop *L) {
// Plan how to best vectorize, return the best VF and its cost.
std::optional<VectorizationFactor> MaybeVF = LVP.plan(UserVF, UserIC);

if (ORE->allowExtraAnalysis(LV_NAME))
LVP.emitInvalidCostRemarks(ORE);

VectorizationFactor VF = VectorizationFactor::Disabled();
unsigned IC = 1;

Expand Down Expand Up @@ -10029,7 +10061,6 @@ bool LoopVectorizePass::processLoop(Loop *L) {
EpilogueVectorizerMainLoop MainILV(L, PSE, LI, DT, TLI, TTI, AC, ORE,
EPI, &LVL, &CM, BFI, PSI, Checks);

assert(EPI.MainLoopVF == VF.Width && "VFs must match");
std::unique_ptr<VPlan> BestMainPlan(BestPlan.duplicate());
const auto &[ExpandedSCEVs, ReductionResumeValues] = LVP.executePlan(
EPI.MainLoopVF, EPI.MainLoopUF, *BestMainPlan, MainILV, DT, true);
Expand Down
23 changes: 20 additions & 3 deletions llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4842,10 +4842,27 @@ static bool clusterSortPtrAccesses(ArrayRef<Value *> VL, Type *ElemTy,
if (!AnyConsecutive)
return false;

for (auto &Base : Bases) {
for (auto &T : Base.second)
// If we have a better order, also sort the base pointers by increasing
// (variable) values if possible, to try and keep the order more regular.
SmallVector<std::pair<Value *, Value *>> SortedBases;
for (auto &Base : Bases)
SortedBases.emplace_back(Base.first,
Base.first->stripInBoundsConstantOffsets());
llvm::stable_sort(SortedBases, [](std::pair<Value *, Value *> V1,
std::pair<Value *, Value *> V2) {
const Value *V = V2.second;
while (auto *Gep = dyn_cast<GetElementPtrInst>(V)) {
if (Gep->getOperand(0) == V1.second)
return true;
V = Gep->getOperand(0);
}
return false;
});

// Collect the final order of sorted indices
for (auto Base : SortedBases)
for (auto &T : Bases[Base.first])
SortedIndices.push_back(std::get<2>(T));
}

assert(SortedIndices.size() == VL.size() &&
"Expected SortedIndices to be the size of VL");
Expand Down
481 changes: 319 additions & 162 deletions llvm/test/Analysis/CostModel/RISCV/rvv-load-store.ll

Large diffs are not rendered by default.

16 changes: 16 additions & 0 deletions llvm/test/CodeGen/AArch64/exp10-libcall-names.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,12 @@
; RUN: llc -mtriple=aarch64-apple-tvos6.0 < %s | FileCheck -check-prefix=APPLE %s
; RUN: llc -mtriple=aarch64-apple-xros6.0 < %s | FileCheck -check-prefix=APPLE %s
; RUN: llc -mtriple=aarch64-apple-xros1.0 < %s | FileCheck -check-prefix=APPLE %s
; RUN: llc -mtriple=arm64-apple-driverkit < %s | FileCheck -check-prefix=MISSED %s
; RUN: llc -mtriple=arm64-apple-driverkit1.0 < %s | FileCheck -check-prefix=MISSED %s
; RUN: llc -mtriple=arm64-apple-driverkit24.0 < %s | FileCheck -check-prefix=MISSED %s
; RUN: llc -mtriple=arm64-apple-bridgeos < %s | FileCheck -check-prefix=LINUX %s
; RUN: llc -mtriple=arm64-apple-bridgeos1.0 < %s | FileCheck -check-prefix=LINUX %s
; RUN: llc -mtriple=arm64-apple-bridgeos9.0 < %s | FileCheck -check-prefix=LINUX %s

; RUN: not llc -mtriple=aarch64-apple-macos10.8 -filetype=null %s 2>&1 | FileCheck -check-prefix=ERR %s
; RUN: not llc -mtriple=aarch64-apple-ios6.0 -filetype=null %s 2>&1 | FileCheck -check-prefix=ERR %s
Expand All @@ -23,6 +29,11 @@ define float @test_exp10_f32(float %x) {
; APPLE-LABEL: test_exp10_f32:
; APPLE: ; %bb.0:
; APPLE-NEXT: b ___exp10f
;
; MISSED-LABEL: test_exp10_f32:
; MISSED: ; %bb.0:
; MISSED-NEXT: b _exp10f
;
%ret = call float @llvm.exp10.f32(float %x)
ret float %ret
}
Expand All @@ -35,6 +46,11 @@ define double @test_exp10_f64(double %x) {
; APPLE-LABEL: test_exp10_f64:
; APPLE: ; %bb.0:
; APPLE-NEXT: b ___exp10
;
; MISSED-LABEL: test_exp10_f64:
; MISSED: ; %bb.0:
; MISSED-NEXT: b _exp10
;
%ret = call double @llvm.exp10.f64(double %x)
ret double %ret
}
100 changes: 51 additions & 49 deletions llvm/test/CodeGen/AArch64/ptrauth-fpac.ll
Original file line number Diff line number Diff line change
@@ -1,12 +1,14 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs | FileCheck %s --check-prefixes=ALL,NOFPAC
; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+fpac -verify-machineinstrs | FileCheck %s --check-prefixes=ALL,FPAC
; RUN: llc < %s -mtriple arm64e-apple-darwin -verify-machineinstrs | FileCheck %s -DL="L" --check-prefixes=ALL,NOFPAC
; RUN: llc < %s -mtriple arm64e-apple-darwin -mattr=+fpac -verify-machineinstrs | FileCheck %s -DL="L" --check-prefixes=ALL,FPAC
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -verify-machineinstrs | FileCheck %s -DL=".L" --check-prefixes=ALL,NOFPAC
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -mattr=+fpac -verify-machineinstrs | FileCheck %s -DL=".L" --check-prefixes=ALL,FPAC

target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"

define i64 @test_auth_ia(i64 %arg, i64 %arg1) {
; ALL-LABEL: test_auth_ia:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autia x16, x1
; ALL-NEXT: mov x0, x16
Expand All @@ -17,7 +19,7 @@ define i64 @test_auth_ia(i64 %arg, i64 %arg1) {

define i64 @test_auth_ia_zero(i64 %arg) {
; ALL-LABEL: test_auth_ia_zero:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autiza x16
; ALL-NEXT: mov x0, x16
Expand All @@ -28,7 +30,7 @@ define i64 @test_auth_ia_zero(i64 %arg) {

define i64 @test_auth_ib(i64 %arg, i64 %arg1) {
; ALL-LABEL: test_auth_ib:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autib x16, x1
; ALL-NEXT: mov x0, x16
Expand All @@ -39,7 +41,7 @@ define i64 @test_auth_ib(i64 %arg, i64 %arg1) {

define i64 @test_auth_ib_zero(i64 %arg) {
; ALL-LABEL: test_auth_ib_zero:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autizb x16
; ALL-NEXT: mov x0, x16
Expand All @@ -50,7 +52,7 @@ define i64 @test_auth_ib_zero(i64 %arg) {

define i64 @test_auth_da(i64 %arg, i64 %arg1) {
; ALL-LABEL: test_auth_da:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autda x16, x1
; ALL-NEXT: mov x0, x16
Expand All @@ -61,7 +63,7 @@ define i64 @test_auth_da(i64 %arg, i64 %arg1) {

define i64 @test_auth_da_zero(i64 %arg) {
; ALL-LABEL: test_auth_da_zero:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autdza x16
; ALL-NEXT: mov x0, x16
Expand All @@ -72,7 +74,7 @@ define i64 @test_auth_da_zero(i64 %arg) {

define i64 @test_auth_db(i64 %arg, i64 %arg1) {
; ALL-LABEL: test_auth_db:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autdb x16, x1
; ALL-NEXT: mov x0, x16
Expand All @@ -83,7 +85,7 @@ define i64 @test_auth_db(i64 %arg, i64 %arg1) {

define i64 @test_auth_db_zero(i64 %arg) {
; ALL-LABEL: test_auth_db_zero:
; ALL: ; %bb.0:
; ALL: %bb.0:
; ALL-NEXT: mov x16, x0
; ALL-NEXT: autdzb x16
; ALL-NEXT: mov x0, x16
Expand All @@ -96,23 +98,23 @@ define i64 @test_auth_db_zero(i64 %arg) {
; the validity of a signature.
define i64 @test_resign_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_ia_ia:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autia x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpaci x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_0
; NOFPAC-NEXT: b.eq [[L]]auth_success_0
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_0
; NOFPAC-NEXT: b [[L]]resign_end_0
; NOFPAC-NEXT: Lauth_success_0:
; NOFPAC-NEXT: pacia x16, x2
; NOFPAC-NEXT: Lresign_end_0:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_ia_ia:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autia x16, x1
; FPAC-NEXT: pacia x16, x2
Expand All @@ -124,23 +126,23 @@ define i64 @test_resign_ia_ia(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_ib_ia:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autib x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpaci x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_1
; NOFPAC-NEXT: b.eq [[L]]auth_success_1
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_1
; NOFPAC-NEXT: b [[L]]resign_end_1
; NOFPAC-NEXT: Lauth_success_1:
; NOFPAC-NEXT: pacia x16, x2
; NOFPAC-NEXT: Lresign_end_1:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_ib_ia:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autib x16, x1
; FPAC-NEXT: pacia x16, x2
Expand All @@ -152,23 +154,23 @@ define i64 @test_resign_ib_ia(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_da_ia(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_da_ia:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autda x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_2
; NOFPAC-NEXT: b.eq [[L]]auth_success_2
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_2
; NOFPAC-NEXT: b [[L]]resign_end_2
; NOFPAC-NEXT: Lauth_success_2:
; NOFPAC-NEXT: pacia x16, x2
; NOFPAC-NEXT: Lresign_end_2:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_da_ia:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autda x16, x1
; FPAC-NEXT: pacia x16, x2
Expand All @@ -180,23 +182,23 @@ define i64 @test_resign_da_ia(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_db_ia(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_db_ia:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autdb x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_3
; NOFPAC-NEXT: b.eq [[L]]auth_success_3
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_3
; NOFPAC-NEXT: b [[L]]resign_end_3
; NOFPAC-NEXT: Lauth_success_3:
; NOFPAC-NEXT: pacia x16, x2
; NOFPAC-NEXT: Lresign_end_3:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_db_ia:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autdb x16, x1
; FPAC-NEXT: pacia x16, x2
Expand All @@ -208,23 +210,23 @@ define i64 @test_resign_db_ia(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_db_ib(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_db_ib:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autdb x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_4
; NOFPAC-NEXT: b.eq [[L]]auth_success_4
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_4
; NOFPAC-NEXT: b [[L]]resign_end_4
; NOFPAC-NEXT: Lauth_success_4:
; NOFPAC-NEXT: pacib x16, x2
; NOFPAC-NEXT: Lresign_end_4:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_db_ib:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autdb x16, x1
; FPAC-NEXT: pacib x16, x2
Expand All @@ -236,23 +238,23 @@ define i64 @test_resign_db_ib(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_db_da(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_db_da:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autdb x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_5
; NOFPAC-NEXT: b.eq [[L]]auth_success_5
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_5
; NOFPAC-NEXT: b [[L]]resign_end_5
; NOFPAC-NEXT: Lauth_success_5:
; NOFPAC-NEXT: pacda x16, x2
; NOFPAC-NEXT: Lresign_end_5:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_db_da:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autdb x16, x1
; FPAC-NEXT: pacda x16, x2
Expand All @@ -264,23 +266,23 @@ define i64 @test_resign_db_da(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_db_db(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_db_db:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autdb x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_6
; NOFPAC-NEXT: b.eq [[L]]auth_success_6
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_6
; NOFPAC-NEXT: b [[L]]resign_end_6
; NOFPAC-NEXT: Lauth_success_6:
; NOFPAC-NEXT: pacdb x16, x2
; NOFPAC-NEXT: Lresign_end_6:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_db_db:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autdb x16, x1
; FPAC-NEXT: pacdb x16, x2
Expand All @@ -292,23 +294,23 @@ define i64 @test_resign_db_db(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_iza_db(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_iza_db:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autiza x16
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpaci x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_7
; NOFPAC-NEXT: b.eq [[L]]auth_success_7
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_7
; NOFPAC-NEXT: b [[L]]resign_end_7
; NOFPAC-NEXT: Lauth_success_7:
; NOFPAC-NEXT: pacdb x16, x2
; NOFPAC-NEXT: Lresign_end_7:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_iza_db:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autiza x16
; FPAC-NEXT: pacdb x16, x2
Expand All @@ -320,23 +322,23 @@ define i64 @test_resign_iza_db(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) {
; NOFPAC-LABEL: test_resign_da_dzb:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autda x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpacd x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_8
; NOFPAC-NEXT: b.eq [[L]]auth_success_8
; NOFPAC-NEXT: mov x16, x17
; NOFPAC-NEXT: b Lresign_end_8
; NOFPAC-NEXT: b [[L]]resign_end_8
; NOFPAC-NEXT: Lauth_success_8:
; NOFPAC-NEXT: pacdzb x16
; NOFPAC-NEXT: Lresign_end_8:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_resign_da_dzb:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autda x16, x1
; FPAC-NEXT: pacdzb x16
Expand All @@ -348,20 +350,20 @@ define i64 @test_resign_da_dzb(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_auth_trap_attribute(i64 %arg, i64 %arg1) "ptrauth-auth-traps" {
; NOFPAC-LABEL: test_auth_trap_attribute:
; NOFPAC: ; %bb.0:
; NOFPAC: %bb.0:
; NOFPAC-NEXT: mov x16, x0
; NOFPAC-NEXT: autia x16, x1
; NOFPAC-NEXT: mov x17, x16
; NOFPAC-NEXT: xpaci x17
; NOFPAC-NEXT: cmp x16, x17
; NOFPAC-NEXT: b.eq Lauth_success_9
; NOFPAC-NEXT: b.eq [[L]]auth_success_9
; NOFPAC-NEXT: brk #0xc470
; NOFPAC-NEXT: Lauth_success_9:
; NOFPAC-NEXT: mov x0, x16
; NOFPAC-NEXT: ret
;
; FPAC-LABEL: test_auth_trap_attribute:
; FPAC: ; %bb.0:
; FPAC: %bb.0:
; FPAC-NEXT: mov x16, x0
; FPAC-NEXT: autia x16, x1
; FPAC-NEXT: mov x0, x16
Expand Down
139 changes: 80 additions & 59 deletions llvm/test/CodeGen/AArch64/ptrauth-intrinsic-auth-resign-with-blend.ll
Original file line number Diff line number Diff line change
@@ -1,24 +1,39 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefixes=UNCHECKED,UNCHECKED-DARWIN
; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s --check-prefix=UNCHECKED
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL="L" --check-prefixes=UNCHECKED,UNCHECKED-DARWIN

; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \
; RUN: | FileCheck %s --check-prefix=CHECKED
; RUN: | FileCheck %s -DL="L" --check-prefixes=CHECKED,CHECKED-DARWIN
; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: | FileCheck %s --check-prefix=CHECKED
; RUN: | FileCheck %s -DL="L" --check-prefixes=CHECKED,CHECKED-DARWIN

; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel=0 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefixes=TRAP,TRAP-DARWIN
; RUN: llc < %s -mtriple arm64e-apple-darwin -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s --check-prefix=TRAP
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL="L" --check-prefixes=TRAP,TRAP-DARWIN

; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefixes=UNCHECKED,UNCHECKED-ELF
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=none | FileCheck %s -DL=".L" --check-prefixes=UNCHECKED,UNCHECKED-ELF

; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
; RUN: | FileCheck %s -DL=".L" --check-prefixes=CHECKED,CHECKED-ELF
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: | FileCheck %s -DL=".L" --check-prefixes=CHECKED,CHECKED-ELF

; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel=0 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefixes=TRAP,TRAP-ELF
; RUN: llc < %s -mtriple aarch64-linux-gnu -mattr=+pauth -global-isel -global-isel-abort=1 -verify-machineinstrs \
; RUN: -aarch64-ptrauth-auth-checks=trap | FileCheck %s -DL=".L" --check-prefixes=TRAP,TRAP-ELF

target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"

define i64 @test_auth_blend(i64 %arg, i64 %arg1) {
; UNCHECKED-LABEL: test_auth_blend:
; UNCHECKED: ; %bb.0:
; UNCHECKED: %bb.0:
; UNCHECKED-NEXT: mov x16, x0
; UNCHECKED-NEXT: mov x17, x1
; UNCHECKED-NEXT: movk x17, #65535, lsl #48
Expand All @@ -27,7 +42,7 @@ define i64 @test_auth_blend(i64 %arg, i64 %arg1) {
; UNCHECKED-NEXT: ret
;
; CHECKED-LABEL: test_auth_blend:
; CHECKED: ; %bb.0:
; CHECKED: %bb.0:
; CHECKED-NEXT: mov x16, x0
; CHECKED-NEXT: mov x17, x1
; CHECKED-NEXT: movk x17, #65535, lsl #48
Expand All @@ -36,15 +51,15 @@ define i64 @test_auth_blend(i64 %arg, i64 %arg1) {
; CHECKED-NEXT: ret
;
; TRAP-LABEL: test_auth_blend:
; TRAP: ; %bb.0:
; TRAP: %bb.0:
; TRAP-NEXT: mov x16, x0
; TRAP-NEXT: mov x17, x1
; TRAP-NEXT: movk x17, #65535, lsl #48
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq Lauth_success_0
; TRAP-NEXT: b.eq [[L]]auth_success_0
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_0:
; TRAP-NEXT: mov x0, x16
Expand All @@ -56,7 +71,7 @@ define i64 @test_auth_blend(i64 %arg, i64 %arg1) {

define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
; UNCHECKED-LABEL: test_resign_blend:
; UNCHECKED: ; %bb.0:
; UNCHECKED: %bb.0:
; UNCHECKED-NEXT: mov x16, x0
; UNCHECKED-NEXT: mov x17, x1
; UNCHECKED-NEXT: movk x17, #12345, lsl #48
Expand All @@ -68,17 +83,17 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
; UNCHECKED-NEXT: ret
;
; CHECKED-LABEL: test_resign_blend:
; CHECKED: ; %bb.0:
; CHECKED: %bb.0:
; CHECKED-NEXT: mov x16, x0
; CHECKED-NEXT: mov x17, x1
; CHECKED-NEXT: movk x17, #12345, lsl #48
; CHECKED-NEXT: autda x16, x17
; CHECKED-NEXT: mov x17, x16
; CHECKED-NEXT: xpacd x17
; CHECKED-NEXT: cmp x16, x17
; CHECKED-NEXT: b.eq Lauth_success_0
; CHECKED-NEXT: b.eq [[L]]auth_success_0
; CHECKED-NEXT: mov x16, x17
; CHECKED-NEXT: b Lresign_end_0
; CHECKED-NEXT: b [[L]]resign_end_0
; CHECKED-NEXT: Lauth_success_0:
; CHECKED-NEXT: mov x17, x2
; CHECKED-NEXT: movk x17, #56789, lsl #48
Expand All @@ -88,15 +103,15 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {
; CHECKED-NEXT: ret
;
; TRAP-LABEL: test_resign_blend:
; TRAP: ; %bb.0:
; TRAP: %bb.0:
; TRAP-NEXT: mov x16, x0
; TRAP-NEXT: mov x17, x1
; TRAP-NEXT: movk x17, #12345, lsl #48
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq Lauth_success_1
; TRAP-NEXT: b.eq [[L]]auth_success_1
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_1:
; TRAP-NEXT: mov x17, x2
Expand All @@ -112,48 +127,48 @@ define i64 @test_resign_blend(i64 %arg, i64 %arg1, i64 %arg2) {

define i64 @test_resign_blend_and_const(i64 %arg, i64 %arg1) {
; UNCHECKED-LABEL: test_resign_blend_and_const:
; UNCHECKED: ; %bb.0:
; UNCHECKED: %bb.0:
; UNCHECKED-NEXT: mov x16, x0
; UNCHECKED-NEXT: mov x17, x1
; UNCHECKED-NEXT: movk x17, #12345, lsl #48
; UNCHECKED-NEXT: autda x16, x17
; UNCHECKED-NEXT: mov x17, #56789 ; =0xddd5
; UNCHECKED-NEXT: mov x17, #56789
; UNCHECKED-NEXT: pacdb x16, x17
; UNCHECKED-NEXT: mov x0, x16
; UNCHECKED-NEXT: ret
;
; CHECKED-LABEL: test_resign_blend_and_const:
; CHECKED: ; %bb.0:
; CHECKED: %bb.0:
; CHECKED-NEXT: mov x16, x0
; CHECKED-NEXT: mov x17, x1
; CHECKED-NEXT: movk x17, #12345, lsl #48
; CHECKED-NEXT: autda x16, x17
; CHECKED-NEXT: mov x17, x16
; CHECKED-NEXT: xpacd x17
; CHECKED-NEXT: cmp x16, x17
; CHECKED-NEXT: b.eq Lauth_success_1
; CHECKED-NEXT: b.eq [[L]]auth_success_1
; CHECKED-NEXT: mov x16, x17
; CHECKED-NEXT: b Lresign_end_1
; CHECKED-NEXT: b [[L]]resign_end_1
; CHECKED-NEXT: Lauth_success_1:
; CHECKED-NEXT: mov x17, #56789 ; =0xddd5
; CHECKED-NEXT: mov x17, #56789
; CHECKED-NEXT: pacdb x16, x17
; CHECKED-NEXT: Lresign_end_1:
; CHECKED-NEXT: mov x0, x16
; CHECKED-NEXT: ret
;
; TRAP-LABEL: test_resign_blend_and_const:
; TRAP: ; %bb.0:
; TRAP: %bb.0:
; TRAP-NEXT: mov x16, x0
; TRAP-NEXT: mov x17, x1
; TRAP-NEXT: movk x17, #12345, lsl #48
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq Lauth_success_2
; TRAP-NEXT: b.eq [[L]]auth_success_2
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_2:
; TRAP-NEXT: mov x17, #56789 ; =0xddd5
; TRAP-NEXT: mov x17, #56789
; TRAP-NEXT: pacdb x16, x17
; TRAP-NEXT: mov x0, x16
; TRAP-NEXT: ret
Expand All @@ -164,7 +179,7 @@ define i64 @test_resign_blend_and_const(i64 %arg, i64 %arg1) {

define i64 @test_resign_blend_and_addr(i64 %arg, i64 %arg1, i64 %arg2) {
; UNCHECKED-LABEL: test_resign_blend_and_addr:
; UNCHECKED: ; %bb.0:
; UNCHECKED: %bb.0:
; UNCHECKED-NEXT: mov x16, x0
; UNCHECKED-NEXT: mov x17, x1
; UNCHECKED-NEXT: movk x17, #12345, lsl #48
Expand All @@ -174,33 +189,33 @@ define i64 @test_resign_blend_and_addr(i64 %arg, i64 %arg1, i64 %arg2) {
; UNCHECKED-NEXT: ret
;
; CHECKED-LABEL: test_resign_blend_and_addr:
; CHECKED: ; %bb.0:
; CHECKED: %bb.0:
; CHECKED-NEXT: mov x16, x0
; CHECKED-NEXT: mov x17, x1
; CHECKED-NEXT: movk x17, #12345, lsl #48
; CHECKED-NEXT: autda x16, x17
; CHECKED-NEXT: mov x17, x16
; CHECKED-NEXT: xpacd x17
; CHECKED-NEXT: cmp x16, x17
; CHECKED-NEXT: b.eq Lauth_success_2
; CHECKED-NEXT: b.eq [[L]]auth_success_2
; CHECKED-NEXT: mov x16, x17
; CHECKED-NEXT: b Lresign_end_2
; CHECKED-NEXT: b [[L]]resign_end_2
; CHECKED-NEXT: Lauth_success_2:
; CHECKED-NEXT: pacdb x16, x2
; CHECKED-NEXT: Lresign_end_2:
; CHECKED-NEXT: mov x0, x16
; CHECKED-NEXT: ret
;
; TRAP-LABEL: test_resign_blend_and_addr:
; TRAP: ; %bb.0:
; TRAP: %bb.0:
; TRAP-NEXT: mov x16, x0
; TRAP-NEXT: mov x17, x1
; TRAP-NEXT: movk x17, #12345, lsl #48
; TRAP-NEXT: autda x16, x17
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq Lauth_success_3
; TRAP-NEXT: b.eq [[L]]auth_success_3
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_3:
; TRAP-NEXT: pacdb x16, x2
Expand All @@ -212,38 +227,44 @@ define i64 @test_resign_blend_and_addr(i64 %arg, i64 %arg1, i64 %arg2) {
}

define i64 @test_auth_too_large_discriminator(i64 %arg, i64 %arg1) {
; UNCHECKED-LABEL: test_auth_too_large_discriminator:
; UNCHECKED: ; %bb.0:
; UNCHECKED-NEXT: mov w8, #65536 ; =0x10000
; UNCHECKED-NEXT: bfi x1, x8, #48, #16
; UNCHECKED-NEXT: mov x16, x0
; UNCHECKED-NEXT: autda x16, x1
; UNCHECKED-NEXT: mov x0, x16
; UNCHECKED-NEXT: ret
; UNCHECKED-LABEL: test_auth_too_large_discriminator:
; UNCHECKED: %bb.0:
; UNCHECKED-NEXT: mov w8, #65536
; UNCHECKED-DARWIN-NEXT: bfi x1, x8, #48, #16
; UNCHECKED-DARWIN-NEXT: mov x16, x0
; UNCHECKED-ELF-NEXT: mov x16, x0
; UNCHECKED-ELF-NEXT: bfi x1, x8, #48, #16
; UNCHECKED-NEXT: autda x16, x1
; UNCHECKED-NEXT: mov x0, x16
; UNCHECKED-NEXT: ret
;
; CHECKED-LABEL: test_auth_too_large_discriminator:
; CHECKED: ; %bb.0:
; CHECKED-NEXT: mov w8, #65536 ; =0x10000
; CHECKED-NEXT: bfi x1, x8, #48, #16
; CHECKED-NEXT: mov x16, x0
; CHECKED-NEXT: autda x16, x1
; CHECKED-NEXT: mov x0, x16
; CHECKED-NEXT: ret
; CHECKED: %bb.0:
; CHECKED-NEXT: mov w8, #65536
; CHECKED-DARWIN-NEXT: bfi x1, x8, #48, #16
; CHECKED-DARWIN-NEXT: mov x16, x0
; CHECKED-ELF-NEXT: mov x16, x0
; CHECKED-ELF-NEXT: bfi x1, x8, #48, #16
; CHECKED-NEXT: autda x16, x1
; CHECKED-NEXT: mov x0, x16
; CHECKED-NEXT: ret
;
; TRAP-LABEL: test_auth_too_large_discriminator:
; TRAP: ; %bb.0:
; TRAP-NEXT: mov w8, #65536 ; =0x10000
; TRAP-NEXT: bfi x1, x8, #48, #16
; TRAP-NEXT: mov x16, x0
; TRAP-NEXT: autda x16, x1
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq Lauth_success_4
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_4:
; TRAP-NEXT: mov x0, x16
; TRAP-NEXT: ret
; TRAP: %bb.0:
; TRAP-NEXT: mov w8, #65536
; TRAP-DARWIN-NEXT: bfi x1, x8, #48, #16
; TRAP-DARWIN-NEXT: mov x16, x0
; TRAP-ELF-NEXT: mov x16, x0
; TRAP-ELF-NEXT: bfi x1, x8, #48, #16
; TRAP-NEXT: autda x16, x1
; TRAP-NEXT: mov x17, x16
; TRAP-NEXT: xpacd x17
; TRAP-NEXT: cmp x16, x17
; TRAP-NEXT: b.eq [[L]]auth_success_4
; TRAP-NEXT: brk #0xc472
; TRAP-NEXT: Lauth_success_4:
; TRAP-NEXT: mov x0, x16
; TRAP-NEXT: ret
%tmp0 = call i64 @llvm.ptrauth.blend(i64 %arg1, i64 65536)
%tmp1 = call i64 @llvm.ptrauth.auth(i64 %arg, i32 2, i64 %tmp0)
ret i64 %tmp1
Expand Down
Loading