Skip to content

[SPIRV] Audit select Result in SPIRVInstructionSelector #115193

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

Merged
merged 5 commits into from
Nov 12, 2024

Conversation

inbelic
Copy link
Contributor

@inbelic inbelic commented Nov 6, 2024

  • as per the definition of select in GlobalISel/InstructionSelector.h the return value is a boolean denoting if the select was successful
  • doing Result |= is incorrect as all inserted instructions should be succesful, hence we change to using Result &=
  • ensure that the return value of all BuildMI instructions are propagated correctly

- as per the definition of `select` in GlobalISel/InstructionSelector.h
the return value is a boolean denoting if the select was successful

- doing `Result |=` is incorrect as all inserted instructions should be
succesful, hence we change to using `Result &=`
@inbelic inbelic marked this pull request as ready for review November 6, 2024 19:04
@llvmbot
Copy link
Member

llvmbot commented Nov 6, 2024

@llvm/pr-subscribers-backend-spir-v

Author: Finn Plummer (inbelic)

Changes
  • as per the definition of select in GlobalISel/InstructionSelector.h the return value is a boolean denoting if the select was successful

  • doing Result |= is incorrect as all inserted instructions should be succesful, hence we change to using Result &=


Full diff: https://github.com/llvm/llvm-project/pull/115193.diff

1 Files Affected:

  • (modified) llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp (+13-13)
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index be38b22f70c583..f5b9ca939ba898 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -1082,16 +1082,16 @@ bool SPIRVInstructionSelector::selectAtomicRMW(Register ResVReg,
   uint32_t MemSem = static_cast<uint32_t>(getMemSemantics(AO));
   Register MemSemReg = buildI32Constant(MemSem /*| ScSem*/, I);
 
-  bool Result = false;
+  bool Result = true;
   Register ValueReg = I.getOperand(2).getReg();
   if (NegateOpcode != 0) {
     // Translation with negative value operand is requested
     Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
-    Result |= selectUnOpWithSrc(TmpReg, ResType, I, ValueReg, NegateOpcode);
+    Result &= selectUnOpWithSrc(TmpReg, ResType, I, ValueReg, NegateOpcode);
     ValueReg = TmpReg;
   }
 
-  Result |= BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
+  Result &= BuildMI(*I.getParent(), I, I.getDebugLoc(), TII.get(NewOpcode))
                 .addDef(ResVReg)
                 .addUse(GR.getSPIRVTypeID(ResType))
                 .addUse(Ptr)
@@ -1264,21 +1264,21 @@ bool SPIRVInstructionSelector::selectAtomicCmpXchg(Register ResVReg,
           .constrainAllUses(TII, TRI, RBI);
   Register CmpSuccReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
   SPIRVType *BoolTy = GR.getOrCreateSPIRVBoolType(I, TII);
-  Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
+  Result &= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpIEqual))
                 .addDef(CmpSuccReg)
                 .addUse(GR.getSPIRVTypeID(BoolTy))
                 .addUse(ACmpRes)
                 .addUse(Cmp)
                 .constrainAllUses(TII, TRI, RBI);
   Register TmpReg = MRI->createVirtualRegister(&SPIRV::iIDRegClass);
-  Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
+  Result &= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
                 .addDef(TmpReg)
                 .addUse(GR.getSPIRVTypeID(ResType))
                 .addUse(ACmpRes)
                 .addUse(GR.getOrCreateUndef(I, ResType, TII))
                 .addImm(0)
                 .constrainAllUses(TII, TRI, RBI);
-  Result |= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
+  Result &= BuildMI(*I.getParent(), I, DL, TII.get(SPIRV::OpCompositeInsert))
                 .addDef(ResVReg)
                 .addUse(GR.getSPIRVTypeID(ResType))
                 .addUse(CmpSuccReg)
@@ -1784,7 +1784,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
   assert(I.getOperand(4).isReg());
   MachineBasicBlock &BB = *I.getParent();
 
-  bool Result = false;
+  bool Result = true;
 
   // Acc = C
   Register Acc = I.getOperand(4).getReg();
@@ -1796,7 +1796,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
   for (unsigned i = 0; i < 4; i++) {
     // A[i]
     Register AElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
-    Result |= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
+    Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
                   .addDef(AElt)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(I.getOperand(2).getReg())
@@ -1806,7 +1806,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
 
     // B[i]
     Register BElt = MRI->createVirtualRegister(&SPIRV::IDRegClass);
-    Result |= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
+    Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
                   .addDef(BElt)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(I.getOperand(3).getReg())
@@ -1816,7 +1816,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
 
     // A[i] * B[i]
     Register Mul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
-    Result |= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS))
+    Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIMulS))
                   .addDef(Mul)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(AElt)
@@ -1825,7 +1825,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
 
     // Discard 24 highest-bits so that stored i32 register is i8 equivalent
     Register MaskMul = MRI->createVirtualRegister(&SPIRV::IDRegClass);
