llvm pass to flatten (some) nested loops - llvm

I want to automatically rewrite simple nested loops as non nested ones.
For example, I have the following code:
if (y >= 0)
{
while (x>y)
{
x -= y+1;
for (z=y; z>0; z--) /* nothing */;
}
}
And I would like some llvm magic to happen so that it becomes:
if (y >= 0)
{
bool outer = true;
while (x>y)
{
if (outer) { z = y; }
if (z > 0) { z--; outer = false; }
else { x-= y+1; outer = true; }
}
}
Am I being over optimistic thinking such a pass exists?
I tried writing opt --help > /tmp/passes.txt && grep "loop" /tmp/passes.txt
but there are so many loop passes I don't know where to start.

This optimization is called loop fusion. I haven't tried your code but Polly should be able to fuse such loops. Polly is the polyhedral compiler framework that ships with LLVM but it should build with LLVM by default. If it does not then you'd need to pass -DLLVM_POLLY_BUILD:BOOL=ON to cmake to build polly with llvm.
Here's the documentation on how to invoke polly optimizations with clang/llvm.
https://polly.llvm.org/docs/UsingPollyWithClang.html#optimizing-with-polly

Related

Simulating Leach has encounter a problem. Finished with error in omnet++

When running the simulation in omnet++ 5.7 the execution stops suddenly and closes.
This is the code that is being run in omnet
auto simulation = getSimulation();
for (i = 1; i <= simulation->getLastComponentId(); i++) {
int x, y, id;
//scan the simulation module vector
mod = (cModule*)simulation->getModule(i);
if (strcmp(mod->getName(), "node") == 0) {
id = ((Node*)mod)->myId;
x = ((Node*)mod)->xpos;
y = ((Node*)mod)->ypos;
nodePtr[id] = ((Node*)mod);
if (id != this->myId) {
cGate* g;
char gName1[32], gName2[32];
// make new gate here
if (this->hasGate(gName1)) {
this->gate(gName1)->disconnect();
this->deleteGate(gName1);
}
this->addGate(gName1, cGate::OUTPUT, false);
// make new gate at other side
if (mod->hasGate(gName2)) {
mod->gate(gName2)->disconnect();
mod->deleteGate(gName2);
}
mod->addGate(gName2, omnetpp::cGate::INPUT, false);
//CHANNEL
cIdealChannel* ch = NULL;
this->gate(gName1)->connectTo(mod->gate(gName2), ch);
g = this->gate(gName1);
g->setDisplayString(g->getDisplayString());
}
}
}
I assume that the last line g->setDisplayString(g->getDisplayString()); is probably where the code breaks. The code repeats in the for loop with i<= simulation->getLastComponentId(). I'm new to Omnet++. Any suggestion to fix this would be helpful.
Thanks.
Several things in your code may be source of crashing:
getModule(i) may return nullptr, see OMNeT++ Simulation API, so you should check in the code whether result is not nullptr.
gName1 and gName2 are not set!
Other issues:
instead of (Node*)mod use dynamic_cast<Node*)>(mod) and check whether results is not nullptr.
instead of strcmp(mod->getName(), "node") == 0 I advice using mod->isName("node") - see OMNeT++ Simulation API
if you want to obtain a module whose name is "node", you do not need to manually check the name of every module - there is a useful method getModuleByPath() see OMNeT++ Simulation Manual

If else ladder optimisation

