Result reshuffling during instruction selection - tuples

In an LLVM backend, during instruction selection, my input looks something like this:
t17: i16,ch = load t16:1, t2, undef:i16
I'd like to select an opcode that has some extra result as well, i.e. replace the above with something like
t17: i16, _: i16, ch = LDW t2, undef:i16
Of course, if I just try to replace the load with this LDW, it fails because the return types are not the same:
llc: lib/CodeGen/SelectionDAG/SelectionDAG.cpp:6525:
void llvm::SelectionDAG::ReplaceAllUsesWith(llvm::SDNode*, llvm::SDNode*):
Assertion `(!From->hasAnyUseOfValue(i) || From->getValueType(i) == To->getValueType(i)) &&
"Cannot use this version of ReplaceAllUsesWith!"' failed.
That's because for i == 1, From->getValueType(i) is ch, and To->getValueType(i) is i16.
My question is, how do I re-shuffle the tuple (x: i16, y: i16, ch) into (x : i16, ch) during instruction selection? I.e. how would I do something like
t17 : i16, ch = project [0, 2] (LDW t2, undef:i16)
where project [0, 2] would be some magic tuple-reshuffling pseudo-instruction that just takes care of dropping coordinate 1?
EDIT: Found what seemed like a possible solution, but still doesn't work
I found that there's a MERGE_VALUES node type which should make what I'm trying to do possible, since it allows taking some inputs and packing them into a multi-value output. So I tried
SDNode* LDW = CurDAG->getMachineNode(
AVR::LDWRdPtr, SDLoc(N), VT, PtrVT, MVT::Other,
LD->getBasePtr(), LD->getChain());
SDValue Unpack[] = { SDValue(LDW, 0), SDValue(LDW, 2) };
SDNode* NN = CurDAG->getMergeValues(Unpack, SDLoc(N)).getNode();
ReplaceNode(N, NN);
If I run instruction selection with --debug, this looks very promising, since it turns this:
SelectionDAG has 16 nodes:
t0: ch = EntryToken
t2: i16,ch = CopyFromReg t0, Register:i16 %vreg0
t5: i16,ch = load<LD2[%v25](align=1)(dereferenceable)> t0, t2, undef:i16
t9: ch,glue = callseq_start t5:1, TargetConstant:i16<0>
t11: ch,glue = CopyToReg t9, Register:i16 %R25R24, t5
t13: ch,glue = CALL t11, TargetGlobalAddress:i16<i8 (i16)* #read_ram> 0, Register:i16 %R25R24, RegisterMask:Untyped, t11:1
t14: ch,glue = callseq_end t13, TargetConstant:i16<0>, TargetConstant:i16<0>, t13:1
t16: i8,ch,glue = CopyFromReg t14, Register:i8 %R24, t14:1
t17: ch = RET_FLAG t16:1
into this:
SelectionDAG has 16 nodes:
t0: ch = EntryToken
t9: i16,ch,glue = ADJCALLSTACKDOWN TargetConstant:i16<0>, t19:1
t11: ch,glue = CopyToReg t9:1, Register:i16 %R25R24, t19
t13: ch,glue = CALLk TargetGlobalAddress:i16<i8 (i16)* #read_ram> 0, Register:i16 %R25R24, RegisterMask:Untyped, t11, t11:1
t14: i16,ch,glue = ADJCALLSTACKUP TargetConstant:i16<0>, TargetConstant:i16<0>, t13, t13:1
t2: i16,ch = CopyFromReg t0, Register:i16 %vreg0
t18: i16,i16,ch = LDWRdPtr t2, t0
t19: i16,ch = merge_values t18, t18:2
t16: i8,ch,glue = CopyFromReg t14:1, Register:i8 %R24, t14:2
t17: ch = RET t16:1
which looks fine to me: t18,_,ch is where we store the result of LDW, then t19,ch unpacks it.
However, this later trips up instruction scheduling:
llc: CodeGen/SelectionDAG/InstrEmitter.cpp:305:
unsigned int llvm::InstrEmitter::getVR(llvm::SDValue, llvm::DenseMap<llvm::SDValue, unsigned int>&):
Assertion `I != VRBaseMap.end() && "Node emitted out of order - late"' failed.
#9 0x0000000001a7eae8 llvm::InstrEmitter::getVR(llvm::SDValue, llvm::DenseMap<llvm::SDValue, unsigned int, llvm::DenseMapInfo<llvm::SDValue>, llvm::detail::DenseMapPair<llvm::SDValue, unsigned int> >&) CodeGen/SelectionDAG/InstrEmitter.cpp:305:0
#10 0x0000000001a819c2 llvm::InstrEmitter::EmitSpecialNode(llvm::SDNode*, bool, bool, llvm::DenseMap<llvm::SDValue, unsigned int, llvm::DenseMapInfo<llvm::SDValue>, llvm::detail::DenseMapPair<llvm::SDValue, unsigned int> >&) CodeGen/SelectionDAG/InstrEmitter.cpp:928:0
#11 0x0000000001971c9c llvm::InstrEmitter::EmitNode(llvm::SDNode*, bool, bool, llvm::DenseMap<llvm::SDValue, unsigned int, llvm::DenseMapInfo<llvm::SDValue>, llvm::detail::DenseMapPair<llvm::SDValue, unsigned int> >&) CodeGen/SelectionDAG/InstrEmitter.h:124:0
#12 0x0000000001988bdb llvm::ScheduleDAGSDNodes::EmitSchedule(llvm::MachineInstrBundleIterator<llvm::MachineInstr, false>&) CodeGen/SelectionDAG/ScheduleDAGSDNodes.cpp:841:0
#13 0x0000000001a33cdc llvm::SelectionDAGISel::CodeGenAndEmitDAG() CodeGen/SelectionDAG/SelectionDAGISel.cpp:890:0