-    Result |= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
+    Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(ExtractOp))
                   .addDef(MaskMul)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(Mul)
@@ -1836,7 +1836,7 @@ bool SPIRVInstructionSelector::selectDot4AddPackedExpansion(
     // Acc = Acc + A[i] * B[i]
     Register Sum =
         i < 3 ? MRI->createVirtualRegister(&SPIRV::IDRegClass) : ResVReg;
-    Result |= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
+    Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpIAddS))
                   .addDef(Sum)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(Acc)
@@ -1907,7 +1907,7 @@ bool SPIRVInstructionSelector::selectSign(Register ResVReg,
 
   if (NeedsConversion) {
     auto ConvertOpcode = IsFloatTy ? SPIRV::OpConvertFToS : SPIRV::OpSConvert;
-    Result |= BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
+    Result &= BuildMI(*I.getParent(), I, DL, TII.get(ConvertOpcode))
                   .addDef(ResVReg)
                   .addUse(GR.getSPIRVTypeID(ResType))
                   .addUse(SignReg)

Copy link
Contributor

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

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

These changes all look good. There are a few instances of BuildMI being called without the result being read or otherwise used that you might consider while you're at it. I don't know why they would fail, but I don't know specifically why any of these would fail, but if they do, it should be passed up.

inbelic and others added 2 commits November 6, 2024 21:39
- propogate all BuildMI returns up

propogate the buildmi result in buildI32Constant
@inbelic
Copy link
Contributor Author

inbelic commented Nov 6, 2024

Merged to get the splat test failure fix

@inbelic inbelic requested a review from farzonl November 6, 2024 22:01
Copy link
Contributor

@spall spall left a comment

Choose a reason for hiding this comment

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

Wow its hard to see the nesting on some of these with the diffs.

}
// Build boolean value from the higher part.
Status &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
Result &= BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpINotEqual))
Copy link
Contributor

Choose a reason for hiding this comment

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

I would do 'return Result && BuildMI', instead of returning later.

- make result return consistent to use return Result && when applicable
Copy link
Contributor

@pow2clk pow2clk left a comment

Choose a reason for hiding this comment

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

Looks good!

I was reminded that have a half-finished change that made a similar cleanup attempt, but it wasn't as complete as what you did.

else {
auto MemSemNeqConstant = buildI32Constant(MemSemEq, I);
MemSemNeqReg = MemSemNeqConstant.first;
Result &= MemSemNeqConstant.second;
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not going to insist on it, but just FYI, you could have made buildI32Constant return Register() in the failing case, which could be identified by checking Register.isValid() rather than returning an additional bool. It might have made this a little more elegant, but I'm not sure about that and it's entirely a non-functional change, so I'll happily defer to the implementer here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I agree it would be more elegant.

But from scanning the file, there doesn't seem to be a consistent precedent to checking a register's validity before use. In particular the returns of similar functions buildZerosVal and BuildOnesVal. I think to differentiate from those functions, and to ensure the result is checked in future calls we should explicitly return the type.

This might be a good reason to also audit the use of returned Registers, which I think is out of scope for this pr. Then we could switch to returning an invalid Register.

So I will merge as-is.

@inbelic inbelic merged commit a93cbd4 into llvm:main Nov 12, 2024
9 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Nov 12, 2024

LLVM Buildbot has detected a new failure on builder bolt-aarch64-ubuntu-clang-shared running on bolt-worker-aarch64 while building llvm at step 9 "test-build-bolt-check-large-bolt".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/126/builds/1073

Here is the relevant piece of the build log for the reference
Step 9 (test-build-bolt-check-large-bolt) failure: test (failure)
******************** TEST 'bolt-tests :: X86/split-func-icf.test' FAILED ********************
Exit Code: 1

Command Output (stderr):
--
RUN: at line 4: /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-nm /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata | grep \.cold |    /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-NM
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-NM
+ grep .cold
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-nm /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata
RUN: at line 10: /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null -v=1 |& /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-NOSKIP
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null -v=1
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-NOSKIP
RUN: at line 16: /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null    -skip-funcs=je_malloc_vsnprintf -v=1 |&  /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-SKIP-PARENT1
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-SKIP-PARENT1
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null -skip-funcs=je_malloc_vsnprintf -v=1
RUN: at line 22: /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null    -skip-funcs=je_malloc_mutex_postfork_child -v=1 |&  /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-SKIP-PARENT2
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/FileCheck /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/split-func-icf.test --check-prefix CHECK-SKIP-PARENT2
+ /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/bin/llvm-bolt /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/bolt-tests/test/X86/Inputs/merge-fdata -o /home/worker/buildbot-aarch64/bolt-aarch64-ubuntu-clang-shared/build/tools/bolttests/X86/Output/split-func-icf.test.tmp.null -skip-funcs=je_malloc_mutex_postfork_child -v=1

--

********************


@inbelic inbelic deleted the inbelic/spirv-audit-result branch November 25, 2024 21:13
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants