Home > Coding, Mainframe > Mixing it up with C and assembler with METALC..

Mixing it up with C and assembler with METALC..

A few months ago I posted this sample C code to reverse a character string:

// Reverse a string

#include <iostream>
#include <string.h>

using namespace std;

char * reverse( char * p) {
    char * e;
    char * s;                // Copy ptr because I am going to mess with it
    int l = strlen(p);
    s=p;                     // first char ptr
    e = p+l-1;               // last char ptr

    char * m;                // mid point of the string
    m=s+l/2;                 // set it (int arith drops remainder if odd length

    for (;s<m;s++) {         // just need to traverse half the string
        s[0]=s[0]^e[0];      // swap curr leading and current last byte
        e[0]=e[0]^s[0];      // using xor
        s[0]=s[0]^e[0];
        e--;                 // back up 1 from end
        }
    return p;                // return same string back to caller

    }

int main()
{
   char c[21]="12345";             // String to reverse
   cout << reverse(c)<<'\n';       // reverse and print result
   cout << c;                      // orig string also reversed
   reverse(c);                     // reverse in place
   cout <<'\n'<<c;                 // show it is reversed

   return 0;
}

Pretty standard loop driven stuff and ‘adequate’ shall we say.

One of my ‘to do’ items this year is to go through the POP (principles of operation) manual and update my knowledge of a lot of the new instructions in there as it’s been forever since I last did that. Anyway, one of the instructions I came across was MVCIN or Move Inverse. This is a bit like MVC (Move Characters) except that it reverses the string as it moves it. Cool, except that we are in C and that is an assembler instruction and it’s a lot of extra work to write a sub routine you could call from a C program to do that.

But wait, there’s more (otherwise this would be a pointless post!)…

On the z/OS mainframe, the run time environment for C (and other programming languages like Cobol and PL/I) is normally provided by Language Environment (LE). BUT! If you use the C compiler option METALC, you can compile C code that has NO LE dependency. It is completely stand alone. Not only that but you can embed small snippets of ASSEMBLER code directly into your C source code and it compiles just like part of the regular program.

What this means is that I can replace that ugly for loop in the code above with a SINGLE instruction that will do the same thing, and do it far more efficiently than that loop will.

Now bear in mind I have not tried this code yet so it may need some tweaking but this is what I have so far:

// Reverse a string

#include <iostream>
#include <string.h>

using namespace std;

char * reverse( char * in) {

    int l = strlen(in);
    char * work;
    work = new char[l];         // get a temp work area 

    __asm (     
      "    MVCIN %0(%1),0(%2)      \n"  
      :"=m"(work) : r(l), "m"(in[l-1])                         
    );   

    memcpy(in,work,l);       // copy reversed string in work to orig input area
    delete [] work;          // release work area

    return in;               // return same string back to caller

}                                        

    }

int main()
{
   char c[21]="12345";             // String to reverse
   cout << reverse(c)<<'\n';       // reverse and print result
   cout << c;                      // orig string also reversed
   reverse(c);                     // reverse in place
   cout <<'\n'<<c;                 // show it is reversed

   return 0;
}

I have to allocate a work area to receive the reversed string since you cannot overlay the source with the output so the question becomes, is the cost (in CPU time) of allocating that work area and releasing it greater than the saving incurred by switching to a hardware instruction to do the reverse. You could however get around that to some extent by requiring the caller to provide the work area.

The only other downside is that this instruction is limited to 256 character strings so for anything longer you would have to implement some sort of loop but even so, the fact that you could reverse the string in 256 byte chunks must have some performance improvement implications.

In case you are wondering, the %0, %1 and %2 represent the positional parameters below the instruction. The fields after the first colon are output fields and the fields after the second colon are input parameters.

The parameter (“=m”(work) after the first colon tells the compiler this is an output field, it will be modified by the code and that it is a memory reference.

The two parameters (r(1) and “m”(in[l-1]) are input parameters. r(1) means this should be a register and the second memory reference (the source string) is a memory reference. It has to be the address of the LAST character of the source string, not the first, hence the [l-1] after the field name.

As soon as I get a chance I’ll try compiling this and seeing it it actually works. Look for another update soon!

Advertisements
Categories: Coding, Mainframe Tags: , ,
  1. March 5, 2014 at 3:14 am

    You seem to be using C++ in a Metal program? Is this supported?

  2. March 5, 2014 at 3:56 am

    If I am, it’s not intentional as, so far as I am aware, c++ is not supported in metal c.

  3. March 12, 2014 at 8:25 pm

    Does the “cout << " syntax work outside of C++. That's probably what confused me.

  4. March 12, 2014 at 10:04 pm

    Probably not and I’m probably mixing up C and C++ here (which is one reason I am not big fan of either, too easy to get horribly confused, at least for beginners. IE me!). If you look at this later post https://davideellis.wordpress.com/2013/07/29/mixing-it-up-with-c-and-assembler-with-metalc-part-2/ you’ll see I replaced the cout with printf which is still a problem because metal C does not have a native printf function.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: