Skip to content

Function has token parameter but isn't an intrinsic #40056

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

Closed
compnerd opened this issue Feb 13, 2019 · 15 comments · Fixed by #99759
Closed

Function has token parameter but isn't an intrinsic #40056

compnerd opened this issue Feb 13, 2019 · 15 comments · Fixed by #99759
Assignees
Labels
bugzilla Issues migrated from bugzilla ipo Interprocedural optimizations

Comments

@compnerd
Copy link
Member

compnerd commented Feb 13, 2019

Bugzilla Link 40710
Version unspecified
OS Windows NT
CC @DougGregor,@hiraditya,@pcc,@zygoloid,@rnk,@smeenai,@vedantk

Extended Description

Reduced from ICU 61:

// RUN: %clang_cc1 -triple x86_64-pc-windows-msvc19.0.0 -emit-obj -o /dev/null -O1 -fcxx-exceptions -fexceptions %s
struct T {
  virtual ~T();
};

void f();

struct S {
  virtual ~S();
  T t_[1];
};

S::~S() { f(); }
@compnerd
Copy link
Member Author

assigned to @hiraditya

@compnerd
Copy link
Member Author

The IR verifier might be too stringent on the token checking. The outlined filter funclet is given a token to tie it to the parent clause but is a "Function" in IR land. This triggers a verification failure.

@compnerd
Copy link
Member Author

This is caused by the hot/cold splitting code path promoting the token to a formal argument.

@rnk
Copy link
Collaborator

rnk commented Feb 13, 2019

(pasting in stuff I said in IRC)

  1. outlining WinEH code is fine, but unlikely to be profitable or save size, as EH funclets are already "outlined", so it's a bit redundant
  2. if you do outline code with funclet bundles, just delete all "funclet" bundle operands and make a "funclet" operand bundle on the call to the outlined code

And, I think the verifier is working as intended here. You are not supposed to be able to pass a token as a regular parameter, it can't be passed through registers/memory/phis, etc, and I think arguments fit in there as well. It just so happens that you can look at the bundle type ("funclet" in this case) and reason about it, so it is possible to do what you want, but in the general case, I don't think tokens can be outlined.

@vedantk
Copy link
Collaborator

vedantk commented Feb 13, 2019

(pasting in stuff I said in IRC)

  1. outlining WinEH code is fine, but unlikely to be profitable or save size,
    as EH funclets are already "outlined", so it's a bit redundant

I only have a vague understanding of WinEH, so apologies for the naive question: is the funclet really the thing being split here?

It looks like two blocks dominated by a cleanuppad are split, and afaik they aren't normally outlined?

  1. if you do outline code with funclet bundles, just delete all "funclet"
    bundle operands and make a "funclet" operand bundle on the call to the
    outlined code

Should splitting even be allowed on functions with WinEH personality? I don't think any run-time testing has been done with this. And as you point out, it may not be profitable.

And, I think the verifier is working as intended here. You are not supposed
to be able to pass a token as a regular parameter, it can't be passed
through registers/memory/phis, etc, and I think arguments fit in there as
well. It just so happens that you can look at the bundle type ("funclet" in
this case) and reason about it, so it is possible to do what you want, but
in the general case, I don't think tokens can be outlined.

This points to a separate bug. CodeExtractor shouldn't permit this.

@vedantk
Copy link
Collaborator

vedantk commented Feb 13, 2019

@compnerd
Copy link
Member Author

Created attachment 21477 [details]
Proposed patch (disable splitting within functions with scoped EH
personalities)

I think that we should still teach the Hot/Cold splitting to deal with the tokens. But, yes the funclets should not be split into the cold path since they are already outlined.

@rnk
Copy link
Collaborator

rnk commented Feb 13, 2019

I only have a vague understanding of WinEH, so apologies for the naive
question: is the funclet really the thing being split here?

It looks like two blocks dominated by a cleanuppad are split, and afaik they
aren't normally outlined?

When I compile this code with -O2 and run the hotcoldsplit pass on it, I see this block being outlined:

Found a cold block:

ehcleanup:                                        ; preds = %entry
  %1 = cleanuppad within none []
  %arraydestroy.element7 = getelementptr inbounds %struct.S, %struct.S* %this, i64 0, i32 1, i64 0
  call void @"??1T@@UEAA@XZ"(%struct.T* nonnull %arraydestroy.element7) #​4 [ "funclet"(token %1) ]
  call void @​__std_terminate() #​5 [ "funclet"(token %1) ]
  unreachable

Outlining in ??_GS@@UEAAPEAXI@Z

The blocks in the cleanuppad region constitute the funclet. They share a stack frame with the parent function, but the code is discontiguous from the parent function and has its own prologue/epilogue.

Should splitting even be allowed on functions with WinEH personality? I
don't think any run-time testing has been done with this. And as you point
out, it may not be profitable.

Up to you. I think if we update CodeExtractor to be token aware, this may sort itself out naturally. Keep in mind that checking isScopedEHPersonality also affects web assembly, which I think uses the same representation.

And, I think the verifier is working as intended here. You are not supposed
to be able to pass a token as a regular parameter, it can't be passed
through registers/memory/phis, etc, and I think arguments fit in there as
well. It just so happens that you can look at the bundle type ("funclet" in
this case) and reason about it, so it is possible to do what you want, but
in the general case, I don't think tokens can be outlined.

This points to a separate bug. CodeExtractor shouldn't permit this.

Makes sense.

@vedantk
Copy link
Collaborator

vedantk commented Feb 13, 2019

I only have a vague understanding of WinEH, so apologies for the naive
question: is the funclet really the thing being split here?

It looks like two blocks dominated by a cleanuppad are split, and afaik they
aren't normally outlined?

When I compile this code with -O2 and run the hotcoldsplit pass on it, I see
this block being outlined:

'''
Found a cold block:

ehcleanup: ; preds = %entry
%1 = cleanuppad within none []
%arraydestroy.element7 = getelementptr inbounds %struct.S, %struct.S*
%this, i64 0, i32 1, i64 0
call void @"??1T@@UEAA@XZ"(%struct.T* nonnull %arraydestroy.element7) #​4 [
"funclet"(token %1) ]
call void @​__std_terminate() #​5 [ "funclet"(token %1) ]
unreachable

Outlining in ??_GS@@UEAAPEAXI@Z
'''

The blocks in the cleanuppad region constitute the funclet. They share a
stack frame with the parent function, but the code is discontiguous from the
parent function and has its own prologue/epilogue.

The splitting pass will refuse to extract EH pads (see mayExtractBlock). It does still consider EH pads to be cold, though, and will propagate that information.

By 'cleanuppad region', can I assume you mean blocks which use a cleannuppad token?

Should splitting even be allowed on functions with WinEH personality? I
don't think any run-time testing has been done with this. And as you point
out, it may not be profitable.

Up to you. I think if we update CodeExtractor to be token aware, this may
sort itself out naturally. Keep in mind that checking isScopedEHPersonality
also affects web assembly, which I think uses the same representation.

I'll take a cut at this, but might need some help with the run-time testing bit.

And, I think the verifier is working as intended here. You are not supposed
to be able to pass a token as a regular parameter, it can't be passed
through registers/memory/phis, etc, and I think arguments fit in there as
well. It just so happens that you can look at the bundle type ("funclet" in
this case) and reason about it, so it is possible to do what you want, but
in the general case, I don't think tokens can be outlined.

This points to a separate bug. CodeExtractor shouldn't permit this.

Makes sense.

@compnerd
Copy link
Member Author

compnerd commented Feb 13, 2019

BTW, I ended up with this reduction:

; RUN: opt -hotcoldsplit %s -S -o /dev/null

define void @"??1S@@UEAA@XZ"() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
  invoke void @"?f@@YAXXZ"()
          to label %invoke.cont unwind label %ehcleanup

invoke.cont:
  ret void

ehcleanup:
  %0 = cleanuppad within none []
  br label %ehcleanup.resume

ehcleanup.resume:
  call void @"?f@@YAXXZ"() [ "funclet"(token %0) ]
  br label %terminate

terminmate:
  call void @"?terminate@@YAXXZ"() [ "funclet"(token %0) ]
  unreachable
}

declare void @"?f@@YAXXZ"()

declare i32 @__CxxFrameHandler3(...)

declare void @"?terminate@@YAXXZ"()

@hiraditya
Copy link
Collaborator

hiraditya commented Sep 24, 2019

Thanks for providing the repro @Saleem. There's a small typo so the fixed up repro is here:

; RUN: opt --hot-cold-split %s -S -o /dev/null

define void @"??1S@@UEAA@XZ"() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
  invoke void @"?f@@YAXXZ"()
          to label %invoke.cont unwind label %ehcleanup

invoke.cont:
  ret void

ehcleanup:
  %0 = cleanuppad within none []
  br label %ehcleanup.resume

ehcleanup.resume:
  call void @"?f@@YAXXZ"() [ "funclet"(token %0) ]
  br label %terminate

terminate:
  call void @"?terminate@@YAXXZ"() [ "funclet"(token %0) ]
  unreachable
}

