Skip to content

[llvmg++] call through array of pointers to member functions fails assertion #537

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
llvmbot opened this issue Dec 8, 2003 · 5 comments
Closed
Assignees

Comments

@llvmbot
Copy link
Member

llvmbot commented Dec 8, 2003

Bugzilla Link 165
Resolution FIXED
Resolved on Feb 22, 2010 12:54
Version 1.0
OS All
Reporter LLVM Bugzilla Contributor

Extended Description

The following test program involving a call through a pointer-to-member function
fails an assertion in llvm-g++ of the "tree not handled yet" flavor. The tree
it prints is a SAVE_EXPR. It looks to me as though c_llvm_expand_lvalue_expr()
needs to be extended to allow for a SAVE_EXPR lvalue.

I noted that if I take out the call to opcode(), the assert no longer fails.

/************/
extern "C" void abort();
class Evil {
public:
void fun () { abort (); }
void step (unsigned int instr);
unsigned short opcode (const unsigned int instr) const;
};
typedef void (Evil::memfunptr) ();
void Evil::step (unsigned int instr) {
static const memfunptr jumpTable[] = { &Evil::fun };
(this->jumpTable[opcode (instr)]) ();
}
/
/

The resulting long and tedious llvm-g++ barf is as follows:

ERROR: In function c_llvm_expand_lvalue_expr:5926, tree not handled by LLVM yet!
<save_expr 0x40018340
type <record_type 0x40190e00 readonly DI
size <integer_cst 0x4001a618 constant 64>
unit size <integer_cst 0x4001a99c constant 8>
align 32 symtab 0 alias set -1
fields <field_decl 0x40190cb0 __pfn type <pointer_type 0x401904d0>
unsigned SI file cpu.ii line 10
size <integer_cst 0x4001a9b0 constant 32>
unit size <integer_cst 0x4001a9d8 constant 4>
align 32 offset_align 32
offset <integer_cst 0x4001aa64 constant 0>
bit offset <integer_cst 0x4001ab04 constant 0> context <record_type
0x40190b60> arguments <integer_cst 0x4001aa64 0> chain <field_decl 0x40190d20
__delta>>
ptrmemfunc fn type <pointer_type 0x401904d0 type <method_type 0x4018d230>
readonly unsigned SI size <integer_cst 0x4001a9b0 32> unit size
<integer_cst 0x4001a9d8 4>
align 32 symtab 0 alias set -1>
pointer_to_this <pointer_type 0x40191000>>
side-effects readonly
arg 0 <array_ref 0x401584c8 type <record_type 0x40190e00>
side-effects readonly
arg 0 <var_decl 0x40190ee0 jumpTable type <array_type 0x40190e70>
readonly addressable asm_written used static tree_1 decl_6 DI file
cpu.ii line 10 size <integer_cst 0x4001a618 64> unit size <integer_cst 0x4001a99c 8>
align 32 context <function_decl 0x4018d5b0 step> initial
<constructor 0x4018ea14>>
arg 1 <nop_expr 0x4018eb54 type <integer_type 0x4001c4d0 int>
side-effects
arg 0 <call_expr 0x401584b0 type <integer_type 0x4001c460 short
unsigned int>
side-effects
arg 0 <addr_expr 0x4018eb40 type <pointer_type 0x401915b0>
constant arg 0 <function_decl 0x4018d850 opcode>>
arg 1 <tree_list 0x4018eb18
value <nop_expr 0x4018eb04 type <pointer_type 0x4018d000>
readonly
arg 0 <nop_expr 0x4018eaf0 type <pointer_type 0x4018d000>
readonly arg 0 <parm_decl 0x40190310 this>>>
chain <tree_list 0x4018eb2c value <parm_decl 0x40190150
instr>>>>>>
arg 1 <function_decl 0x4018d5b0 step
type <method_type 0x4018d540 type <void_type 0x40023bd0 void>
DI size <integer_cst 0x4001a618 64> unit size <integer_cst 0x4001a99c 8>
align 32 symtab 0 alias set -1 method basetype <record_type
0x4018bee0 Evil>
arg-types <tree_list 0x40186e10 value <pointer_type 0x4018d000>
chain <tree_list 0x40186dfc value <integer_type 0x4001c540
unsigned int>
chain <tree_list 0x4015a8e8 tree_2 value <void_type
0x40023bd0 void>>>>>
asm_written public static decl_5 QI file cpu.ii line 9 context
<record_type 0x4018bee0 Evil>
arguments <parm_decl 0x40190310 this type <pointer_type 0x4018d310>
readonly unsigned SI file cpu.ii line 9 size <integer_cst 0x4001a9b0
32> unit size <integer_cst 0x4001a9d8 4>
align 32 context <function_decl 0x4018d5b0 step> initial
<pointer_type 0x4018d310> arg-type <pointer_type 0x4018d310> chain <parm_decl
0x40190150 instr>>
result <result_decl 0x40190380 type <void_type 0x40023bd0 void>
VOID file cpu.ii line 9
align 8 context <function_decl 0x4018d5b0 step>> initial <block
0x40184de8>

    chain <function_decl 0x4018d850 opcode type <method_type 0x4018d930>
        addressable used public external QI file cpu.ii line 6 context