if (value >= 2) {
return 1
} else if (value >= 1) {
return 0.9;
} else if (value >= 0.8) {
return 0.7
} else if (value >= 0.5) {
return 0.5;
} else {
return 0;
}
How to solve this if-else ladder. If i use switch cyclometric complexity increases and also also values feels like true.
In some cases the solution is breakaway code. Not everyone likes it - I do like it.
It just means you handle situations "from the top" and end situations with a return
pseudocode in any language...
(Everything should be in a function anyway...)
HandleTemperature(float t)
{
if (t > 90)
{
RunEmergencyCooling();
return;
}
if (round.t == 63)
{
DealWithgMagicValue();
return;
}
if (round.t > 40)
{
Debug.("normal temps! no worries!);
return;
}
// if you get to here, temp is very lopw
RunEmergencyHeating();
}
(In many languages there's a "finally" or "always do" concept, which can work well w/. breakaway dcode.)
Your example ...
Step 1, put in in a function as it should be anyway, Step 2 use "breakaway chunks".
float HandleValue(float v)
{
if (2.0 <= v) {
return 1
}
if (0.7 < v && v < 2.0) {
return 0.9;
}
if (0.13 <= v && v <= 0.7) {
return 17.6;
}
log didn't find a bracket in HandleValue
return default value
}
Every bracket is totally explicit. You can easily build testing code from there, too.
Those annoying long blocks before errors ...
Breakaway is particularly clean-looking in error cases...
Something()
{
if comms.text != 17.2
{
.. 100s of lines of code here ..
.. they are all indented ..
}
else
{
an error!
}
}
Some (but not all) believe this is better:
Something()
{
if comms.text == 17.2
{
an error!
return; .. note the "return" in breakaway code
}
.. 100s of lines of code here ..
.. no need for indentation ..
}
"Breakaway code" may work for you in some cases; in any event you can be aware of the approach.

'else if' logical statements in gnuplot

The new gnuplot (5.x) has new syntax for logic, but I cannot get the 'else if' statement to work. For example:
if(flag==1){
plot sin(x)
}
else{
plot cos(x)
}
does work, but:
if(flag==1){
plot sin(x)
}
else if(flag==2){
plot cos(x)
}
else if(flag==3){
plot tan(x)
}
does not. I have tried many combinations of {} and placement of 'if' and 'else' to no avail. Does anyone know how to correctly implement 'else if' in gnuplot 5.x?
The gnuplot guide (http://www.bersch.net/gnuplot-doc/if.html) has no examples of the new logic syntax using 'else if' but does have examples using the old syntax, but I would rather avoid the old.
Based on a brief inspection of the source code of command.c in the latest version of Gnuplot, I would say that this feature is not supported. To be more specific, the relevant part can be found on line 1163 (see below). The parser first makes sure that the if is followed by a condition enclosed in parentheses. If the following token is a {, it activates the new syntax, isolates the entire if block enclosed in a pair of matching {} and optionally looks for an else which is however permitted to be followed also only with a {}-enclosed clause. Because of this, a simple script such as:
if(flag == 1){
print 1;
}else if(flag == 2){
print 2;
}
indeed produces the error message expected {else-clause}. One workaround would be to nest the if statements as:
if(flag == 1){
}else{
if(flag == 2){
}else{
if(flag == 3){
}
}
}
which is admittedly slightly more verbose...
void
if_command()
{
double exprval;
int end_token;
if (!equals(++c_token, "(")) /* no expression */
int_error(c_token, "expecting (expression)");
exprval = real_expression();
/*
* EAM May 2011
* New if {...} else {...} syntax can span multiple lines.
* Isolate the active clause and execute it recursively.
*/
if (equals(c_token,"{")) {
/* Identify start and end position of the clause substring */
char *clause = NULL;
int if_start, if_end, else_start=0, else_end=0;
int clause_start, clause_end;
c_token = find_clause(&if_start, &if_end);
if (equals(c_token,"else")) {
if (!equals(++c_token,"{"))
int_error(c_token,"expected {else-clause}");
c_token = find_clause(&else_start, &else_end);
}
end_token = c_token;
if (exprval != 0) {
clause_start = if_start;
clause_end = if_end;
if_condition = TRUE;
} else {
clause_start = else_start;
clause_end = else_end;
if_condition = FALSE;
}
if_open_for_else = (else_start) ? FALSE : TRUE;
if (if_condition || else_start != 0) {
clause = new_clause(clause_start, clause_end);
begin_clause();
do_string_and_free(clause);
end_clause();
}

gcc - leverage compiler to aid in code instrumentation

BACKGROUND
I'm developing on OMAP 5 (ARM) and using a QNX gcc-based C++ compiler.
I know about the ability of gcc to insert a custom entry/exit callback for each function but I'd like to have more info than that.
PROBLEM
For starters, I want to instrument every control-flow statement
void func()
{
if(bob == 9)
{
bob = 55;
}
else
{
bob = 101;
}
}
Would become
void func()
{
if(bob == 5)
{
MACRO(0x1433) //0x1433 = ID for this particular if-statement
bob = 55;
}
else
{
MACRO(0x3243) //0x3243 = ID for this particular else-statement
bob = 99;
}
}
I know I could do the parsing myself but for more complex statements, it would get messy.
QUESTION
The gcc compiler already does the parsing of the code in the process of compilation.
Is there any way I can leverage some intermediate output so I can more easily identify control-flow statements?
Obviously there's the preprocessed output but that only resolves macros

Implementing Prolog in C or C++ [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 5 years ago.
Improve this question
I was wondering how would Prolog implementation in C or C++ look like. I am mainly interested in building it as a C or C++ library, though the interpreter app would also do. I am interested in reading about its internals, namely query execution i.e. finding the solutions and the associated datatypes involved. I would be glad if you recommended me any readings on topic or for any direct suggestions/advices. Readings might be for other OOP languages or for general OOP as well. Most exhausting material will solve the question.
If you want to see how a Prolog system implemented in C can be used from C/C++ as a library, look at SWI-Prolog. It offers a completely bi-directional interface including non-determinism for Unix/Mac/Window — and much, much more. Think of constraints.
On the other hand, you are asking also about its actual implementation. There are two ways to approach this. You can either start from the very bottom and work yourself up level-to-level. Or you can start with Prolog, and start with meta-interpreters that implement Prolog in Prolog. From this you can slowly dig into the gore.
The traditional approach was to start with the very bottom issues first, studying the various abstract machines. The most commonly cited one is the WAM (Warren Abstract Machine) and then there are
Alternatives to the WAM
you should not miss. Be prepared that it will take a long way from this to a working ISO implementation. There are many issues that are only cursorily dealt with in the literature like garbage collection and constraints. Yet, they are needed for a robust implementation.
The other approach is to first learn Prolog, and then study meta-interpreters in detail. In this manner you might learn to see Prolog from an entirely different perspective. And you might also gain insights you would not get otherwise. You can start with the classical three clause meta-interpreter which reuses much of Prolog's functionality. Depending on your interest you then can start to reify parts of it. The nice thing is that you pay (in terms of code size) almost only for the parts you want to dig in and reuse the other parts of the language.
At least in the past this approach led to various new implementation techniques, e.g. constraints, Erlang, binary Prolog all existed first as a "simple" meta-interpreter. Only then, after understanding the language issues, actual implementations were done.
There is also another point in favour of starting with Prolog first: What happens, if you stop your effort right in the middle of it? With the bottom-up approach you end up with a collection of defunct code. For the second approach, you have learned Prolog.
Some time ago I wrote a Prolog interpreter in C++ (really, my first C++ program), and followed a different approach instead of the (now nearly ubiquitous) WAM. Our teacher at course of languages and compilers construction talked about an ABC algorithm, and I implemented that (I goggled 'Prolog implementation ABC algorithm', here a PDF that I found, but I don't know - yet) : here the core solver
//--------------------------
// evaluation core of query
// use algorithm ABC
//
int IntlogExec::query(const Clause *q)
{
unsigned nc = 0;
ProofStack::Env *pcn, *pfn;
stkpos cn, fn;
#define PCN (pcn = ps->get(cn))
#define PFN (pfn = ps->get(fn))
UnifyStack us(vs, ts);
if (!q)
goto C;
fn = ps->push(STKNULL);
PFN->vspos = vs->reserve(q->get_nvars());
pfn->trail = ts->curr_dim();
pfn->dbpos = 0;
pfn->call = 0;
// current query is empty?
A: if (!q->get_body()) {
// search untried calls
A1: //fn = ps->curr_dim() - 1;
fn = cn;
ProofStack::Env *e = ps->get(fn);
while (e->father != STKNULL) {
if (tr && e->call && tr->exit(fn, e->call))
return -1;
if (e->call && !e->call->is_last())
break;
e = ps->get(fn = e->father);
}
if (e->father == STKNULL)
return 1;
// set call to next untried brother
cn = ps->push(PFN->father);
PCN->call = pfn->call->next();
pcn->vspos = pfn->vspos;
fn = pfn->father;
} else {
cn = ps->push(fn);
PCN->call = q->get_body();
}
A2: PFN;
pcn->dbpos = 0;
cc = pcn->call;
if (nc++ == ncycle)
{
nc = 0;
sighandler();
}
// trace the call
if (tr && tr->call(cn, cc))
return -1;
switch (cc->get_type()) {
case CallData::BUILTIN: {
BuiltIn *btp = cc->get_builtin();
pcn->trail = ts->curr_dim();
pcn->vspos = pfn->vspos;
// if evaluate OK
if (btp->eval(cc->args(), this, 0)) {
// if (tr && tr->exit(cn, cc))
// return -1;
// if (btp->retry || pcn->call->last())
// goto A1;
// pcn->call = pcn->call->next();
// goto A2;
goto A1;
}
PCN;
if (tr && tr->fail(cn, pcn->call))
return -1;
unbind(pcn->trail);
}
goto C1;
case CallData::CUT: {
stkpos gf = PFN->father;
if ( gf != STKNULL &&
pfn->call->is_last() &&
pfn->call == pcn->call->next()) {
// tail recursion optimization
ProofStack::Env *pgf = ps->get(gf);
pgf->vspos = pfn->vspos;
ASSERT(!pcn->call->is_last());
slist_iter s(tmpt);
ElemTmp *t;
while ((t = (ElemTmp*)s.next()) != 0 && t->spos > fn)
t->spos = fn;
CallData *cproc = pcn->call;
cn = ps->pop(cn - fn) - 1;
PCN->call = cproc->next();
fn = pcn->father;
goto A2;
}
pcn->trail = ts->curr_dim();
pcn->vspos = pfn->vspos;
}
goto A1;
case CallData::DISJUNCT: // replace with catenated try
pcn->vspos = pfn->vspos;
pcn->trail = ts->curr_dim();
cn = ps->push(fn);
PCN->call = cc->next(); // left side
goto A2;
case CallData::DBPRED:
// initialize DB search
pcn->dbpos = db->StartProc(cc->get_dbe());
// DB matching & unification
B: if (pcn->dbpos && (q = pcn->dbpos->get()) != 0) {
unsigned nvars = q->get_nvars();
pcn->vspos = vs->reserve(nvars);
pcn->trail = ts->curr_dim();
/*
if (!unify( pfn->vspos, cc->args(),
pcn->vspos, q->h_args(), q->h_arity()))
*/
if (q->h_arity() > 0) {
TermArgs pa1 = cc->args(),
pa2 = q->h_args();
us.clear();
for (int i = q->h_arity() - 1; i > 0; i--) {
UnifyStack::termPair *tp = us.push();
tp->t1 = pa1.getarg(i);
tp->i1 = pfn->vspos;
tp->t2 = pa2.getarg(i);
tp->i2 = pcn->vspos;
}
us.check_overflow();
if (!us.work( pa1.getarg(0), pfn->vspos,
pa2.getarg(0), pcn->vspos))
{
// undo changes
unbind(pcn->trail);
vs->pop(nvars);
// try next match
pcn->dbpos = pcn->dbpos->succ(db);
goto B;
}
}
fn = cn;
goto A;
}
break;
default:
ASSERT(0);
}
if (tr && PCN->call && tr->fail(cn, cc))
return -1;
// backtracking
C1: query_fail(ps->curr_dim() - cn);
// resume top query
C: cn = ps->curr_dim() - 1;
unbind(PCN->trail);
C2: if ((fn = pcn->father) == STKNULL)
return 0;
if ((cc = pcn->call) == 0)
goto C1;
switch (cc->get_type()) {
case CallData::CUT: { // change satisfaction path up to father
stkpos fvp = PFN->vspos;
query_fail(cn - fn + 1);
if ((cn = ps->curr_dim() - 1) != STKNULL) {
unbind(PCN->trail);
vs->pop(vs->curr_dim() - fvp);
goto C2;
}
return 0;
}
case CallData::BUILTIN: { // check builtins retry
BuiltIn *btp = cc->get_builtin();
if (btp->args & BuiltIn::retry) {
if (tr && tr->redo(cn, cc))
return -1;
// could be resatisfied
pcn->trail = ts->curr_dim();
pcn->vspos = PFN->vspos;
// if evaluate OK
if (btp->eval(cc->args(), this, 1))
goto A1;
}
// failed
goto C1;
}
case CallData::DISJUNCT: // evaluate right side
if (tr && tr->redo(cn, cc))
return -1;
pcn->call = cc->get_orelse();
goto A2;
case CallData::DBPRED: // a DB query node to retry
if (tr) { // display REDOs (TBD)
if (pcn->dbpos && pcn->dbpos->succ(db) && tr->redo(cn, cc))
return -1;
}
vs->pop(vs->curr_dim() - pcn->vspos);
pcn->dbpos = pcn->dbpos->succ(db);
PFN;
goto B;
default:
ASSERT(0);
}
return -1;
}
now I'm not very proud of that code: instead of ABC I ended up (by means of rather painful debugging) to an A-A1-A2 B C1-C-C2.
edit: I placed the complete interpreter sources in github.
You can start by checking the answers to this question.
You can also check the source of various open-source prolog implementations (gnu prolog, swi-prolog, yap prolog and more) (although this might be too complicated if you just want a "naive" implementation or some prolog-like features like backtracking).
Finally you should check the prolog ISO.
Having said that, if you are interested in combining C and prolog there are some interfaces you can use; I don't think that implementing an (efficient) prolog is a trivial task, especially if we consider that there are (surprisingly) many companies/organizations dedicated to it.
You might also be interested in looking at Mike Spivey's An Introduction to Logic Programming through Prolog. Both the full text of the book as well as an implementation of a simplified Prolog are available at the previous link (Note: the implementation itself is written in a minimal Pascal dialect, but for compilation this is translated into C. According to the author, this minimal Pascal dialect is more or less the "intersection of Pascal and C", anyway---whatever that means, so while not strictly satisfying the criteria, it should be quite useful for learning about Prolog).
I also noticed Alan Mycroft's Logic Programming and Functional Nets, following this link you will find a Prolog interpreter in C++, but I don't know much about it.