declare void @"?f@@YAXXZ"()

declare i32 @__CxxFrameHandler3(...)

declare void @"?terminate@@YAXXZ"()

the compilation aborts after hotcoldsplit with the following IR.

*** IR Dump After Hot Cold Splitting ***
; ModuleID = '<stdin>'
source_filename = "<stdin>"

define void @"??1S@@UEAA@XZ"() personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
entry:
  invoke void @"?f@@YAXXZ"()
          to label %invoke.cont unwind label %ehcleanup

invoke.cont:                                      ; preds = %entry
  ret void

ehcleanup:                                        ; preds = %entry
  %0 = cleanuppad within none []
  br label %codeRepl

codeRepl:                                         ; preds = %ehcleanup
  call void @"??1S@@[email protected]"(token %0) #1
  ret void
}

declare void @"?f@@YAXXZ"()

declare i32 @__CxxFrameHandler3(...)

declare void @"?terminate@@YAXXZ"()

; Function Attrs: cold minsize noreturn
define internal void @"??1S@@[email protected]"(token %0) #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) {
newFuncRoot:
  br label %ehcleanup.resume

ehcleanup.resume:                                 ; preds = %newFuncRoot
  call void @"?f@@YAXXZ"() [ "funclet"(token %0) ]
  br label %terminate

terminate:                                        ; preds = %ehcleanup.resume
  call void @"?terminate@@YAXXZ"() [ "funclet"(token %0) ]
  unreachable
}

attributes #0 = { cold minsize noreturn }
attributes #1 = { noinline }
Function has token parameter but isn't an intrinsic
  call void @"??1S@@[email protected]"(token %0) #1
in function ??1S@@UEAA@XZ
LLVM ERROR: Broken function found, compilation aborted!

@hiraditya
Copy link
Collaborator

Bug fix: D68192

@hiraditya
Copy link
Collaborator

hjyamauchi added a commit to hjyamauchi/swift-build that referenced this issue Jul 3, 2023
swift-inspect will fail to build in release mode after the dump-arrays
PR (swiftlang/swift#66973) due to an llvm bug
(llvm/llvm-project#40056). This is a
workaround for it.
hjyamauchi added a commit to compnerd/swift-build that referenced this issue Jul 3, 2023
swift-inspect will fail to build in release mode after the dump-arrays
PR (swiftlang/swift#66973) due to an llvm bug
(llvm/llvm-project#40056). This is a
workaround for it.
@Endilll Endilll added the clang:to-be-triaged Should not be used for new issues label Jul 19, 2024
@compnerd
Copy link
Member Author

@Endilll - what exactly needs to be done in terms of triaging? This is an issue with the hot cold splitting implementation, which is done in LLVM.

@Endilll Endilll added llvm Umbrella label for LLVM issues and removed clang:to-be-triaged Should not be used for new issues labels Jul 20, 2024
@hiraditya
Copy link
Collaborator

I think the fix is to disable outlining of basic blocks with token-type instructions

@EugeneZelenko EugeneZelenko removed c++ llvm Umbrella label for LLVM issues labels Jul 20, 2024
@EugeneZelenko EugeneZelenko added the ipo Interprocedural optimizations label Jul 20, 2024
compnerd pushed a commit to swiftlang/llvm-project that referenced this issue Jul 24, 2024
…lvm#99759)

Hot cold splitting should not outline:
1. Basic blocks with token type instructions
1. Functions with scoped EH personality (As suggested by Vedant in
llvm#40056 (comment))

Fixes: llvm#40056
(cherry picked from commit c59ee7e)
fredriss pushed a commit to swiftlang/llvm-project that referenced this issue Jul 25, 2024
…lvm#99759)

Hot cold splitting should not outline:
1. Basic blocks with token type instructions
1. Functions with scoped EH personality (As suggested by Vedant in
llvm#40056 (comment))

Fixes: llvm#40056
(cherry picked from commit c59ee7e)
(cherry picked from commit 267c6ed)
yuxuanchen1997 pushed a commit that referenced this issue Jul 25, 2024
…99759)

Hot cold splitting should not outline:
1. Basic blocks with token type instructions
1. Functions with scoped EH personality (As suggested by Vedant in
#40056 (comment))

Fixes: #40056
kingbri1 added a commit to kingbri1/llama.cpp that referenced this issue Jul 29, 2024
Adds some flags for Swift's LLVM compiler to succeed on Windows.

Related: llvm/llvm-project#40056

Signed-off-by: kingbri <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla ipo Interprocedural optimizations
Projects
None yet
Development

Successfully merging a pull request may close this issue.

6 participants