Skip to content

[SYCL][ESIMD] Fix the crash in sycl-post-link while processing global spirv functions. #7590

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
Dec 5, 2022

Conversation

fineg74
Copy link
Contributor

@fineg74 fineg74 commented Nov 30, 2022

Currently for int i = __spirv_GlobalInvocationId_x(); c++ code followinf IR code is generated:

%0 = load <3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, align 32
 %1 = extractelement <3 x i64> %0, i64 0
 %conv = trunc i64 %1 to i32

This IR is what sycl-post-link is expecting and is able to process successfully.
However, following IR code was generated during the testing:

%0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32
  %conv = trunc i64 %0 to i32

and it caused sycl-post-link to crash.
The fix resolves the issue

@fineg74 fineg74 requested review from a team as code owners November 30, 2022 03:51
@fineg74 fineg74 requested a review from againull November 30, 2022 03:51
bool IsVectorCall) {
uint64_t IndexValue = isa<ExtractElementInst>(EEI)
? getIndexFromExtract(cast<ExtractElementInst>(EEI))
: 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think using '0' for the getelementptr case is wrong. Instead, index from the GEP instruction should be extracted (marked below)

%0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It is actually for trunc instruction. In the pathological case there is no getElementptr i.e. for

%0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32
  %conv = trunc i64 %0 to i32

case and that is why index doesn't matter much here.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't understand why index does not matter.

%ref.tmp.i = alloca %"class.sycl::_V1::ext::intel::esimd::simd.0", align 32
%0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32
%conv = trunc i64 %0 to i32
%1 = bitcast %"class.sycl::_V1::ext::intel::esimd::simd.0"* %ref.tmp.i to i8*
Copy link
Contributor

Choose a reason for hiding this comment

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

  1. Please simplify the test. Only instructions participating in pattern matching should be left.
  2. Please inline //CHECK: directives right after source IR instruction they are supposed to verify
    transformation of

!opencl.compiler.options = !{!45}
!llvm.ident = !{!46}

!0 = !{i32 1, !"wchar_size", i32 4}
Copy link
Contributor

Choose a reason for hiding this comment

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

likewise, all unnecessary metadata should be removed.

@@ -0,0 +1,153 @@
; RUN: sycl-post-link -split-esimd -lower-esimd -O2 -S %s -o %t.table
Copy link
Contributor

Choose a reason for hiding this comment

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

please move the test to llvm/test/tools/sycl-post-link

@fineg74 fineg74 requested a review from a team as a code owner November 30, 2022 07:51
@MrSidims
Copy link
Contributor

MrSidims commented Dec 1, 2022

BTW can we instead of handling this GEP(0,0) in sycl-post-link - remove this GEP at all here? It seems to be incorrect to access a vector via GEP and GEP(0,0) is quite useless anyway. Though, unfortunately, we can't just call replaceAllUsesWith...

@kbobrovs kbobrovs closed this Dec 1, 2022
@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 1, 2022

It seems to be incorrect to access a vector via GEP and GEP(0,0) is quite useless anyway.

Good catch. extractelement should be used for accessing vector elements normally, even though for Intel GPU target the GEP will generate correct address. I wonder who generates the questionable IR now:
%0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32

@kbobrovs kbobrovs reopened this Dec 1, 2022
@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 1, 2022

kbobrovs closed this 17 minutes ago

sorry, hit wrong button

@Fznamznon
Copy link
Contributor

It seems to be incorrect to access a vector via GEP and GEP(0,0) is quite useless anyway.

Good catch. extractelement should be used for accessing vector elements normally, even though for Intel GPU target the GEP will generate correct address. I wonder who generates the questionable IR now: %0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32

This IR appeared during the pulldown after llvm/llvm-project@163bb6d.

@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 1, 2022

It seems to be incorrect to access a vector via GEP and GEP(0,0) is quite useless anyway.

Good catch. extractelement should be used for accessing vector elements normally, even though for Intel GPU target the GEP will generate correct address. I wonder who generates the questionable IR now: %0 = load i64, i64 addrspace(1)* getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0), align 32

