llvm / llvm/Polygeist

The virtual function is not correctly invoked.

Open
#420 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
624
Forks
170
PR merge metrics
No merged PRs in 30d

Description

Hello, when I try to translate operations with Polygeist that call virtual functions, I find that the base class calls the functions of the base class, not the functions overridden by the subclass. The sample I used is as follows. The comments are the translated result. The command I used is cgeist test.cpp --function=main --resource-dir=/Polygeist/llvm-project/build/lib/clang/18 -I /Polygeist/tools/cgeist/Test/polybench/utilities -S

In the base class, vfunc is an addition operation. In the subclass, it is rewritten as a subtraction operation. The final translation is the addition operation of the base class(%12 = arith.addi %10, %11 : i32) instead of the expected subtraction operation of the subclass.


#include <new>
#include <cstdio>
class SimStream {
public:
    int n;
    SimStream() {
        n = 0;
    }
    virtual int vfunc(int val1 , int val2) {
        return val1 + val2;
    }
};

class subSimStream : public SimStream {
public:
    int vfunc(int val1 , int val2) override {
        return val1 - val2;
    }
};

int myfunc(SimStream *ptr , int val1 , int val2) {
    int output = ptr->vfunc(val1 , val2);
    return output;
}

int main() {
    SimStream *r = new subSimStream;
    int val1 , val2 , output;
    scanf("%d%d" , &val1 , &val2);
    output = r->vfunc(val1 , val2);
    printf("output = %d\n" , output);
    delete r;
    return 0;
}

/*
module attributes {dlti.dl_spec = #dlti.dl_spec<#dlti.dl_entry<i32, dense<32> : vector<2xi32>>, #dlti.dl_entry<f16, dense<16> : vector<2xi32>>, #dlti.dl_entry<f64, dense<64> : vector<2xi32>>, #dlti.dl_entry<i16, dense<16> : vector<2xi32>>, #dlti.dl_entry<f128, dense<128> : vector<2xi32>>, #dlti.dl_entry<i8, dense<8> : vector<2xi32>>, #dlti.dl_entry<i1, dense<8> : vector<2xi32>>, #dlti.dl_entry<!llvm.ptr, dense<64> : vector<4xi32>>, #dlti.dl_entry<f80, dense<128> : vector<2xi32>>, #dlti.dl_entry<i64, dense<64> : vector<2xi32>>, #dlti.dl_entry<!llvm.ptr<272>, dense<64> : vector<4xi32>>, #dlti.dl_entry<!llvm.ptr<271>, dense<32> : vector<4xi32>>, #dlti.dl_entry<!llvm.ptr<270>, dense<32> : vector<4xi32>>, #dlti.dl_entry<"dlti.stack_alignment", 128 : i32>, #dlti.dl_entry<"dlti.endianness", "little">>, llvm.data_layout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128", llvm.target_triple = "x86_64-unknown-linux-gnu", "polygeist.target-cpu" = "x86-64", "polygeist.target-features" = "+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87", "polygeist.tune-cpu" = "generic"} {
  llvm.func @free(!llvm.ptr)
  llvm.mlir.global internal constant @str1("output = %d\0A\00") {addr_space = 0 : i32}
  llvm.func @printf(!llvm.ptr, ...) -> i32
  llvm.mlir.global internal constant @str0("%d%d\00") {addr_space = 0 : i32}
  llvm.func @scanf(!llvm.ptr, ...) -> i32
  func.func @main() -> i32 attributes {llvm.linkage = #llvm.linkage<external>} {
    %c0_i32 = arith.constant 0 : i32
    %0 = llvm.mlir.undef : i32
    %alloca = memref.alloca() : memref<1xi32>
    affine.store %0, %alloca[0] : memref<1xi32>
    %alloca_0 = memref.alloca() : memref<1xi32>
    affine.store %0, %alloca_0[0] : memref<1xi32>
    %alloc = memref.alloc() : memref<1x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>
    %cast = memref.cast %alloc : memref<1x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>> to memref<?x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>
    call @_ZN12subSimStreamC1Ev(%cast) : (memref<?x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>) -> ()
    %1 = "polygeist.memref2pointer"(%alloc) : (memref<1x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>) -> !llvm.ptr
    %2 = llvm.mlir.zero : !llvm.ptr
    %3 = llvm.icmp "ne" %1, %2 : !llvm.ptr
    %4 = arith.select %3, %1, %2 : !llvm.ptr
    %5 = llvm.mlir.addressof @str0 : !llvm.ptr
    %6 = llvm.getelementptr %5[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<5 x i8>
    %7 = "polygeist.memref2pointer"(%alloca_0) : (memref<1xi32>) -> !llvm.ptr
    %8 = "polygeist.memref2pointer"(%alloca) : (memref<1xi32>) -> !llvm.ptr
    %9 = llvm.call @scanf(%6, %7, %8) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, !llvm.ptr, !llvm.ptr) -> i32
    %10 = affine.load %alloca_0[0] : memref<1xi32>
    %11 = affine.load %alloca[0] : memref<1xi32>
    %12 = arith.addi %10, %11 : i32
    %13 = llvm.mlir.addressof @str1 : !llvm.ptr
    %14 = llvm.getelementptr %13[0, 0] : (!llvm.ptr) -> !llvm.ptr, !llvm.array<13 x i8>
    %15 = llvm.call @printf(%14, %12) vararg(!llvm.func<i32 (ptr, ...)>) : (!llvm.ptr, i32) -> i32
    llvm.call @free(%4) : (!llvm.ptr) -> ()
    return %c0_i32 : i32
  }
  func.func @_ZN12subSimStreamC1Ev(%arg0: memref<?x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>) attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %0 = "polygeist.memref2pointer"(%arg0) : (memref<?x!llvm.struct<(struct<packed (ptr, i32, array<4 x i8>)>)>>) -> !llvm.ptr
    %1 = "polygeist.pointer2memref"(%0) : (!llvm.ptr) -> memref<?x!llvm.struct<packed (ptr, i32, array<4 x i8>)>>
    call @_ZN9SimStreamC1Ev(%1) : (memref<?x!llvm.struct<packed (ptr, i32, array<4 x i8>)>>) -> ()
    return
  }
  func.func @_ZN9SimStream5vfuncEii(%arg0: memref<?x!llvm.struct<packed (ptr, i32, array<4 x i8>)>>, %arg1: i32, %arg2: i32) -> i32 attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %0 = arith.addi %arg1, %arg2 : i32
    return %0 : i32
  }
  func.func @_ZN9SimStreamC1Ev(%arg0: memref<?x!llvm.struct<packed (ptr, i32, array<4 x i8>)>>) attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %c0_i32 = arith.constant 0 : i32
    %0 = "polygeist.memref2pointer"(%arg0) : (memref<?x!llvm.struct<packed (ptr, i32, array<4 x i8>)>>) -> !llvm.ptr
    %1 = llvm.getelementptr %0[0, 1] : (!llvm.ptr) -> !llvm.ptr, !llvm.struct<packed (ptr, i32, array<4 x i8>)>
    llvm.store %c0_i32, %1 : i32, !llvm.ptr
    return
  }
}
*/

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Reproduce the issue with the provided C++ example in test.cpp using the cgeist command shown, then inspect the generated MLIR around the virtual call and the emitted SimStream and subSimStream functions. The result is complete when a call through SimStream* dispatches to subSimStream::vfunc and produces subtraction rather than the base-class addition.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
30/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.