Related

QT: sqlite and qlist issue

I have a multithread application which accesses a DB from multiple thread, and randomically I fall in this error (not the same query)...
__GI___libc_free (mem=0x7fff00042660) at /build/glibc-vjB4T1/glibc-2.28/malloc/malloc.c:3093
QList<_RData>::node_destruct (this=0x7fffebffce08, from=0x7fffe4037fc0, to=0x7fffe4037fd8) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h:494
QList<_RData>::dealloc (this=0x7fffebffce08, data=0x7fffe4037fb0) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h:865
QList<_RData>::~QList (this=0x7fffebffce08) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h:827
QList<_RData>::operator= (this=0x55555565cd68, other=#0x7fffebffd880: {<QListSpecialMethods<_RoomData>> = {<No data fields>}, {p = {static shared_null = {ref = {atomic = {_q_value = {<std::__atomic_base<int>> = {static _S_alignment = 4, _M_i = -1}, <No data fields>}}}, alloc = 0, begin = 0, end = 0, array = {0x0}}, d = 0x7ffff6ff76c0 <QListData::shared_null>}, d = 0x7ffff6ff76c0 <QListData::shared_null>}}) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qlist.h:159
AMProcess::doActionAM (this=0x55555565cc30) at /smart/software/AudioIO/AMProcess.cpp:453
QtPrivate::FunctorCall<QtPrivate::IndexesList<>, QtPrivate::List<>, void, void (AMProcess::*)()>::call(void (AMProcess::*)(), AMProcess*, void**) (f=(void (AMProcess::*)(AMProcess * const)) 0x5555555b943c <AMProcess::doActionAM()>, o=0x55555565cc30, arg=0x7fffebffee40) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:134
QtPrivate::FunctionPointer<void (AMProcess::*)()>::call<QtPrivate::List<>, void>(void (AMProcess::*)(), AMProcess*, void**) (f=(void (AMProcess::*)(AMProcess * const)) 0x5555555b943c <AMProcess::doActionAM()>, o=0x55555565cc30, arg=0x7fffebffee40) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:167
QtPrivate::QSlotObject<void (AMProcess::*)(), QtPrivate::List<>, void>::impl(int, QtPrivate::QSlotObjectBase*, QObject*, void**, bool*) (which=1, this_=0x555555661cf0, r=0x55555565cc30, a=0x7fffebffee40, ret=0x0) at /usr/include/x86_64-linux-gnu/qt5/QtCore/qobjectdefs_impl.h:396
QMetaObject::activate(QObject*, int, int, void**) () at null:
QThread::started(QThread::QPrivateSignal) () at null:
?? () at null:
start_thread (arg=<optimized out>) at /build/glibc-vjB4T1/glibc-2.28/nptl/pthread_create.c:486
clone () at /build/glibc-vjB4T1/glibc-2.28/misc/../sysdeps/unix/sysv/linux/x86_64/clone.S:95
This is some snippets of my code
rData = DBRManager::ReadRData("R", m_connName);
if (rData.size() > 0) {
}
...and this is the query
QList<_RData> DBRManager::ReadRData(QString tbName, QString dbName)
{
QList<_RData> records;
QSqlQuery query(QSqlDatabase::database(dbName));
query.setForwardOnly(true);
query.exec("DSQLITE_THREADSAFE=2");
query.exec("SELECT * FROM " + tbName);
while (query.next()) {
_RData data;
data.id = query.value("id").toInt();
data.type = query.value("type").toInt();
records.append(data);
}
query.finish();
return records;
}

LLVM pass for generating object code is giving segmentation fault

I'm writing a C-subset compiler using the LLVM C++ API, and using a pass for generating object code as well. But the object code generation step is giving segfault when the source files include an if-else block. Below are the codes I'm using
Compiler code for generating the if-else block
llvm::Value *Conditional::generateCode(CodeKit &kit) {
auto *cond = condition->generateCode(kit);
if (cond == nullptr) {
return nullptr;
}
llvm::Function *func = kit.builder.GetInsertBlock()->getParent();
auto *ifBlock = llvm::BasicBlock::Create(kit.context, "if", func);
auto *elseBlock = llvm::BasicBlock::Create(kit.context, "else");
auto *mergeBlock = llvm::BasicBlock::Create(kit.context, "ifelsemerge");
kit.builder.CreateCondBr(cond, ifBlock, elseBlock);
kit.builder.SetInsertPoint(ifBlock);
if (ifstmt != nullptr) {
kit.symbolTable.enterScope();
ifstmt->generateCode(kit);
kit.symbolTable.exitScope();
}
kit.builder.CreateBr(mergeBlock);
ifBlock = kit.builder.GetInsertBlock();
func->getBasicBlockList().push_back(elseBlock);
kit.builder.SetInsertPoint(elseBlock);
if (elsestmt != nullptr) {
kit.symbolTable.enterScope();
elsestmt->generateCode(kit);
kit.symbolTable.exitScope();
}
kit.builder.CreateBr(mergeBlock);
elseBlock = kit.builder.GetInsertBlock();
func->getBasicBlockList().push_back(mergeBlock);
kit.builder.SetInsertPoint(mergeBlock);
return nullptr;
Code for generating object code from the llvm module.
void emitCode(CodeKit &kit) {
kit.module.print(llvm::outs(), nullptr);
auto irFile = "output.bc";
error_code ec;
llvm::raw_fd_ostream irFileStream(irFile, ec, llvm::sys::fs::F_None);
llvm::WriteBitcodeToFile(kit.module, irFileStream);
irFileStream.flush();
auto targetTriple = llvm::sys::getDefaultTargetTriple();
llvm::InitializeAllTargetInfos();
llvm::InitializeAllTargets();
llvm::InitializeAllTargetMCs();
llvm::InitializeAllAsmParsers();
llvm::InitializeAllAsmPrinters();
string error;
auto target = llvm::TargetRegistry::lookupTarget(targetTriple, error);
auto cpu = "generic";
auto features = "";
llvm::TargetOptions opt;
auto rm = llvm::Optional<llvm::Reloc::Model>();
auto targetMachine =
target->createTargetMachine(targetTriple, cpu, features, opt, rm);
kit.module.setDataLayout(targetMachine->createDataLayout());
kit.module.setTargetTriple(targetTriple);
auto objectFile = "output.o";
llvm::raw_fd_ostream objectFileStream(objectFile, ec,
llvm::sys::fs::OF_None);
llvm::legacy::PassManager pass;
auto fileType = llvm::CGFT_ObjectFile;
targetMachine->addPassesToEmitFile(pass, objectFileStream, nullptr,
fileType);
pass.run(kit.module);
objectFileStream.flush();
}
Source file on which I'm testing at the moment
int factorial(int n) {
if (n <= 0)
return 1;
else
return n * factorial(n - 1);
}
Generated IR code
; ModuleID = 'bootleg c compiler'
source_filename = "bootleg c compiler"
define i32 #factorial(i32 %n) {
entry:
%n1 = alloca i32
store i32 %n, i32* %n1
%n2 = load i32, i32* %n1
%"Less or Equal" = icmp sle i32 %n2, 0
br i1 %"Less or Equal", label %if, label %else
if: ; preds = %entry
ret i32 1
br label %ifelsemerge
else: ; preds = %entry
%n3 = load i32, i32* %n1
%n4 = load i32, i32* %n1
%Subtract = sub i32 %n4, 1
%call = call i32 #factorial(i32 %Subtract)
%Multiply = mul i32 %n3, %call
ret i32 %Multiply
br label %ifelsemerge
ifelsemerge: ; preds = %else, %if
}
GDB stack trace of the segfault
#0 0x00007ffff4386bc0 in llvm::Instruction::getNumSuccessors() const () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#1 0x00007ffff4fd643c in llvm::BranchProbabilityInfo::computePostDominatedByUnreachable(llvm::Function const&, llvm::PostDominatorTree*) ()
from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#2 0x00007ffff4fdb175 in llvm::BranchProbabilityInfo::calculate(llvm::Function const&, llvm::LoopInfo const&, llvm::TargetLibraryInfo const*) ()
from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#3 0x00007ffff4fdb9c4 in llvm::BranchProbabilityInfoWrapperPass::runOnFunction(llvm::Function&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#4 0x00007ffff43a7d76 in llvm::FPPassManager::runOnFunction(llvm::Function&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#5 0x00007ffff43a7ff3 in llvm::FPPassManager::runOnModule(llvm::Module&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#6 0x00007ffff43a84a0 in llvm::legacy::PassManagerImpl::run(llvm::Module&) () from /lib/x86_64-linux-gnu/libLLVM-10.so.1
#7 0x0000555555565b73 in emitCode (kit=...) at c.ast.cpp:88
#8 0x0000555555579957 in generateCode (ast=...) at cc.cpp:25
#9 0x0000555555579a83 in main (argc=2, argv=0x7fffffffdfe8) at cc.cpp:41
ret i32 1
br label %ifelsemerge
is invalid IR, you must have exactly one terminator instruction (e.g. br or ret) in a BasicBlock. You can avoid this by checking for a terminator instruction before inserting the branch,
if (ifBlock->size() == 0 || !ifBlock->back().isTerminator()) {
kit.builder.CreateBr(mergeBlock);
}
// ...
if (elseBlock->size() == 0 || !elseBlock->back().isTerminator()) {
kit.builder.CreateBr(mergeBlock);
}
Note that empty blocks are also invalid so in case both branches of the conditional exit the function, you probably shouldn't generate mergeBlock. AFAIK if you have no branches to an empty block it's fine to leave it in.
Usually you can catch these kinds of bugs in your front-end by adding a verification pass or using llvm::verifyFunction or llvm::verifyModule. Also running llc with the generated IR code will give a more detailed error message.

How can i fix Onnxruntime session->Run problem?

I am trying to write a wrapper for onnxruntime.
The model receives one tensor as an input and one tensor as an output.
During session->Run, a segmentation error occurs inside the onnxruntime library. Both downloaded library and built from source throw the same error.
Here is error:
Thread 1 "app" received signal SIGSEGV, Segmentation fault.
0x00007ffff6b16eb1 in onnxruntime::logging::ISink::Send (this=0x5555559154c0, timestamp=..., logger_id="", message=...) at /home/listray/Work/Libs/onnxruntime/include/onnxruntime/core/common/logging/isink.h:23
23 SendImpl(timestamp, logger_id, message);
Here is bt:
#0 0x00007ffff6b16eb1 in onnxruntime::logging::ISink::Send (this=0x5555559154c0, timestamp=..., logger_id="", message=...)
at /home/listray/Work/Libs/onnxruntime/include/onnxruntime/core/common/logging/isink.h:23
#1 0x00007ffff6b174b8 in onnxruntime::logging::LoggingManager::Log (this=0x55555576cbb0, logger_id="", message=...) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/common/logging/logging.cc:153
#2 0x00007ffff6b16cae in onnxruntime::logging::Logger::Log (this=0x7fffffffcdd0, message=...) at /home/listray/Work/Libs/onnxruntime/include/onnxruntime/core/common/logging/logging.h:291
#3 0x00007ffff6b16ce0 in onnxruntime::logging::Capture::~Capture (this=0x7fffffffc4e0, __in_chrg=<optimized out>) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/common/logging/capture.cc:57
#4 0x00007ffff6a86301 in onnxruntime::SequentialExecutor::Execute(onnxruntime::SessionState const&, std::vector<int, std::allocator<int> > const&, std::vector<OrtValue, std::allocator<OrtValue> > const&, std::vector<int, std::allocator<int> > const&, std::vector<OrtValue, std::allocator<OrtValue> >&, std::unordered_map<unsigned long, std::function<onnxruntime::common::Status (onnxruntime::TensorShape const&, OrtMemoryInfo const&, OrtValue&, bool&)>, std::hash<unsigned long>, std::equal_to<unsigned long>, std::allocator<std::pair<unsigned long const, std::function<onnxruntime::common::Status (onnxruntime::TensorShape const&, OrtMemoryInfo const&, OrtValue&, bool&)> > > > const&, onnxruntime::logging::Logger const&) (this=0x5555559da4c0, session_state=..., feed_mlvalue_idxs=std::vector of length 1, capacity 1 = {...},
feeds=std::vector of length 1, capacity 1 = {...}, fetch_mlvalue_idxs=std::vector of length 1, capacity 1 = {...}, fetches=std::vector of length 1, capacity 1 = {...},
fetch_allocators=std::unordered_map with 0 elements, logger=...) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/framework/sequential_executor.cc:309
#5 0x00007ffff6a6d787 in onnxruntime::utils::ExecuteGraphImpl(const onnxruntime::SessionState &, const onnxruntime::FeedsFetchesManager &, const std::vector<OrtValue, std::allocator<OrtValue> > &, std::vector<OrtValue, std::allocator<OrtValue> > &, const std::unordered_map<long unsigned int, std::function<onnxruntime::common::Status(const onnxruntime::TensorShape&, const OrtMemoryInfo&, OrtValue&, bool&)>, std::hash<long unsigned int>, std::equal_to<long unsigned int>, std::allocator<std::pair<long unsigned int const, std::function<onnxruntime::common::Status(const onnxruntime::TensorShape&, const OrtMemoryInfo&, OrtValue&, bool&)> > > > &, ExecutionMode, const bool &, const onnxruntime::logging::Logger &, bool) (session_state=..., feeds_fetches_manager=..., feeds=std::vector of length 1, capacity 1 = {...},
fetches=std::vector of length 1, capacity 1 = {...}, fetch_allocators=std::unordered_map with 0 elements, execution_mode=ORT_SEQUENTIAL, terminate_flag=#0x7fffffffd168: false, logger=...,
only_execute_path_to_fetches=false) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/framework/utils.cc:454
#6 0x00007ffff6a6df37 in onnxruntime::utils::ExecuteGraph (session_state=..., feeds_fetches_manager=..., feeds=std::vector of length 1, capacity 1 = {...}, fetches=std::vector of length 1, capacity 1 = {...},
execution_mode=ORT_SEQUENTIAL, terminate_flag=#0x7fffffffd168: false, logger=..., only_execute_path_to_fetches=false) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/framework/utils.cc:513
#7 0x00007ffff63e00c2 in onnxruntime::InferenceSession::Run (this=0x555555917110, run_options=..., feed_names=std::vector of length 1, capacity 1 = {...}, feeds=std::vector of length 1, capacity 1 = {...},
output_names=std::vector of length 1, capacity 1 = {...}, p_fetches=0x7fffffffd120) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/session/inference_session.cc:1206
#8 0x00007ffff637ecc3 in OrtApis::Run (sess=0x555555917110, run_options=0x0, input_names=0x5555559c1a10, input=0x7fffffffd2f8, input_len=1, output_names1=0x555555a521a0, output_names_len=1,
output=0x555555a3fb30) at /home/listray/Work/Libs/onnxruntime/onnxruntime/core/session/onnxruntime_c_api.cc:506
#9 0x00007ffff7ba6a93 in Ort::Session::Run (this=0x555555916440, run_options=..., input_names=0x5555559c1a10, input_values=0x7fffffffd2f8, input_count=1, output_names=0x555555a521a0,
output_values=0x555555a3fb30, output_count=1) at /home/listray/Work/Libs/onnx_debug/include/onnxruntime_cxx_inline.h:246
#10 0x00007ffff7ba69da in Ort::Session::Run (this=0x555555916440, run_options=..., input_names=0x5555559c1a10, input_values=0x7fffffffd2f8, input_count=1, output_names=0x555555a521a0, output_names_count=1)
at /home/listray/Work/Libs/onnx_debug/include/onnxruntime_cxx_inline.h:237
#11 0x00007ffff7bb0b31 in ai::common::OnnxruntimeGenericModelWrapper<1ul, 1ul>::process (this=0x55555576cb60, tensors=...)
at /home/listray/Work/Projects/ml-library/framework/onnxruntime/onnx_generic_model_wrapper.h:48
...
The downloaded library stops at onnxruntime::logging::LoggingManager::Log.
Here is some wrapper code.
Loading the model:
void load_graph(const ByteBuffer& model)
{
// enviroment maintains thread pools and other state info
Ort::Env env(ORT_LOGGING_LEVEL_WARNING, "Vicue Run");
// initialize session options
Ort::SessionOptions session_options(nullptr);
//session_options.SetIntraOpNumThreads(1);
//Loading models
session = std::make_unique<Ort::Session>(env,
static_cast<const void*>(model.data.get()),
model.length,
session_options);
}
session is wrapper's field:
std::unique_ptr<Ort::Session> session;
ByteBuffer:
struct ByteBuffer
{
std::unique_ptr<char[]> data;
size_t length;
}
Actually wrapper was generic, but this code gets the same error.
std::array<Tensor, outputs> process(std::array<Tensor, inputs> tensors) override
{
std::array<Tensor, outputs> result;
// maybe this should be different if we have multiple input
Ort::AllocatorWithDefaultOptions allocator;
auto memory_info = Ort::MemoryInfo::CreateCpu(OrtArenaAllocator, OrtMemTypeDefault);
if(outputs == 1 && inputs == 1) {
auto input_shape = session->GetInputTypeInfo(0).GetTensorTypeAndShapeInfo().GetShape();
Ort::Value input_tensor = Ort::Value::CreateTensor<float>(memory_info,
tensors[0].data.data(),
tensors[0].data.size(),
input_shape.data(),
input_shape.size());
std::vector<const char*> input_node_names = { session->GetInputName(0, allocator) };
std::vector<const char*> output_node_names = { session->GetOutputName(0, allocator) };
std::vector<Ort::Value> output_tensors = session->Run(Ort::RunOptions{nullptr},
input_node_names.data(),
&input_tensor,
inputs,
output_node_names.data(),
outputs);
One strange thing that I don't understand. During an error i see this:
(gdb) print this
$4 = (onnxruntime::logging::Capture * const) 0x7fffffffc4e0
(gdb) print this->logger_->logging_manager_->sink_
$5 = std::unique_ptr<onnxruntime::logging::ISink> = {get() = 0x5555559154c0}
(gdb) print *(this->logger_->logging_manager_->sink_)
$6 = {_vptr.ISink = 0x0}
When the logger is created, its *(logging_manager_->sink_) is also {_vptr.ISink = 0x0}.
I do not have the complete idea of your code structure but try making Ort::Env variable static.

Template instantiation with Armadillo and boost::numeric::odeint

I am trying to combine boost::numeric::odeint with an implementation of the System class of my own (see System.hpp).
A (template) System object is used within a BatchFilter class method, like so:
# BatchFilter.cpp
# template <typename state_type> BatchFilter class {...}
System<state_type> dynamics(this -> args,
N_true,
this -> true_dynamics_fun );
typedef boost::numeric::odeint::runge_kutta_cash_karp54< state_type > error_stepper_type;
auto stepper = boost::numeric::odeint::make_controlled<error_stepper_type>( 1.0e-13 , 1.0e-16 );
auto tbegin = T_obs.begin();
auto tend = T_obs.end();
boost::numeric::odeint::integrate_times(stepper, dynamics, X0_true_copy, tbegin, tend,0.1,
Observer::push_back_state(this -> true_state_history));
BatchFilter is a template derived class which I am explicitly instantiating at the bottom of BatchFilter.cpp. The two explicit instantiations are
template class BatchFilter< arma::vec >;
template class BatchFilter< arma::vec::fixed<2> >;
The Base class is also explicitly instantiated. I must use arma::vec::fixed<2> since using arma::vec within odeint causes a runtime crash as the state will not have the proper size.
What does not work?
The instantiation with arma::vec::fixed<2> fails while the one with arma::vec succeeds. The compiler complains about an illegal binding:
cannot bind non-const lvalue reference of type'arma::Col<double>::fixed<2>&' to an rvalue of type'arma::Col<double>::fixed<2>' sys( x , m_dxdt.m_v ,t );
What puzzles me is that everything works fine when the explicit instantiation of BatchFilter< arma::vec > succeeds while BatchFilter< arma::vec::fixed<2> > fails.
Any insight as to what is going on?
[ 3%] Building CXX object CMakeFiles/ASPEN.dir/source/BatchFilter.cpp.o
In file included from /usr/local/include/boost/numeric/odeint.hpp:35:0,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/Filter.hpp:5,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/BatchFilter.hpp:5,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:1:
/usr/local/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp: In instantiation of 'boost::numeric::odeint::controlled_step_result boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::try_step_v1(System, StateInOut&, boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type&, boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type&) [with System = System<arma::Col<double>::fixed<2>, arma::Mat<double> >; StateInOut = arma::Col<double>; ErrorStepper = boost::numeric::odeint::runge_kutta_cash_karp54<arma::Col<double> >; ErrorChecker = boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations>; StepAdjuster = boost::numeric::odeint::default_step_adjuster<double, double>; Resizer = boost::numeric::odeint::initially_resizer; boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type = double]':
/usr/local/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp:283:27: required from 'boost::numeric::odeint::controlled_step_result boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::try_step(System, StateInOut&, boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type&, boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type&) [with System = System<arma::Col<double>::fixed<2>, arma::Mat<double> >; StateInOut = arma::Col<double>; ErrorStepper = boost::numeric::odeint::runge_kutta_cash_karp54<arma::Col<double> >; ErrorChecker = boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations>; StepAdjuster = boost::numeric::odeint::default_step_adjuster<double, double>; Resizer = boost::numeric::odeint::initially_resizer; boost::numeric::odeint::controlled_runge_kutta<ErrorStepper, ErrorChecker, StepAdjuster, Resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type = double]'
/usr/local/include/boost/numeric/odeint/integrate/detail/integrate_times.hpp:101:81: required from 'size_t boost::numeric::odeint::detail::integrate_times(Stepper, System, State&, TimeIterator, TimeIterator, Time, Observer, boost::numeric::odeint::controlled_stepper_tag) [with Stepper = boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_cash_karp54<arma::Col<double> >, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_tag>; System = System<arma::Col<double>::fixed<2>, arma::Mat<double> >; State = arma::Col<double>; TimeIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double> >; Time = double; Observer = Observer::push_back_state<arma::Col<double> >; size_t = long unsigned int]'
/usr/local/include/boost/numeric/odeint/integrate/integrate_times.hpp:129:35: required from 'size_t boost::numeric::odeint::integrate_times(Stepper, System, State&, TimeIterator, TimeIterator, Time, Observer) [with Stepper = boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_cash_karp54<arma::Col<double> >, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_tag>; System = System<arma::Col<double>::fixed<2>, arma::Mat<double> >; State = arma::Col<double>; TimeIterator = __gnu_cxx::__normal_iterator<const double*, std::vector<double> >; Time = double; Observer = Observer::push_back_state<arma::Col<double> >; size_t = long unsigned int]'
/Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:231:42: required from void BatchFilter<state_type>::compute_reference_state_history(const std::vector<double>&, std::vector<_RealType>&, std::vector<arma::Mat<double> >&) [with state_type = arma::Col<double>::fixed<2>]'
/Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:327:16: required from here
/usr/local/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp:481:12: error: no match for call to '(boost::numeric::odeint::unwrap_reference<System<arma::Col<double>::fixed<2>, arma::Mat<double> > >::type {aka System<arma::Col<double>::fixed<2>, arma::Mat<double> >}) (arma::Col<double>&, arma::Col<double>&, boost::numeric::odeint::controlled_runge_kutta<boost::numeric::odeint::runge_kutta_cash_karp54<arma::Col<double> >, boost::numeric::odeint::default_error_checker<double, boost::numeric::odeint::range_algebra, boost::numeric::odeint::default_operations>, boost::numeric::odeint::default_step_adjuster<double, double>, boost::numeric::odeint::initially_resizer, boost::numeric::odeint::explicit_error_stepper_tag>::time_type&)'
sys( x , m_dxdt.m_v ,t );
~~~^~~~~~~~~~~~~~~~~~~~~
In file included from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/Filter.hpp:6:0,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/BatchFilter.hpp:5,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:1:
/Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/System.hpp:32:7: note: candidate: void System<state_type, jacobian_type>::operator()(const state_type&, state_type&, double) [with state_type = arma::Col<double>::fixed<2>; jacobian_type = arma::Mat<double>] <near match>
void operator() (const state_type & x , state_type & dxdt , const double t ){
^~~~~~~~
/Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/System.hpp:32:7: note: conversion of argument 2 would be ill-formed:
In file included from /usr/local/include/boost/numeric/odeint.hpp:35:0,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/Filter.hpp:5,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/BatchFilter.hpp:5,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:1:
/usr/local/include/boost/numeric/odeint/stepper/controlled_runge_kutta.hpp:481:25: error: cannot bind non-const lvalue reference of type 'arma::Col<double>::fixed<2>&' to an rvalue of type 'arma::Col<double>::fixed<2>'
sys( x , m_dxdt.m_v ,t );
~~~~~~~^~~
In file included from /usr/local/include/armadillo:568:0,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/include/BatchFilter.hpp:4,
from /Users/bbercovici/GDrive/CUBoulder/Research/code/ASPEN_gui_less/lib/source/BatchFilter.cpp:1:
/usr/local/include/armadillo_bits/Col_meat.hpp:1145:1: note: after user-defined conversion: arma::Col<eT>::fixed<fixed_n_elem>::fixed(const arma::Base<eT, T1>&) [with T1 = arma::Mat<double>; long long unsigned int fixed_n_elem = 2; eT = double]
Col<eT>::fixed<fixed_n_elem>::fixed(const Base<eT,T1>& A)
^~~~~~~
make[2]: *** [CMakeFiles/ASPEN.dir/source/BatchFilter.cpp.o] Error 1
make[1]: *** [CMakeFiles/ASPEN.dir/all] Error 2
make: *** [all] Error 2
For reference, System.hpp is down here:
# System.hpp
template <typename state_type,typename jacobian_type = arma::mat> class System {
public:
System(const Args & args,
unsigned int N_est,
state_type (*estimate_dynamics_fun)(double, const state_type & , const Args & args) ,
jacobian_type (*jacobian_estimate_dynamics_fun)(double, const state_type & , const Args & args),
unsigned int N_true = 0,
state_type (*true_dynamics_fun)(double, const state_type & , const Args & args) = nullptr)
: N_est(N_est), N_true(N_true){
this -> estimate_dynamics_fun = estimate_dynamics_fun;
this -> true_dynamics_fun = estimate_dynamics_fun;
this -> jacobian_estimate_dynamics_fun = jacobian_estimate_dynamics_fun;
this -> args = args;
}
System(const Args & args,
unsigned int N_true,
state_type (*true_dynamics_fun)(double, const state_type & , const Args & args))
: N_est(0), N_true(N_true){
this -> true_dynamics_fun = true_dynamics_fun;
this -> args = args;
}
void operator() (const state_type & x , state_type & dxdt , const double t ){
if (this -> true_dynamics_fun != nullptr){
dxdt.rows(this -> N_est + this -> N_est * this -> N_est,
this -> N_est + this -> N_est * this -> N_est + this -> N_true - 1) = this -> true_dynamics_fun(t,
x.rows(this -> N_est + this -> N_est * this -> N_est,
this -> N_est + this -> N_est * this -> N_est + this -> N_true - 1),args);
}
if (this -> estimate_dynamics_fun != nullptr){
arma::mat Phi = arma::reshape(x.rows(this -> N_est,
this -> N_est + this -> N_est * this -> N_est - 1), this -> N_est, this -> N_est );
arma::mat A = this -> jacobian_estimate_dynamics_fun(t,x.rows(0,this -> N_est - 1),this -> args);
dxdt.rows(0,this -> N_est - 1) = this -> estimate_dynamics_fun(t,x.rows(0,this -> N_est - 1),this -> args);
dxdt.rows(this -> N_est,
this -> N_est + this -> N_est * this -> N_est - 1) = arma::vectorise(A * Phi);
}
}
protected:
const unsigned int N_est;
const unsigned int N_true;
state_type (*estimate_dynamics_fun)(double, const state_type & , const Args & args) = nullptr;
state_type (*true_dynamics_fun)(double, const state_type & , const Args & args) = nullptr;
jacobian_type (*jacobian_estimate_dynamics_fun)(double, const state_type & , const Args & args) = nullptr;
Args args;
};
I found a way around the resizing issue here:
https://reformatcode.com/code/c/armadillo-conflicts-with-boost-odeint-odeint-resizes-the-state-vector-to-zero-during-integration
The solution consists in extending boost:numeric::odeint with the following adapters that handle automatic resizing of the arma::vec for safe use with odeint
#include <armadillo>
namespace boost { namespace numeric { namespace odeint {
template <>
struct is_resizeable<arma::vec>
{
typedef boost::true_type type;
const static bool value = type::value;
};
template <>
struct same_size_impl<arma::vec, arma::vec>
{
static bool same_size(const arma::vec & x, const arma::vec& y)
{
return x.n_rows == y.n_rows;
}
};
template<>
struct resize_impl<arma::vec, arma::vec>
{
static void resize(arma::vec &v1, const arma::vec & v2)
{
v1.resize(v2.n_rows,1);
}
};
} } } // namespace boost::numeric::odeint

Call to non-constexpr function 'std::map...'

I'm attempting to create a pseudo-media center thing on an Arduino and a breadboard, not all that complicated but this is my first project with C++ that amounted to more than 'Hello world!' or a calculator.
Digressing to my point though, I started rewriting almost the entire original program, and in an effort to clean things up, started using a map to hold the keys and values (IR codes), and to further organize it, put the assignments inside of a function (IR_generateMap()), but I'm getting an error when I compile it.
C:\Users\trevo\Documents\Arduino\improvedIRRemote\improvedIRRemote.ino: In function 'void IRLoop(bool)':
improvedIRRemote:78: error: call to non-constexpr function 'std::map<Key, T, Compare, Allocator>::reference std::map<Key, T, Compare, Allocator>::operator[](const key_type&) [with Key = std::basic_string<char>; T = int; Compare = std::less<std::basic_string<char> >; Allocator = std::allocator<int>; std::map<Key, T, Compare, Allocator>::reference = int&; std::map<Key, T, Compare, Allocator>::key_type = std::basic_string<char>]'
case IRCodes["Power Button"]:
^
improvedIRRemote:78: error: call to non-constexpr function 'std::map<Key, T, Compare, Allocator>::reference std::map<Key, T, Compare, Allocator>::operator[](const key_type&) [with Key = std::basic_string<char>; T = int; Compare = std::less<std::basic_string<char> >; Allocator = std::allocator<int>; std::map<Key, T, Compare, Allocator>::reference = int&; std::map<Key, T, Compare, Allocator>::key_type = std::basic_string<char>]'
exit status 1
call to non-constexpr function 'std::map<Key, T, Compare, Allocator>::reference std::map<Key, T, Compare, Allocator>::operator[](const key_type&) [with Key = std::basic_string<char>; T = int; Compare = std::less<std::basic_string<char> >; Allocator = std::allocator<int>; std::map<Key, T, Compare, Allocator>::reference = int&; std::map<Key, T, Compare, Allocator>::key_type = std::basic_string<char>]'
I've looked up and attempted to understand errors with non-constexpr calls, but to be perfectly honest, I don't understand how what I'm trying to do with the map relates to the problems being described in the posts that deal with said error.
#include <IRremote.h>
#include <StandardCplusplus.h>
#include <map>
//Variables responsible for recieving and decoding IR signals/codes.
IRrecv receiver(10); //IR receiver initialization.
decode_results results; //Object that is responsible for decoding the IR signal.
//Variables responsible for tracking channel changing.
int channel = 1; //The active channel.
int desiredChannel = ""; //The string that is used to concatenate the numbers pressed on the remote keypad together.
int channelEnterDelay = 4000; //The delay between the last time a number was pressed on the remote keypad and when the desiredChannel is cleared.
unsigned long channelEnterStartTime = 0; //The time in which that last number was pressed on the remote keypad.
String intConverter; //The string responsible for casting an integer to a string.
//Variables responsible for tracking volume changing.
int volume = 50; //The current volume.
int lastVolume = 50; //Holds the value of the volume previous to the volume being muted.
bool isMuted = false; //Whether or not the sound has been muted.
//Map responsible for the setting and getting of IR codes and their respective keys.
const std::map<std::string, int> IRCodes;
//Miscellanious Stuff - mostly waiting for depreciation.
int IRFlasherPin = 8;
int mode = 0;
int IRFlasherBlinkRate = 10;
//Debug mode shows channel switching info when entering from the remote keypad, turn it off to declutter the serial feed if it is not being used.
bool DEBUG_MODE = false;
void setup() {
receiver.enableIRIn(); //Tells the receiver to start listening for IR communication.
pinMode(IRFlasherPin, OUTPUT); //Configuring the pin that flashes upon recieving the 'excess communication' IR code.
Serial.begin(9600); //Begins serial communication at 9600 baud.
IR_generateMap(); //Sets all of the values for the map of IR keys and values.
//Ready message.
Serial.println("The Arduino is ON and ready for communication.");
if (DEBUG_MODE) { Serial.println("Also please note that debug mode has been preemptively enabled. The serial monitor can be expected to be much more cluttered than normal. To disable this, press the 'U/SD' button on the remote."); }
Serial.println();
}
void loop() {
//Pre-loop checks.
//empty
IRLoop(true);
}
void IRLoop(bool toldToContinueLooking) {
if (receiver.decode(&results)) {
switch(results.value) {
case IRCodes["Power Button"]:
Serial.println("Power Toggle");
break;
default:
if (DEBUG_MODE) {
Serial.print("Extraneous code: ");
Serial.print(results.value);
}
break;
}
}
if (toldToContinueLooking) { receiver.resume(); }
}
void IR_generateMap() {
//General Keys
IRCodes["Power Button"] = 16753245;
IRCodes["Mode Button"] = 16736925;
IRCodes["Back Button"] = 16750695;
IRCodes["EQ Button"] = 16769055;
IRCodes["USD Button"] = 16756815;
//Media Keys
IRCodes["PlayPause Button"] = 16720605;
IRCodes["Rewind Button"] = 16712445;
IRCodes["Fast Forward Button"] = 16761405;
//Volume Keys
IRCodes["Mute Button"] = 16769565;
IRCodes["Minus Button"] = 16754775;
IRCodes["Plus Button"] = 16748655;
//Numpad Keys
IRCodes["Numpad 0"] = 16738455;
IRCodes["Numpad 1"] = 16724175;
IRCodes["Numpad 2"] = 16718055;
IRCodes["Numpad 3"] = 16743045;
IRCodes["Numpad 4"] = 16716015;
IRCodes["Numpad 5"] = 16726215;
IRCodes["Numpad 6"] = 16734885;
IRCodes["Numpad 7"] = 16728765;
IRCodes["Numpad 8"] = 16730805;
IRCodes["Numpad 9"] = 16732845;
//Non-Key Codes
IRCodes["Excess Communication"] = 4294967295;
}
Can someone explain what I'm doing wrong to me in terms that someone of my early C++ knowledge-base would understand?
The expression in the 'case' must be compile time constant. Just use an if/else construction instead and it should work.
Thomas
I'd go in opposite way by using map to decode IR Code to handler function or by using enum. Something like this:
#include <StandardCplusplus.h>
#include <map>
#include <functional>
void power_key();
void num_key0();
void num_key1();
void num_key2();
void num_key3();
void num_key4();
void num_key5();
void num_key6();
void num_key7();
void num_key8();
void num_key9();
void num_key(int8_t);
typedef void(*handler_t)();
std::map<uint32_t, handler_t> keys;
void setup() {
keys[16753245UL] = power_key;
keys[16738455UL] = num_key0;
keys[16724175UL] = num_key1;
keys[16718055UL] = num_key2;
keys[16743045UL] = num_key3;
keys[16716015UL] = num_key4;
keys[16726215UL] = num_key5;
keys[16734885UL] = num_key6;
keys[16728765UL] = num_key7;
keys[16730805UL] = num_key8;
keys[16732845UL] = num_key9;
Serial.begin(57600);
}
void loop() {
uint32_t recvd_code = 16753245UL; // literal value, for testing purpose without IR receiver and remote
auto iter = keys.find(recvd_code); // find received code and execute it
if (iter != keys.end()) {
iter->second();
} else {
Serial.print(F("IR Code "));
Serial.print(recvd_code);
Serial.println(F("not found"));
}
delay(1000);
}
void power_key() {
Serial.println(F("Power key pressed"));
}
void num_key0() { num_key(0); }
void num_key1() { num_key(1); }
void num_key2() { num_key(2); }
void num_key3() { num_key(3); }
void num_key4() { num_key(4); }
void num_key5() { num_key(5); }
void num_key6() { num_key(6); }
void num_key7() { num_key(7); }
void num_key8() { num_key(8); }
void num_key9() { num_key(9); }
void num_key(int8_t num) {
Serial.print(F("Numeric key pressed: "));
Serial.println(num);
}
Initializer list somehow didin't work, so initialization must be done in setup and map can't be const.