Skip to content

cgeist errored when trying to compile c++ templated function #431

@alifahrri

Description

@alifahrri

Hi, i tried to compile the following code using cgeist (commit 77c04bb):

template <typename T, auto N>
auto array_test_template(const std::array<T,N>& array)
{
    auto result = std::array<T,N>{};
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
    return result;
}

template auto array_test_template<int,4>(const std::array<int,4>&);

template <typename T>
auto vector_test_template(const std::vector<T>& array)
{
    auto result = std::vector<T>{};
    auto N = array.size();
    result.resize(N);
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
    return result;
}

template auto vector_test_template<int>(const std::vector<int>&);

Both errored when using cgeist but ok when using clang,
error for array version:

toStore.val: %15 = "polygeist.pointer2memref"(%14) : (!llvm.ptr<i8>) -> memref<4xi32> isref 0 isar1
cgeist: /home/fahri/projects/Polygeist/tools/cgeist/Lib/ValueCategory.cc:154: void ValueCategory::store(mlir::Location, mlir::OpBuilder&, ValueCategory, bool) const: Assertion `toStore.isReference' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:

error for vector version:

CXXBindTemporaryExpr 0x57d38ae5e378 'std::vector<int>':'class std::vector<int>' (CXXTemporary 0x57d38ae5e378)
`-CXXTemporaryObjectExpr 0x57d38ae5e340 'std::vector<int>':'class std::vector<int>' 'void (void) noexcept' list zeroing
cleanup not handled
warning: ignoring __builtin_unreachable
warning, not performing catches for try: CXXTryStmt 0x57d38ae8dfb8
|-CompoundStmt 0x57d38ae8de28
| `-CallExpr 0x57d38ae8ddd8 'int *':'int *'
|   |-ImplicitCastExpr 0x57d38ae8ddc0 'int *(*)(int *, unsigned long, allocator<int> &)' <FunctionToPointerDecay>
|   | `-DeclRefExpr 0x57d38ae8dd88 'int *(int *, unsigned long, allocator<int> &)' lvalue Function 0x57d38ae75358 '__uninitialized_default_n_a' 'int *(int *, unsigned long, allocator<int> &)' (FunctionTemplate 0x57d38ac2d900 '__uninitialized_default_n_a')
|   |   `-NestedNameSpecifier Namespace 0x57d38ade9638 'std'
|   |-BinaryOperator 0x57d38ae8da68 'pointer':'int *' '+'
|   | |-ImplicitCastExpr 0x57d38ae8da38 'pointer':'int *' <LValueToRValue>
|   | | `-DeclRefExpr 0x57d38ae8d9f8 'pointer':'int *' lvalue Var 0x57d38ae75aa0 '__new_start' 'pointer':'int *'
|   | `-ImplicitCastExpr 0x57d38ae8da50 'size_type':'unsigned long' <LValueToRValue>
|   |   `-DeclRefExpr 0x57d38ae8da18 'const size_type':'const unsigned long' lvalue Var 0x57d38ae74048 '__size' 'const size_type':'const unsigned long'
|   |-ImplicitCastExpr 0x57d38ae8de10 'size_type':'unsigned long' <LValueToRValue>
|   | `-DeclRefExpr 0x57d38ae8da88 'size_type':'unsigned long' lvalue ParmVar 0x57d38ae50a78 '__n' 'size_type':'unsigned long'
|   `-CXXMemberCallExpr 0x57d38ae8db80 '_Tp_alloc_type':'class std::allocator<int>' lvalue
|     `-MemberExpr 0x57d38ae8db38 '<bound member function type>' ->_M_get_Tp_allocator 0x57d38ae36d58
|       `-ImplicitCastExpr 0x57d38ae8dba0 'struct std::_Vector_base<int, class std::allocator<int> > *' <UncheckedDerivedToBase (_Vector_base)>
|         `-CXXThisExpr 0x57d38ae8db28 'class std::vector<int> *' implicit this
`-CXXCatchStmt 0x57d38ae8df98
  |-<<<NULL>>>
  `-CompoundStmt 0x57d38ae8df78
    |-CXXMemberCallExpr 0x57d38ae8def8 'void'
    | |-MemberExpr 0x57d38ae8de70 '<bound member function type>' ->_M_deallocate 0x57d38ae3a998
    | | `-ImplicitCastExpr 0x57d38ae8df28 'struct std::_Vector_base<int, class std::allocator<int> > *' <UncheckedDerivedToBase (_Vector_base)>
    | |   `-CXXThisExpr 0x57d38ae8de60 'class std::vector<int> *' implicit this
    | |-ImplicitCastExpr 0x57d38ae8df48 'pointer':'int *' <LValueToRValue>
    | | `-DeclRefExpr 0x57d38ae8deb8 'pointer':'int *' lvalue Var 0x57d38ae75aa0 '__new_start' 'pointer':'int *'
    | `-ImplicitCastExpr 0x57d38ae8df60 'size_type':'unsigned long' <LValueToRValue>
    |   `-DeclRefExpr 0x57d38ae8ded8 'const size_type':'const unsigned long' lvalue Var 0x57d38ae758e0 '__len' 'const size_type':'const unsigned long'
    `-CXXThrowExpr 0x57d38ae09ea0 'void'
cleanup of materialized not handledBinaryOperator 0x57d38ae9cda0 'unsigned long' '+'
|-CXXMemberCallExpr 0x57d38ae9c708 'size_type':'unsigned long'
| `-MemberExpr 0x57d38ae9c6d8 '<bound member function type>' ->size 0x57d38ae46560
|   `-CXXThisExpr 0x57d38ae9c6c8 'const class std::vector<int> *' implicit this
`-ImplicitCastExpr 0x57d38ae9cd88 'unsigned long':'unsigned long' <LValueToRValue>
  `-CallExpr 0x57d38ae9cd10 'const unsigned long':'const unsigned long' lvalue
    |-ImplicitCastExpr 0x57d38ae9ccf8 'const unsigned long &(*)(const unsigned long &, const unsigned long &)' <FunctionToPointerDecay>
    | `-ParenExpr 0x57d38ae9ccb0 'const unsigned long &(const unsigned long &, const unsigned long &)' lvalue
    |   `-DeclRefExpr 0x57d38ae9cb48 'const unsigned long &(const unsigned long &, const unsigned long &)' lvalue Function 0x57d38ae9ca38 'max' 'const unsigned long &(const unsigned long &, const unsigned long &)' (FunctionTemplate 0x57d38aaed7c0 'max')
    |     `-NestedNameSpecifier Namespace 0x57d38ac3ebf8 'std'
    |-MaterializeTemporaryExpr 0x57d38ae9cd58 'const size_type':'const unsigned long' lvalue
    | `-ImplicitCastExpr 0x57d38ae9cd40 'const size_type':'const unsigned long' <NoOp>
    |   `-CXXMemberCallExpr 0x57d38ae9c7d8 'size_type':'unsigned long'
    |     `-MemberExpr 0x57d38ae9c7a8 '<bound member function type>' ->size 0x57d38ae46560
    |       `-CXXThisExpr 0x57d38ae9c798 'const class std::vector<int> *' implicit this
    `-ImplicitCastExpr 0x57d38ae9cd70 'const unsigned long':'const unsigned long' lvalue <NoOp>
      `-DeclRefExpr 0x57d38ae9c7f8 'size_type':'unsigned long' lvalue ParmVar 0x57d38ae51d90 '__n' 'size_type':'unsigned long'
