Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Mips] Fix missing sign extension in expansion of sub-word atomic max #77072

Merged
merged 1 commit into from
Mar 8, 2024

Conversation

yingopq
Copy link
Contributor

@yingopq yingopq commented Jan 5, 2024

Add sign extension "SEB/SEH" before compare.

Fix #61881

Copy link

github-actions bot commented Jan 5, 2024

✅ With the latest revision this PR passed the C/C++ code formatter.

@brad0 brad0 requested review from jyknight and topperc January 6, 2024 08:48
@yingopq yingopq force-pushed the Fix_bug_61881 branch 2 times, most recently from 0cdecec to d96c168 Compare January 8, 2024 02:39
@yingopq
Copy link
Contributor Author

yingopq commented Jan 8, 2024

@topperc Could you help review this patch? Thanks.

@brad0
Copy link
Contributor

brad0 commented Jan 14, 2024

@topperc @jyknight Ping.

@brad0 brad0 requested a review from MaskRay January 20, 2024 05:04
@yingopq
Copy link
Contributor Author

yingopq commented Jan 23, 2024

@topperc Hello, could you help review this patch at your convenience? Thanks.

@yingopq
Copy link
Contributor Author

yingopq commented Feb 4, 2024

@MaskRay Hello, could you help review this patch at your convenience? Thanks.

@brad0
Copy link
Contributor

brad0 commented Feb 8, 2024

@MaskRay ?

@brad0
Copy link
Contributor

brad0 commented Feb 14, 2024

@yingopq Ping.

@brad0
Copy link
Contributor

brad0 commented Feb 24, 2024

@topperc @MaskRay

1 similar comment
@brad0
Copy link
Contributor

brad0 commented Feb 27, 2024

@topperc @MaskRay

; MIPS32-NEXT: $BB4_1: # %entry
; MIPS32-NEXT: # =>This Inner Loop Header: Depth=1
; MIPS32-NEXT: ll $2, 0($6)
; MIPS32-NEXT: and $2, $2, $8
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Are these and instructions needed? The srav will move the 16 bit chunk to the LSBs, then the sll+sra pair will fill the upper 16 bits with the sign of the lower 16 bits. Doesn't seem like anything needs ANDed before hand.

@brad0
Copy link
Contributor

brad0 commented Mar 8, 2024

@topperc

Copy link
Collaborator

@topperc topperc left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@brad0 brad0 merged commit 755b439 into llvm:main Mar 8, 2024
4 checks passed
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 8, 2024
…llvm#77072)

Add sign extension "SEB/SEH" before compare.

Fix llvm#61881

(cherry picked from commit 755b439)
llvmbot pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 24, 2024
…llvm#77072)

Add sign extension "SEB/SEH" before compare.

Fix llvm#61881

(cherry picked from commit 755b439)
tstellar pushed a commit to llvmbot/llvm-project that referenced this pull request Mar 27, 2024
…llvm#77072)

Add sign extension "SEB/SEH" before compare.

Fix llvm#61881

(cherry picked from commit 755b439)
@martn3
Copy link

martn3 commented Apr 11, 2024

Hello, I started to see MIPS failures in the Rust standard library tests after this change. For example, this program begins to fail after this change:

fn main() {
    let x = std::sync::atomic::AtomicI8::new(23);
    assert_eq!(x.fetch_max(42, std::sync::atomic::Ordering::SeqCst), 23);
}

Please see rust-lang/rust#123772 for more details.

This seems quite problematic, so please let me know if I can help investigate this somehow.

@yingopq
Copy link
Contributor Author

yingopq commented Apr 11, 2024

Hello, I started to see MIPS failures in the Rust standard library tests after this change. For example, this program begins to fail after this change:

fn main() {
    let x = std::sync::atomic::AtomicI8::new(23);
    assert_eq!(x.fetch_max(42, std::sync::atomic::Ordering::SeqCst), 23);
}

Please see rust-lang/rust#123772 for more details.

This seems quite problematic, so please let me know if I can help investigate this somehow.

hi, please use code 0e501db to test again, because we submit another patch after fbb27d1. This issue include two patch.
Thanks, please let me know if you have any other questions.