<record_type 0x4018bee0 Evil> arguments <parm_decl 0x4018da80 this>
>>
rtl 2 (nil)

rtl 3 (nil)

cpu.ii: In member function `void Evil::step(unsigned int)':
cpu.ii:11: internal compiler error: in c_llvm_expand_lvalue_expr, at
llvm-expand.c:5926
Please submit a full bug report,
with preprocessed source if appropriate.
See URL:http://llvm.cs.uiuc.edu for instructions.

@llvmbot
Copy link
Member Author

llvmbot commented Dec 8, 2003

assigned to @lattner

@lattner
Copy link
Collaborator

lattner commented Dec 8, 2003

Cute. This is definitely a bug, and should be relatively easy to fix. Nice 1.1
fodder. :)

-Chris

@llvmbot
Copy link
Member Author

llvmbot commented Dec 8, 2003

Minor fix to summary. Procrastinate, procrastinate.

@lattner
Copy link
Collaborator

lattner commented Dec 8, 2003

Fixed.

Testcase here: test/Regression/C++Frontend/2003-12-08-ArrayOfPtrToMemberFunc.cpp

Patch here:

$ diff -u llvm-expand.c~ llvm-expand.c
--- llvm-expand.c~ Fri Nov 28 22:21:26 2003
+++ llvm-expand.c Mon Dec 8 00:27:54 2003
@@ -5044,6 +5044,37 @@
llvm_expand_expr(Fn, exp, Result);
break;

  • case SAVE_EXPR:
  • /* Return the innermost context enclosing DECL that is a FUNCTION_DECL, or
  •   zero if none.  */
    
  • context = decl_function_context (exp);
  • /* If this SAVE_EXPR was at global context, assume we are an
  •   initialization function and move it into our context.  */
    
  • if (context == 0)
  •  SAVE_EXPR_CONTEXT (exp) = current_function_decl;
    
  • /* We treat inline_function_decl as an alias for the current function
  •   because that is the inline function whose vars, types, etc.
    
  •   are being merged into the current function.
    
  •   See expand_inline_function.  */
    
  • if (context == current_function_decl)
  •  context = 0;
    
  • /* If this is non-local, handle it. */
  • if (context) LLVM_TODO_TREE(exp); /* Don't handle nested functions yet! */
  • /* If the expression has not been computed yet... */
  • if (SAVE_EXPR_LLVM(exp) == 0) {
  •  /* Expand the saved expression. This does not handle bit-fields yet. */
    
  •  Result = llvm_expand_lvalue_expr(Fn, TREE_OPERAND(exp, 0), 0, 0);
    
  •  SAVE_EXPR_LLVM(exp) = Result;
    
  •  TREE_USED(exp) = 1;
    
  • } else {
  •  Result = SAVE_EXPR_LLVM(exp);
    
  • }
  • break;
  • case COND_EXPR: { /* ?: expression /
    /
    Allocate a new temporary to hold the result of the expression */
    llvm_basicblock *TrueBlock = llvm_basicblock_new("cond_true");

Thanks for the bug report!

-Chris

@lattner
Copy link
Collaborator

lattner commented Dec 8, 2003

whoops, I thought the midair collision was just due to fixing pointers, which I
had covered. fix my bogus fix

@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 1, 2021
pysuxing pushed a commit to pysuxing/llvm-project that referenced this issue Jul 17, 2024
This PR perform flattening for `cir::IfOp`
Basically, we just move the code from `LowerToLLVM.cpp` to
`FlattenCFG.cpp`.
There are several important things though I would like to highlight.
1) Consider the next code from the tests:
```
cir.func @foo(%arg0: !s32i) -> !s32i {
    %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool
    cir.if %4 {
      %5 = cir.const(#cir.int<1> : !s32i) : !s32i
      cir.return %5 : !s32i
    } else {
      %5 = cir.const(#cir.int<0> : !s32i) : !s32i
      cir.return %5 : !s32i
    }
    cir.return %arg0 : !s32i
  }
```
The last `cir.return` becomes unreachable after flattening and hence is
not reachable in the lowering. So we got the next error:
```
error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for'
    cir.return %arg0 : !s32i
```
the parent after lowering is `llvm.func`.
And this is only the beginning - the more operations will be flatten,
the more similar fails will happen. Thus, I added lowering for the
unreachable code as well in `LowerToLLVM.cpp`. But may be you have
another solution in your mind.

2) Please, pay attention on the flattening pass - I'm not that familiar
with `mlir` builders as you are, so may be I'm doing something wrong.
The idea was to start flattening from the most nested operations.

3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to
`cir-flat-to-llvm`. The only thing remain undone is related to the
following:

> Since it would be wrong to run cir-flat-to-llvm without running
cir-flatten-cfg, we should make cir-flat-to-llvm pass to require
cir-flatten-cfg pass to be run before.

And I'm not sure I know how to do it exactly - is there something
similar to pass dependencies from LLVM IR?

4) The part of `IfOp` lowering related to elimination of the vain casts
for condition branch moved directly to the lowering of `BrCondOp` with
some refactoring and guarding.

5) Just note, that now `cir-opt` is able to dump the flat cir as well:
`cir-opt -cir-flat-cfg`
pysuxing pushed a commit to pysuxing/llvm-project that referenced this issue Jul 17, 2024
This PR perform flattening for `cir::IfOp`
Basically, we just move the code from `LowerToLLVM.cpp` to
`FlattenCFG.cpp`.
There are several important things though I would like to highlight.
1) Consider the next code from the tests:
```
cir.func @foo(%arg0: !s32i) -> !s32i {
    %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool
    cir.if %4 {
      %5 = cir.const(#cir.int<1> : !s32i) : !s32i
      cir.return %5 : !s32i
    } else {
      %5 = cir.const(#cir.int<0> : !s32i) : !s32i
      cir.return %5 : !s32i
    }
    cir.return %arg0 : !s32i
  }
```
The last `cir.return` becomes unreachable after flattening and hence is
not reachable in the lowering. So we got the next error:
```
error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for'
    cir.return %arg0 : !s32i
```
the parent after lowering is `llvm.func`.
And this is only the beginning - the more operations will be flatten,
the more similar fails will happen. Thus, I added lowering for the
unreachable code as well in `LowerToLLVM.cpp`. But may be you have
another solution in your mind.

2) Please, pay attention on the flattening pass - I'm not that familiar
with `mlir` builders as you are, so may be I'm doing something wrong.
The idea was to start flattening from the most nested operations.

3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to
`cir-flat-to-llvm`. The only thing remain undone is related to the
following:

> Since it would be wrong to run cir-flat-to-llvm without running
cir-flatten-cfg, we should make cir-flat-to-llvm pass to require
cir-flatten-cfg pass to be run before.

And I'm not sure I know how to do it exactly - is there something
similar to pass dependencies from LLVM IR?

4) The part of `IfOp` lowering related to elimination of the vain casts
for condition branch moved directly to the lowering of `BrCondOp` with
some refactoring and guarding.

5) Just note, that now `cir-opt` is able to dump the flat cir as well:
`cir-opt -cir-flat-cfg`
keryell pushed a commit to keryell/llvm-project that referenced this issue Oct 19, 2024
This PR perform flattening for `cir::IfOp`
Basically, we just move the code from `LowerToLLVM.cpp` to
`FlattenCFG.cpp`.
There are several important things though I would like to highlight.
1) Consider the next code from the tests:
```
cir.func @foo(%arg0: !s32i) -> !s32i {
    %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool
    cir.if %4 {
      %5 = cir.const(#cir.int<1> : !s32i) : !s32i
      cir.return %5 : !s32i
    } else {
      %5 = cir.const(#cir.int<0> : !s32i) : !s32i
      cir.return %5 : !s32i
    }
    cir.return %arg0 : !s32i
  }
```
The last `cir.return` becomes unreachable after flattening and hence is
not reachable in the lowering. So we got the next error:
```
error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for'
    cir.return %arg0 : !s32i
```
the parent after lowering is `llvm.func`.
And this is only the beginning - the more operations will be flatten,
the more similar fails will happen. Thus, I added lowering for the
unreachable code as well in `LowerToLLVM.cpp`. But may be you have
another solution in your mind.

2) Please, pay attention on the flattening pass - I'm not that familiar
with `mlir` builders as you are, so may be I'm doing something wrong.
The idea was to start flattening from the most nested operations.

3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to
`cir-flat-to-llvm`. The only thing remain undone is related to the
following:

> Since it would be wrong to run cir-flat-to-llvm without running
cir-flatten-cfg, we should make cir-flat-to-llvm pass to require
cir-flatten-cfg pass to be run before.

And I'm not sure I know how to do it exactly - is there something
similar to pass dependencies from LLVM IR?

4) The part of `IfOp` lowering related to elimination of the vain casts
for condition branch moved directly to the lowering of `BrCondOp` with
some refactoring and guarding.

5) Just note, that now `cir-opt` is able to dump the flat cir as well:
`cir-opt -cir-flat-cfg`
xlauko pushed a commit to trailofbits/instafix-llvm that referenced this issue Mar 28, 2025
This PR perform flattening for `cir::IfOp`
Basically, we just move the code from `LowerToLLVM.cpp` to
`FlattenCFG.cpp`.
There are several important things though I would like to highlight.
1) Consider the next code from the tests:
```
cir.func @foo(%arg0: !s32i) -> !s32i {
    %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool
    cir.if %4 {
      %5 = cir.const(#cir.int<1> : !s32i) : !s32i
      cir.return %5 : !s32i
    } else {
      %5 = cir.const(#cir.int<0> : !s32i) : !s32i
      cir.return %5 : !s32i
    }
    cir.return %arg0 : !s32i
  }
```
The last `cir.return` becomes unreachable after flattening and hence is
not reachable in the lowering. So we got the next error:
```
error: 'cir.return' op expects parent op to be one of 'cir.func, cir.scope, cir.if, cir.switch, cir.do, cir.while, cir.for'
    cir.return %arg0 : !s32i
```
the parent after lowering is `llvm.func`.
And this is only the beginning - the more operations will be flatten,
the more similar fails will happen. Thus, I added lowering for the
unreachable code as well in `LowerToLLVM.cpp`. But may be you have
another solution in your mind.

2) Please, pay attention on the flattening pass - I'm not that familiar
with `mlir` builders as you are, so may be I'm doing something wrong.
The idea was to start flattening from the most nested operations.

3) As you requested in llvm#516, `cir-to-llvm-internal` is renamed to
`cir-flat-to-llvm`. The only thing remain undone is related to the
following:

> Since it would be wrong to run cir-flat-to-llvm without running
cir-flatten-cfg, we should make cir-flat-to-llvm pass to require
cir-flatten-cfg pass to be run before.

And I'm not sure I know how to do it exactly - is there something
similar to pass dependencies from LLVM IR?

4) The part of `IfOp` lowering related to elimination of the vain casts
for condition branch moved directly to the lowering of `BrCondOp` with
some refactoring and guarding.

5) Just note, that now `cir-opt` is able to dump the flat cir as well:
`cir-opt -cir-flat-cfg`
eq19 pushed a commit to eq19/eq19.github.io that referenced this issue May 7, 2025
WIP: Spike out the documentation
This issue was closed.
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

No branches or pull requests

2 participants