Skip to content
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

Invalid C++ Code from AST-Printer at value assignment with reflection #242

Closed
SimeonEhrig opened this issue May 23, 2018 · 5 comments
Closed

Comments

@SimeonEhrig
Copy link
Contributor

SimeonEhrig commented May 23, 2018

Update: The bug is fixed with the version of the CUDA device code compiler. See: #284

This bug occurs at my CUDA implementation, which should merged in to the cling (#240 ). The bug is already in the master of the cling, but has no effect without the CUDA implementation.

Input code in cling

[cling]$ #include "cling/Interpreter/Interpreter.h"
[cling]$ #include "cling/Interpreter/Transaction.h"
[cling]$ #include "llvm/IR/Function.h"
[cling]$ #include "llvm/IR/Module.h"
[cling]$ std::shared_ptr<llvm::Module> M = gCling->getLatestTransaction()->getModule();

Error at cling -xcuda

Description of the workflow

For cuda, I need a second jit (clang target nvptx), which generate code for cuda device side (see. #240 - Concept). To generate the code, I pass all input code of cling direct to the clang (Argument StringRef input of cling::IncrementalParser::ParseInternal()) except one case. If a variable will declared, I need the unwrapped variable declaration. In this case, I use the c++ code, which cling has generated.

https://github.com/SimeonEhrig/cling/blob/46ed41902fa18b81a98b48ea8b9d05fb8eb7f757/lib/Interpreter/IncrementalCUDADeviceCompiler.cpp#L198-L210

This implementation works with the clang AST-Printer.

Input of the clang cuda jit

#include <new>

#include "cling/Interpreter/RuntimeUniverse.h"
namespace cling { class Interpreter; namespace runtime { Interpreter* gCling=(Interpreter*)0x7fffffffd150;}}
extern "C" int __cxa_atexit(void (*f)(void*), void*, void*)  noexcept;
#define __dso_handle ((void*)0x7fffffffd150)
extern "C" int atexit(void(*f)())  throw ()  { return __cxa_atexit((void(*)(void*))f, 0, __dso_handle); }
extern "C++" int at_quick_exit(void(*f)())  throw ()  { return __cxa_atexit((void(*)(void*))f, 0, __dso_handle); }

#include "cling/Interpreter/Interpreter.h"
#include "cling/Interpreter/Transaction.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"

// printed via AST-Printer
constexpr bool value;
constexpr bool value;
std::shared_ptr<llvm::Module> M = (const cling::Transaction *)cling_runtime_internal_throwIfInvalidPointer((void *)140723068407056UL, (void *)94197571161392UL, (const void *)(const cling::Interpreter *)cling_runtime_internal_throwIfInvalidPointer((void *)140723068407056UL, (void *)94197571161432UL, (const void *)gCling)->getLatestTransaction())->getModule();
constexpr bool value;
constexpr bool value;

Error message of clang cuda jit

[cling]$ #include "cling/Interpreter/Interpreter.h"
[cling]$ #include "cling/Interpreter/Transaction.h"
[cling]$ #include "llvm/IR/Function.h"
[cling]$ #include "llvm/IR/Module.h"
[cling]$ std::shared_ptr<llvm::Module> M = gCling->getLatestTransaction()->getModule();
/tmp/cling-1880/cling6.cu:1:16: error: default initialization of an object of const type 'const bool'
constexpr bool value;
               ^
                     = false
/tmp/cling-1880/cling6.cu:2:16: error: redefinition of 'value'
constexpr bool value;
               ^
/tmp/cling-1880/cling6.cu:1:16: note: previous definition is here
constexpr bool value;
               ^
/tmp/cling-1880/cling6.cu:3:298: error: member reference base type 'void' is not a structure or union
  ...(void *)94600387748952UL, (const void *)(const cling::Interpreter *)cling_runtime_internal_throwIfInvalidPointer((void *)140736302475680UL, (void *)94600387748992UL, (const void *)gCling)->getLatestTransaction())->getModule();
                                                                         ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~^ ~~~~~~~~~~~~~~~~~~~~
/tmp/cling-1880/cling6.cu:4:16: error: redefinition of 'value'
constexpr bool value;
               ^
/tmp/cling-1880/cling6.cu:1:16: note: previous definition is here
constexpr bool value;
               ^
/tmp/cling-1880/cling6.cu:5:16: error: redefinition of 'value'
constexpr bool value;
               ^
/tmp/cling-1880/cling6.cu:1:16: note: previous definition is here
constexpr bool value;
               ^
5 errors generated.
error at launching clang instance to generate PCH file

[cling]$ 

Dump of Module in cling (-x c++)

The dump() function of the cling::Transaction also use the AST-Printer. I dumped the Transaction at the end of the function cling::IncrementalParser::ParseInternal(). The content is the same, like the input of my cuda jit.

[cling]$ auto M1 = gCling->getLatestTransaction()->getModule();

Breakpoint 1, cling::IncrementalParser::ParseInternal (this=0x55555579db50, input=...)
    at $HOME/cling/src/tools/cling/lib/Interpreter/IncrementalParser.cpp:808
808	    return kSuccess;
(gdb) p m_Consumer->getTransaction()->dump()
kCCIHandleCXXStaticMemberVarInstantiation <- constexpr bool value
kCCIHandleCXXStaticMemberVarInstantiation <- constexpr bool value
kCCIHandleCXXImplicitFunctionInstantiation <- shared_ptr(std::shared_ptr<llvm::Module> &&__r) noexcept : __shared_ptr<llvm::Module>(std::move(__r)) {
}

kCCIHandleTopLevelDecl <- auto M1 = (const cling::Transaction *)cling_runtime_internal_throwIfInvalidPointer((void *)140737488343376UL, (void *)93825115123096UL, (const void *)(const cling::Interpreter *)cling_runtime_internal_throwIfInvalidPointer((void *)140737488343376UL, (void *)93825115123136UL, (const void *)gCling)->getLatestTransaction())->getModule()
kCCIHandleTopLevelDecl <- void __cling_Un1Qu30(void *vpClingValue) {
    M1;
    ;
}

kCCIHandleTagDeclDefinition <- template<> struct remove_reference<std::shared_ptr<llvm::Module> &> {
    typedef std::shared_ptr<llvm::Module> type;
}
kCCIHandleTopLevelDecl <- template<> constexpr typename std::remove_reference<shared_ptr<Module> &>::type &&move<std::shared_ptr<llvm::Module> &>(std::shared_ptr<llvm::Module> &&__t) noexcept {
    return static_cast<typename std::remove_reference<shared_ptr<Module> &>::type &&>(__t);
}

kCCIHandleCXXStaticMemberVarInstantiation <- constexpr bool value
kCCIHandleCXXStaticMemberVarInstantiation <- constexpr bool value
kCCIHandleCXXImplicitFunctionInstantiation <- __shared_ptr(std::__shared_ptr<llvm::Module, __gnu_cxx::_Lock_policy::_S_atomic> &&__r) noexcept : __shared_ptr_access<llvm::Module, (__gnu_cxx::_Lock_policy)2U>(), _M_ptr(__r._M_ptr), _M_refcount() {
    this->_M_refcount._M_swap(__r._M_refcount);
    __r._M_ptr = 0;
}

kCCIHandleTopLevelDecl <- shared_ptr(std::shared_ptr<llvm::Module> &&__r) noexcept : __shared_ptr<llvm::Module>(std::move(__r)) {
}

kCCIHandleTopLevelDecl <- __shared_ptr(std::__shared_ptr<llvm::Module, __gnu_cxx::_Lock_policy::_S_atomic> &&__r) noexcept : __shared_ptr_access<llvm::Module, (__gnu_cxx::_Lock_policy)2U>(), _M_ptr(__r._M_ptr), _M_refcount() {
    this->_M_refcount._M_swap(__r._M_refcount);
    __r._M_ptr = 0;
}

$1 = void
(gdb) 

Possible reasons

I think, there are two bugs. The first is the generation of constexpr bool value. The second is the wrong semantic of the value assignment of "M".

constexpr bool value

I don't know, why the expressions are generated but they cause two errors. constexpr needs an assignment and there are redefinition errors, because the statement exists four times.

M assignment

I think, it is a problem of the AST-Printer. If I add two pairs of brackets, the semantic is OK.

// generated by the AST-Printer
std::shared_ptr<llvm::Module> M = (const cling::Transaction *)cling_runtime_internal_throwIfInvalidPointer((void *)140723068407056UL, (void *)94197571161392UL, (const void *)(const cling::Interpreter *)cling_runtime_internal_throwIfInvalidPointer((void *)140723068407056UL, (void *)94197571161432UL, (const void *)gCling)->getLatestTransaction())->getModule();
// repaired version
std::shared_ptr<llvm::Module> M = ((const cling::Transaction *)cling_runtime_internal_throwIfInvalidPointer((void *)140737488343376UL, (void *)93825124585336UL, (const void *)((const cling::Interpreter *)cling_runtime_internal_throwIfInvalidPointer((void *)140737488343376UL, (void *)93825124585376UL, (const void *)gCling))->getLatestTransaction()))->getModule();

I don't know, if my brackets are OK and the function still do the right thing, but it compiles.

Questions and possible solutions

I try to solve the problems but I need some information to develop a working solution.

  1. What is the purpose of the constexpr bool value?
  2. Are the brackets OK at my M assignment?
  3. Is there any property, which show me, that the clang::VarDecl is same, as the declaration in the original wrapper function?

If the constexpr bool value is just relevant for cling internals, I would overwork the filter and just send the value assignment, which was original inside the wrapper function.

if(clang::VarDecl * v = llvm::dyn_cast<clang::VarDecl>(decl)){

https://github.com/SimeonEhrig/cling/blob/46ed41902fa18b81a98b48ea8b9d05fb8eb7f757/lib/Interpreter/IncrementalCUDADeviceCompiler.cpp#L202

If the M assignment problem is a AST-Printer bug, I hope anyone of the cling-team or the clang-community (I would open a bug report) can fix the problem. I'm not really familiar with the AST-Printer implementation.

@SimeonEhrig
Copy link
Contributor Author

@Axel-Naumann @vgvassilev

@Axel-Naumann
Copy link
Member

Axel-Naumann commented May 24, 2018

Could you check what the DeclContext of these constexpr bool value is? I bet they are members. Dumping a VarDecl doesn't dump its DeclContext...

Note also that the transaction only keeps decls that are relevant for CodeGen, which is probably not enough for your case! I need to think how else to do it...

@SimeonEhrig
Copy link
Contributor Author

You are right. constexpr bool value is a member and a specialization of the struct std::integral_constant.
The right statement should be constexpr bool value = true.
Here is a reduced output from my gdb (I used cling -xcuda for easier debug):

(gdb) p v->dump()
VarDecl 0x5555580858a8 parent 0x5555561a7040 prev 0x5555561bb620 </usr/include/c++/7/type_traits:84:5, col:48> col:48 used value 'const _Bool':'const _Bool' constexpr
$6 = void
(gdb) p v->getDeclContext()->getDeclKindName()
$7 = 0x7ffff13e2a8a "ClassTemplateSpecialization"
(gdb) p v->getDeclContext()->dumpDeclContext()
static constexpr bool value = true;
typedef bool value_type;
typedef integral_constant<bool, true> type;
constexpr operator value_type() const noexcept __attribute__((host)) __attribute__((device));
$9 = void
(gdb) p v->getDeclContext()->getParent()->dumpDeclContext()
template <typename _Tp, _Tp __v> struct integral_constant {
    static constexpr _Tp value = __v;
    typedef _Tp value_type;
    typedef integral_constant<_Tp, __v> type;
    constexpr operator value_type() const noexcept __attribute__((host)) __attribute__((device))     {
        return value;
    }
};

The full gdb dump: DeclContext.txt

I have a idea to solve this problem. clang::VarDecl has the method isStaticDataMember(). In case of constexpr bool value the return value is true. In case of the variable declaration is it false. I could use the function, to filter the input of the clang nvptx jit. Do you think, it is a good idea?

@Axel-Naumann
Copy link
Member

Axel-Naumann commented May 25, 2018

You should only iterate over kCCIHandleTopLevelDecl elements; you will need to surround them with namespace FOO { etc if they are inside a namespace or LinkageSpec.

@SimeonEhrig
Copy link
Contributor Author

Solved with #284

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