@nikic
Copy link
Contributor

nikic commented Apr 11, 2024

@yingopq As I understand it, this was reproduced with the release/18.x branch (or rust's fork, which is essentially the same), which already contains that second commit as well.

@yingopq
Copy link
Contributor Author

yingopq commented Apr 11, 2024

@yingopq As I understand it, this was reproduced with the release/18.x branch (or rust's fork, which is essentially the same), which already contains that second commit as well.

In rust-lang/rust#123772, he comments With src/llvm-project pointing to https://github.com/llvm/llvm-project/commit/fbb27d16fa12aa595cbd20a1fb5f1c5b80748fa4 the test also fails, but when pointing src/llvm-project to the parent commit (https://github.com/llvm/llvm-project/commit/e74c1678231ab2a7c6defe8bb90366e664780d6f) the test passes.. So I reply him use code 0e501db

@martn3
Copy link

martn3 commented Apr 11, 2024

Hi @yingopq, thank you for the reply and for the tip. I double-checked, and I get the test failure also with 0e501db. I also tested some extra commits just to be sure. Here are my results:

Commit Commit info Commit Title Test result
dc39028 branch main [mlir] Fix -Wsign-compare in ValueBoundsOpInterface.cpp (NFC) Fail
b6ebea7 branch release/18.x [SPARC] Implement L and H inline asm argument modifiers Fail
7c7c3d4 tag llvmorg-18.1.2 + 13 [ODS][NFC] Cast range.size() to int32_t in accumulation Fail
0e501db tag llvmorg-18.1.2 + 12 [Mips] Restore wrong deletion of instruction 'and' in unsigned min/max processing. Fail
fbb27d1 tag llvmorg-18.1.2 + 11 [Mips] Fix missing sign extension in expansion of sub-word atomic max Fail
e74c167 tag llvmorg-18.1.2 + 10 [PowerPC] provide CFI for ELF32 to unwind cr2, cr3, cr4 OK
1c7c16e tag llvmorg-18.1.2 + 9 [NFC][PowerPC] use script to regenerate the CHECK lines OK

Please let me know if you would like me to perform more tests.

@yingopq
Copy link
Contributor Author

yingopq commented Apr 11, 2024

Hi @yingopq, thank you for the reply and for the tip. I double-checked, and I get the test failure also with 0e501db. I also tested some extra commits just to be sure. Here are my results:

Commit Commit info Commit Title Test result
dc39028 branch main [mlir] Fix -Wsign-compare in ValueBoundsOpInterface.cpp (NFC) Fail
b6ebea7 branch release/18.x [SPARC] Implement L and H inline asm argument modifiers Fail
7c7c3d4 tag llvmorg-18.1.2 + 13 [ODS][NFC] Cast range.size() to int32_t in accumulation Fail
0e501db tag llvmorg-18.1.2 + 12 [Mips] Restore wrong deletion of instruction 'and' in unsigned min/max processing. Fail
fbb27d1 tag llvmorg-18.1.2 + 11 [Mips] Fix missing sign extension in expansion of sub-word atomic max Fail
e74c167 tag llvmorg-18.1.2 + 10 [PowerPC] provide CFI for ELF32 to unwind cr2, cr3, cr4 OK
1c7c16e tag llvmorg-18.1.2 + 9 [NFC][PowerPC] use script to regenerate the CHECK lines OK
Please let me know if you would like me to perform more tests.

Thanks, I would check it.

@DianQK
Copy link
Member

DianQK commented Apr 12, 2024

I have reduced to the following code:

target datalayout = "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64"
target triple = "mipsel-unknown-linux-gnu"

define i32 @main() {
  %1 = call signext i8 @test()
  %2 = sext i8 %1 to i32
  ret i32 %2
}

define signext i8 @test() {
  %i = alloca i8, align 1
  store i8 23, ptr %i, align 1
  %i1 = atomicrmw max ptr %i, i8 42 seq_cst, align 1
  ret i8 %i1
}

https://llvm.godbolt.org/z/4Mxnc1Eda

@yingopq I hope this can be of some use.

There might be no need to create a variable:

define i8 @test(ptr %arg) {
  %i6 = atomicrmw max ptr %arg, i8 42 seq_cst, align 1
  ret i8 %i6
}

@DianQK
Copy link
Member

DianQK commented Apr 13, 2024

Clarify: I don't have any knowledge about MIPS, and the following is only confirmed from the output logs. Please correct me if there is any mistake. :)

TL;DR: All issues have been fixed in LLVM 17. This appears to be an incorrect patch; we might consider reverting it. But I hope @yingopq and others can come to confirm this.

Consider the following two pieces of code:

; v1.ll https://github.com/rust-lang/rust/issues/100650
define i8 @test(ptr %arg) {
  %i6 = atomicrmw max ptr %arg, i8 -25 seq_cst, align 1
  %i7 = load atomic i8, ptr %arg seq_cst, align 1
  ret i8 %i7
}

define i32 @main() {
  %i = alloca i8, align 1
  store i8 30, ptr %i, align 1
  %1 = call i8 @test(ptr %i)
  %2 = sext i8 %1 to i32
  ret i32 %2
}

and

; v2.ll https://github.com/rust-lang/rust/issues/123772
define i8 @test(ptr %arg) {
  %i6 = atomicrmw max ptr %arg, i8 42 seq_cst, align 1
  ret i8 %i6
}

define i32 @main() {
  %i = alloca i8, align 1
  store i8 23, ptr %i, align 1
  %1 = call signext i8 @test(ptr %i)
  %2 = sext i8 %1 to i32
  ret i32 %2
}

I can confirm that the return value of v2.ll from llvmorg-17-init to 18.1.2 is always 23. However, starting from 18.1.3, it changes to 0.
For v1.ll, starting with the commit c65b4d6, the return value changes from 231 to 30. However, starting from 18.1.3, it also changes to 0.

This is my verification script:

LLC=path/llc
MIPSEL_GCC=path/mipsel-unknown-linux-gnu-gcc

$LLC -march=mipsel -O0 -mcpu=mips32 -verify-machineinstrs v1.ll -filetype=obj -o v1.o
$MIPSEL_GCC -o v1 v1.o
qemu-mipsel v1
mipsel=$?
$LLC -O0 -march=x86-64 v1.ll -filetype=obj -o v1.o
clang -o v1 v1.o
./v1
x86=$?
echo "v1: $mipsel == $x86"

$LLC -march=mipsel -O0 -mcpu=mips32 -verify-machineinstrs v2.ll -filetype=obj -o v2.o
$MIPSEL_GCC -o v2 v2.o
qemu-mipsel v2
mipsel=$?
$LLC -O0 -march=x86-64 v2.ll -filetype=obj -o v2.o
clang -o v2 v2.o
./v2
x86=$?
if [ "$mipsel" != "$x86" ]; then
  bad=$((bad + 1))
fi
echo "v2: $mipsel == $x86"

@yingopq
Copy link
Contributor Author

yingopq commented Apr 15, 2024

Clarify: I don't have any knowledge about MIPS, and the following is only confirmed from the output logs. Please correct me if there is any mistake. :)

TL;DR: All issues have been fixed in LLVM 17. This appears to be an incorrect patch; we might consider reverting it. But I hope @yingopq and others can come to confirm this.

Consider the following two pieces of code:

; v1.ll https://github.com/rust-lang/rust/issues/100650
define i8 @test(ptr %arg) {
  %i6 = atomicrmw max ptr %arg, i8 -25 seq_cst, align 1
  %i7 = load atomic i8, ptr %arg seq_cst, align 1
  ret i8 %i7
}

define i32 @main() {
  %i = alloca i8, align 1
  store i8 30, ptr %i, align 1
  %1 = call i8 @test(ptr %i)
  %2 = sext i8 %1 to i32
  ret i32 %2
}

and

; v2.ll https://github.com/rust-lang/rust/issues/123772
define i8 @test(ptr %arg) {
  %i6 = atomicrmw max ptr %arg, i8 42 seq_cst, align 1
  ret i8 %i6
}

define i32 @main() {
  %i = alloca i8, align 1
  store i8 23, ptr %i, align 1
  %1 = call signext i8 @test(ptr %i)
  %2 = sext i8 %1 to i32
  ret i32 %2
}

I can confirm that the return value of v2.ll from llvmorg-17-init to 18.1.2 is always 23. However, starting from 18.1.3, it changes to 0. For v1.ll, starting with the commit c65b4d6, the return value changes from 231 to 30. However, starting from 18.1.3, it also changes to 0.

This is my verification script:

LLC=path/llc
MIPSEL_GCC=path/mipsel-unknown-linux-gnu-gcc

$LLC -march=mipsel -O0 -mcpu=mips32 -verify-machineinstrs v1.ll -filetype=obj -o v1.o
$MIPSEL_GCC -o v1 v1.o
qemu-mipsel v1
mipsel=$?
$LLC -O0 -march=x86-64 v1.ll -filetype=obj -o v1.o
clang -o v1 v1.o
./v1
x86=$?
echo "v1: $mipsel == $x86"

$LLC -march=mipsel -O0 -mcpu=mips32 -verify-machineinstrs v2.ll -filetype=obj -o v2.o
$MIPSEL_GCC -o v2 v2.o
qemu-mipsel v2
mipsel=$?
$LLC -O0 -march=x86-64 v2.ll -filetype=obj -o v2.o
clang -o v2 v2.o
./v2
x86=$?
if [ "$mipsel" != "$x86" ]; then
  bad=$((bad + 1))
fi
echo "v2: $mipsel == $x86"

Thanks for your detail comment.
The reason about submitting this patch is that code did not do correct sign extension. And when I verify this patch, I use %i = alloca i32, align 4, so did not find the current issue you found. And I am investigating.

@DianQK
Copy link
Member

DianQK commented Apr 15, 2024

Thank you very much for looking into it. Would you mind temporarily reverting these two commits? :>

nikic added a commit to nikic/llvm-project that referenced this pull request Apr 16, 2024
…omic max (llvm#77072)"

These changes caused correctness regressions observed in Rust,
see
llvm#77072 (comment).

This reverts commit 0e501db.
This reverts commit fbb27d1.
@topperc
Copy link
Collaborator

topperc commented Apr 16, 2024

There's definitely an issue in this sequence

; MIPSEL-NEXT:    srav $2, $2, $10
; MIPSEL-NEXT:    srav $7, $7, $10
; MIPSEL-NEXT:    seh $2, $2
; MIPSEL-NEXT:    seh $7, $7
; MIPSEL-NEXT:    slt $5, $2, $7
; MIPSEL-NEXT:    move $3, $2
; MIPSEL-NEXT:    movn $3, $7, $5

The move and movn need to use the values in $2 and $7 before the srav and seh. The rest of the code expect the 16 bit value to be in the same place in the register as it was when it came out of the load.

tstellar pushed a commit to nikic/llvm-project that referenced this pull request Apr 16, 2024
…omic max (llvm#77072)"

These changes caused correctness regressions observed in Rust,
see
llvm#77072 (comment).

This reverts commit 0e501db.
This reverts commit fbb27d1.
@yingopq
Copy link
Contributor Author

yingopq commented Apr 17, 2024

There's definitely an issue in this sequence

; MIPSEL-NEXT:    srav $2, $2, $10
; MIPSEL-NEXT:    srav $7, $7, $10
; MIPSEL-NEXT:    seh $2, $2
; MIPSEL-NEXT:    seh $7, $7
; MIPSEL-NEXT:    slt $5, $2, $7
; MIPSEL-NEXT:    move $3, $2
; MIPSEL-NEXT:    movn $3, $7, $5

The move and movn need to use the values in $2 and $7 before the srav and seh. The rest of the code expect the 16 bit value to be in the same place in the register as it was when it came out of the load.

@topperc Thanks so much for pointing out the key to the problem, and I have verified that this is indeed the problem. I would submit patch again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[MIPS] Incorrect expansion of sub-word signed atomic max
6 participants