cleanup not handled
cleanup of materialized not handledCallExpr 0x57d38ae8d4b0 '_Bool'
|-ImplicitCastExpr 0x57d38ae8d498 '_Bool (*)(true_type)' <FunctionToPointerDecay>
| `-DeclRefExpr 0x57d38ae799c0 '_Bool (true_type)' lvalue CXXMethod 0x57d38ae3eea8 '_S_nothrow_relocate' '_Bool (true_type)'
`-CXXConstructExpr 0x57d38ae8d5a0 'true_type':'struct std::integral_constant<_Bool, true>' 'void (integral_constant<_Bool, true> &&) noexcept'
  `-ImplicitCastExpr 0x57d38ae8d4f0 'integral_constant<_Bool, true>':'struct std::integral_constant<_Bool, true>' xvalue <DerivedToBase (is_move_constructible -> __is_move_constructible_impl -> __is_constructible_impl -> integral_constant)>
    `-MaterializeTemporaryExpr 0x57d38ae8d4d8 '__is_move_insertable<_Tp_alloc_type>':'struct std::__is_move_insertable<class std::allocator<int> >' xvalue
      `-CXXFunctionalCastExpr 0x57d38ae79470 '__is_move_insertable<_Tp_alloc_type>':'struct std::__is_move_insertable<class std::allocator<int> >' functional cast to __is_move_insertable<_Tp_alloc_type> <NoOp>
        `-InitListExpr 0x57d38ae78e58 '__is_move_insertable<_Tp_alloc_type>':'struct std::__is_move_insertable<class std::allocator<int> >'
          `-InitListExpr 0x57d38ae791b0 'is_move_constructible<int>':'struct std::is_move_constructible<int>'
            `-InitListExpr 0x57d38ae79238 '__is_move_constructible_impl<int>':'struct std::__is_move_constructible_impl<int>'
              `-InitListExpr 0x57d38ae792c0 '__is_constructible_impl<int, int &&>':'struct std::__is_constructible_impl<int, int &&>'
                `-InitListExpr 0x57d38ae79348 '__bool_constant<__is_constructible(int, int &&)>':'struct std::integral_constant<_Bool, true>'