I take this back.
Actually, I believe getelementptr (<3 x i64>, <3 x i64> addrspace(1)* @__spirv_BuiltInGlobalInvocationId, i64 0, i64 0) is OK.
extractelement, of course, is required to be used to access elements, but we are calculating vector element's offset in memory. Vector's layout in memory is defined by the target, so for SPIRV target this seems perfectly OK code.

@Fznamznon
Copy link
Contributor

Can we proceed with this patch? The pulldown is blocked by the crash being fixed here.

Comment on lines 1262 to 1267
auto *GEPCE =
dyn_cast<GetElementPtrConstantExpr>(LI->getPointerOperand());
if (GEPCE) {
IndexValue = cast<Constant>(GEPCE->getOperand(2))
->getUniqueInteger()
.getZExtValue();
Copy link
Contributor

Choose a reason for hiding this comment

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

The above code silently produces invalid IR if it gets unexpected IR. Please fix.

Suggested change
auto *GEPCE =
dyn_cast<GetElementPtrConstantExpr>(LI->getPointerOperand());
if (GEPCE) {
IndexValue = cast<Constant>(GEPCE->getOperand(2))
->getUniqueInteger()
.getZExtValue();
auto *GEPCE =
cast<GetElementPtrConstantExpr>(LI->getPointerOperand());
IndexValue = cast<Constant>(GEPCE->getOperand(2))
->getUniqueInteger()
.getZExtValue();

@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 2, 2022

Can we proceed with this patch? The pulldown is blocked by the crash being fixed here.

not yet, there is still a bug to be fixed. (see above comment). I believe the patch can be merged once it is addressed.

@againull againull removed request for a team and againull December 2, 2022 19:55
Copy link
Contributor

@kbobrovs kbobrovs left a comment

Choose a reason for hiding this comment

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

This comment hasn't been addressed:
Please inline //CHECK: directives right after source IR instruction they are supposed to verify transformation of

Approving for the sake of urgency. Please address with follow-up patch.

@fineg74
Copy link
Contributor Author

fineg74 commented Dec 5, 2022

@intel/dpcpp-tools-reviewers Could you please take a look ?

Copy link
Contributor

@sarnex sarnex left a comment

Choose a reason for hiding this comment

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

Approving for urgency, leaving correctness review to Konst and other reviewers

@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 5, 2022

HIP Failures are unrelated:

Unresolved Tests (5):
SYCL :: Assert/assert_in_kernels.cpp
SYCL :: Assert/assert_in_multiple_tus.cpp
SYCL :: Assert/assert_in_multiple_tus_one_ndebug.cpp
SYCL :: Assert/assert_in_one_kernel.cpp
SYCL :: Assert/assert_in_simultaneously_multiple_tus_one_ndebug.cpp


Timed Out Tests (1):
SYCL :: AtomicRef/max_local.cpp

@kbobrovs kbobrovs merged commit 63c749c into intel:sycl Dec 5, 2022
@Fznamznon
Copy link
Contributor

The guilty llvm change that caused crash just enables an additional optimization. To unblock pulldown the change that disables the optimization for sycl device code was merged. But this is not a proper solution. I've been testing workaround in SPIR-V translator together with reverting change that disables guilty optimization and also cherry-picked changes from this PR for testing. I've started testing here https://github.com/intel/llvm/actions/runs/3623046607/jobs/6108488479 . The thing is, with changes from this PR, I still see one of the tests failing, but with another error:

sycl-post-link: /__w/llvm/llvm/src/llvm/lib/SYCLLowerIR/ESIMD/LowerESIMD.cpp:1252: void {anonymous}::translateSpirvGlobalUses(llvm::LoadInst*, llvm::StringRef, llvm::SmallVectorImpl<llvm::Instruction*>&): Assertion `(isa<ExtractElementInst>(LU) || isa<TruncInst>(LU)) && "SPIRV global users should be either ExtractElementInst or TruncInst"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:
0.	Program arguments: sycl-post-link -split-esimd -lower-esimd -O0 -S /__w/llvm/llvm/build/tools/sycl/test/esimd/Output/spirv_intrins_trans.cpp.tmp -o /__w/llvm/llvm/build/tools/sycl/test/esimd/Output/spirv_intrins_trans.cpp.tmp.table
 #0 0x000055774af13ff4 PrintStackTraceSignalHandler(void*) Signals.cpp:0:0
 #1 0x000055774af11fe4 SignalHandler(int) Signals.cpp:0:0
 #2 0x00007fc293202420 __restore_rt (/lib/x86_64-linux-gnu/libpthread.so.0+0x14420)
 #3 0x00007fc292ca500b raise (/lib/x86_64-linux-gnu/libc.so.6+0x4300b)
 #4 0x00007fc292c84859 abort (/lib/x86_64-linux-gnu/libc.so.6+0x22859)
 #5 0x00007fc292c84729 (/lib/x86_64-linux-gnu/libc.so.6+0x22729)
 #6 0x00007fc292c95fd6 (/lib/x86_64-linux-gnu/libc.so.6+0x33fd6)
 #7 0x000055774af8fdd1 llvm::SYCLLowerESIMDPass::runOnFunction(llvm::Function&, llvm::SmallPtrSet<llvm::Type*, 4u>&) (/__w/llvm/llvm/build/bin/sycl-post-link+0x3a5dd1)
 #8 0x000055774af92180 llvm::SYCLLowerESIMDPass::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/__w/llvm/llvm/build/bin/sycl-post-link+0x3a8180)
 #9 0x000055774acb05b6 llvm::detail::PassModel<llvm::Module, llvm::SYCLLowerESIMDPass, llvm::PreservedAnalyses, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/__w/llvm/llvm/build/bin/sycl-post-link+0xc65b6)
#10 0x000055774ae30c69 llvm::PassManager<llvm::Module, llvm::AnalysisManager<llvm::Module>>::run(llvm::Module&, llvm::AnalysisManager<llvm::Module>&) (/__w/llvm/llvm/build/bin/sycl-post-link+0x246c69)
#11 0x000055774acbc574 (anonymous namespace)::lowerEsimdConstructs(llvm::module_split::ModuleDesc&) sycl-post-link.cpp:0:0
#12 0x000055774acc2b7c (anonymous namespace)::processInputModule(std::unique_ptr<llvm::Module, std::default_delete<llvm::Module>>) sycl-post-link.cpp:0:0
#13 0x000055774ac5e0b6 main (/__w/llvm/llvm/build/bin/sycl-post-link+0x740b6)
#14 0x00007fc292c86083 __libc_start_main (/lib/x86_64-linux-gnu/libc.so.6+0x24083)
#15 0x000055774acaf85e _start (/__w/llvm/llvm/build/bin/sycl-post-link+0xc585e)

error: command failed with exit status: -6

--

********************
Testing:  0.. 10.. 20.. 30.. 40.. 50.. 60.. 70.. 80.. 90.. 
********************
Failed Tests (1):
  SYCL :: esimd/spirv_intrins_trans.cpp

Could you please double check that everything is correct?

@kbobrovs
Copy link
Contributor

kbobrovs commented Dec 5, 2022

@fineg74, please take a look at the issue reported above.

ExtractElementInst *EEI = cast<ExtractElementInst>(LU);
assert(
(isa<ExtractElementInst>(LU) || isa<TruncInst>(LU)) &&
"SPIRV global users should be either ExtractElementInst or TruncInst");
Copy link
Contributor

Choose a reason for hiding this comment

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

Sorry for being late for the review, I don't see such restrictions in SPIR-V spec, could you please help me finding it?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

These restrictions are to protect the code to make sure it processes only the code it is expected to process and not to enforce SPIR-V spec.

@fineg74
Copy link
Contributor Author

fineg74 commented Dec 7, 2022

@fineg74, please take a look at the issue reported above.

Folow up PR: #7673

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.

5 participants