cleanup not handled
warning: ignoring __builtin_expect
cgeist: /home/fahri/projects/Polygeist/llvm-project/mlir/lib/IR/PatternMatch.cpp:326: mlir::RewriterBase::eraseOp(mlir::Operation*)::<lambda(mlir::Operation*)>: Assertion `mayBeGraphRegion(*op->getParentRegion()) && "expected that op has no uses"' failed.
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace.
Stack dump:

I also tried another version of the program using raw pointer and std::array version with output parameter (instead of return) and it works with the following ir output:

module attributes {dlti.dl_spec = #dlti.dl_spec<#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<f128, dense<128> : vector<2xi32>>, #dlti.dl_entry<f64, dense<64> : vector<2xi32>>, #dlti.dl_entry<f16, dense<16> : vector<2xi32>>, #dlti.dl_entry<i32, dense<32> : vector<2xi32>>, #dlti.dl_entry<i16, dense<16> : vector<2xi32>>, #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"} {
  func.func @_Z19array_test_templateIiTnDaLi4EEDaRKSt5arrayIT_XT0_EERS2_(%arg0: memref<?x!llvm.struct<(array<4 x i32>)>>, %arg1: memref<?x!llvm.struct<(array<4 x i32>)>>) attributes {llvm.linkage = #llvm.linkage<weak_odr>} {
    %c4 = arith.constant 4 : index
    %c0 = arith.constant 0 : index
    %c1 = arith.constant 1 : index
    %c1_i32 = arith.constant 1 : i32
    scf.for %arg2 = %c0 to %c4 step %c1 {
      %0 = arith.index_cast %arg2 : index to i32
      %1 = arith.extsi %0 : i32 to i64
      %2 = func.call @_ZNSt5arrayIiLm4EEixEm(%arg1, %1) : (memref<?x!llvm.struct<(array<4 x i32>)>>, i64) -> memref<?xi32>
      %3 = func.call @_ZNKSt5arrayIiLm4EEixEm(%arg0, %1) : (memref<?x!llvm.struct<(array<4 x i32>)>>, i64) -> memref<?xi32>
      %4 = affine.load %3[0] : memref<?xi32>
      %5 = arith.addi %4, %c1_i32 : i32
      affine.store %5, %2[0] : memref<?xi32>
    }
    return
  }
  func.func @_ZNSt5arrayIiLm4EEixEm(%arg0: memref<?x!llvm.struct<(array<4 x i32>)>>, %arg1: i64) -> memref<?xi32> attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %0 = "polygeist.memref2pointer"(%arg0) : (memref<?x!llvm.struct<(array<4 x i32>)>>) -> !llvm.ptr
    %1 = "polygeist.pointer2memref"(%0) : (!llvm.ptr) -> memref<4xi32>
    %2 = call @_ZNSt14__array_traitsIiLm4EE6_S_refERA4_Kim(%1, %arg1) : (memref<4xi32>, i64) -> memref<?xi32>
    return %2 : memref<?xi32>
  }
  func.func @_ZNKSt5arrayIiLm4EEixEm(%arg0: memref<?x!llvm.struct<(array<4 x i32>)>>, %arg1: i64) -> memref<?xi32> attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %0 = "polygeist.memref2pointer"(%arg0) : (memref<?x!llvm.struct<(array<4 x i32>)>>) -> !llvm.ptr
    %1 = "polygeist.pointer2memref"(%0) : (!llvm.ptr) -> memref<4xi32>
    %2 = call @_ZNSt14__array_traitsIiLm4EE6_S_refERA4_Kim(%1, %arg1) : (memref<4xi32>, i64) -> memref<?xi32>
    return %2 : memref<?xi32>
  }
  func.func @_Z17raw_test_templateIiTnDaLi4EEDaPKT_PS0_(%arg0: memref<?xi32>, %arg1: memref<?xi32>) attributes {llvm.linkage = #llvm.linkage<weak_odr>} {
    %c4 = arith.constant 4 : index
    %c0 = arith.constant 0 : index
    %c1 = arith.constant 1 : index
    %c1_i32 = arith.constant 1 : i32
    scf.for %arg2 = %c0 to %c4 step %c1 {
      %0 = memref.load %arg0[%arg2] : memref<?xi32>
      %1 = arith.addi %0, %c1_i32 : i32
      memref.store %1, %arg1[%arg2] : memref<?xi32>
    }
    return
  }
  func.func @_ZNSt14__array_traitsIiLm4EE6_S_refERA4_Kim(%arg0: memref<4xi32>, %arg1: i64) -> memref<?xi32> attributes {llvm.linkage = #llvm.linkage<linkonce_odr>} {
    %0 = arith.index_cast %arg1 : i64 to index
    %1 = "polygeist.subindex"(%arg0, %0) : (memref<4xi32>, index) -> memref<?xi32>
    return %1 : memref<?xi32>
  }
}

I'm not sure what happened, but i think the original program is correct, but somehow cgeist failed to convert to mlir polygeist dialect? Does polygeist fully support c++ template features? Any suggestions would be appreciated. Thank you!

Full test progam:

// test0.cpp
// cgeist test0.cpp --std=c++17 --function="*" -S
// clang test0.cpp --std=c++17 -S

#include <array>
#include <vector>

template<typename T>
auto scalar_test_template(T a)
{
    return a + 1;
}

template <typename T, auto N>
auto array_test_template(const std::array<T,N>& array)
{
    auto result = std::array<T,N>{};
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
    return result;
}

template <typename T, auto N>
auto array_test_template(const std::array<T,N>& array, std::array<T,N>& result)
{
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
}

template <typename T>
auto vector_test_template(const std::vector<T>& array)
{
    auto result = std::vector<T>{};
    auto N = array.size();
    result.resize(N);
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
    return result;
}

template <typename T>
auto vector_test_template(const std::vector<T>& array, std::vector<T>& result)
{
    auto N = array.size();
    if (result.size() != N) {
        result.resize(N);
    }
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
}

template <typename T, auto N>
auto raw_test_template(const T* array, T* result)
{
    for (int i=0; i<N; i++) {
        result[i] = array[i] + 1;
    }
}

// int version
template auto scalar_test_template<int>(int);
template auto array_test_template<int,4>(const std::array<int,4>&, std::array<int,4>&);
template auto raw_test_template<int,4>(const int*,int*);

// float version
template auto scalar_test_template<float>(float);
template auto array_test_template<float,4>(const std::array<float,4>&, std::array<float,4>&);
template auto raw_test_template<float,4>(const float*,float*);

// Error on cgeist, ok in clang:

// template auto array_test_template<int,4>(const std::array<int,4>&);

// template auto vector_test_template<int>(const std::vector<int>&);
// template auto vector_test_template<int>(const std::vector<int>&, std::vector<int>&);

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions