Welcome, Guest. Please login or register.

Author Topic: Help needed combining GCC/C++ with asm sources  (Read 5764 times)

Description:

0 Members and 1 Guest are viewing this topic.

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Help needed combining GCC/C++ with asm sources
« on: March 22, 2004, 02:20:11 AM »
Hi,

As part of an ongoing effort to move my old C++ codebase away from stormc, I'm struggling with gcc regarding calling assembler functions.

Specifically, I'm having problems specifying which registers are used for 680x0 asm function parameters. Most of the functions that I have that are asm generally dont return anything (void) and generally trash d0/d1/a0/a1.

So assume I have a function that takes an int in d0, and a char* in a0.

How do I define the function within gcc/c++?

In C mode the following was ok

void func(int i __asm("d0"), char* c __asm("a0"));

but C++ mode did not want to know. I also tried making the above a header and using extern "C", but this didnt work either.

Furthermore, the gnu assembler is scary. Can asm code assembled with phxass be linked with gcc code and are there any known issues?

Any help gladly received :-D
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #1 on: March 22, 2004, 02:52:53 PM »
Hi Matt,

Whilst I appreciate the sentiment, the project in question is the amiga OS3.x 680x0 backend implementation my C++ framework.

Hence portability of this particular code is not an issue. C++ versions of this code already exist in the "generic" part of the tree, the asm used here replaces these for speed gains *specifically* on the 680x0 - other implementations may or may not have similarly optimised code.

Now, the asm used therein is sparse but essential for performance. They are used in memory copy / set / endian swap routines. No matter how good your compiler or algorithm, some things C/C++ just cannot achieve with the same level of performance.

For instance, you can byteswap a 32-bit longword with just 3 instructions in asm thanks to instructions like "rol.w" and "swap", for which C/C++ have no equivalent operators.

I also have some pixel conversion routines etc. that are up to 5x slower in the generic C++ code than the asm, despite loop unrolling, longword only accesses and stuff, again simply due to the lack of rotate instructions.

I'm moving the code to gcc, purely so the generic branch of it is easier to port cross platform and more advanced C++ features can be used.

Any given backend, be it Amiga680x0/PPC, AROS, Linux, Win32, etc. will always use whatever it can to get the best performance, only the public front needs to be completely platform intependent.
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #2 on: March 22, 2004, 03:44:18 PM »
Quote

bloodline wrote:
Sorry, yes, I did think before I clicked "Submit" that It could be eligable for "most useless post of the year award"... but even without portability, I would still recommend using C :-)


On any CPU other than 680x0 I'd probably agree. Although I have a very nice endian conversion loop for ppc too ;-)

Quote

My thinking is that CPU's only get faster, theny  never get slower... so I wouldn't worry about optimising it (Yes I can't believe I just said that... Next you will hear that I've just got the job of cheif architect at MicroSoft).


:lol:

Quote

Can't you assemble your ASM functions serparatley and then link them in at link time?


This is basically what I'm trying to do. The problem is in specifying (for those asm functions that use it) which registers arguments are expected in.

Worst case scenario is that I will have to just use stack passing and modify the asm side. Then I should be able to use 'extern "C"' at least ;-)
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #3 on: March 22, 2004, 04:17:39 PM »
Quote

bloodline wrote:
I think you should make a shared library, that way we can all have the benefit of your functions :-)


The 680x0 asm stuff in a normal amiga os linrary you mean? a memfunc.library...?

Hmm, I don't see why not. Wouldn't have too many functions in it just now though. Just copy, set, set16, set32, set64, swap16, swap32, swap64.

The pixel conversion stuff would only be useful for folks dealing directly with CGX pixel formats...

The C++ framework thing will go opensource once its' de storm-ified and gnu-ified anyway, then the actual source will be available to anybody wanting to play with it.
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #4 on: March 22, 2004, 06:10:11 PM »
Quote

bloodline wrote:
Quote

The 680x0 asm stuff in a normal amiga os linrary you mean? a memfunc.library...?

Hmm, I don't see why not. Wouldn't have too many functions in it just now though. Just copy, set, set16, set32, set64, swap16, swap32, swap64.

 


It might be nice to have a standardized API for those functions, especially when porting from 68k code to x86 for example.


Well, the original StormC3 Mem class member functions all operate on blocks of memort and are defined like this


Code: [Select]

class Mem {
   // Mem:: should really be a namespace

   // ... snip ...

  public:
    // low level block memory operations
    static void copy(REGP0 void* dst, REGP1 void* src, REGI0 size_t len);
    static void move(REGP0 void* dst, REGP1 void* src, REGI0 size_t len);
    static void swap16(REGP0 void* dst, REGP1 void* src, REGI0 size_t num);
    static void swap32(REGP0 void* dst, REGP1 void* src, REGI0 size_t num);
    static void swap64(REGP0 void* dst, REGP1 void* src, REGI0 size_t num);
    static void zero(REGP0 void* dst, REGI0 size_t len);
    static void set(REGP0 void* dst, REGI0 int val, REGI1 size_t len);
    static void set16(REGP0 void* dst, REGI0 uint16 val, REGI1 size_t num);
    static void set32(REGP0 void* dst, REGI0 uint32 val, REGI1 size_t num);
    static void set64(REGP0 void* dst, REGP1 uint64& val, REGI0 size_t num);

    //...snip
};
[/size]

In the old definitions, REGP0 - REGP7 (register pointer parameter) are #defined as register __a0 to register __a7.

Similarly, REGI0 - REGI7 (register integer parameter) are #defined as register __d0 to register __d7

On non amiga 680x0 targets, these macros may be empty or mapped to other registers etc.

The "size_t num" parameter is always defined in terms of the element size for any function that has an implicit size (eg swap32, set16 etc.). So, byteswapping swapping a block of 128 32-bit entities would be

uint32* source;

//...

Mem::swap32(source, source, 128); // NOTE : overlap only allowed when destination address == source source address

Zeroing the same block, however would be

Mem::zero(source, 128*sizeof(uint32));

Basing a shared library on these functions wouldn't be very difficult.
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #5 on: March 24, 2004, 03:01:59 PM »
*bump*

I've been looking for the 680x0 backend info for gcc to see what conventions it uses for register usage, but I didnt find the info.

Assuming I can link my older asm code (perhaps with some modifications), do I have to preserve all registers, or (as with various other compilers) are d0/d1/d0/a1 deemed volatile?

Anybody?
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #6 on: March 25, 2004, 02:55:30 PM »
Heh, cheers :-)

The shared library thing was just a spin off. It wouldn't be written in C++, so no need to worry there.

The main issue is just getting some old asm code that I wrote in phxass to work with StormC3 C++ code to work with the same C++ code compiled under gcc. As it goes, all of these functions are static class members, so worring about the this pointer isnt an issue :-)

As for inling, I was thinking the same thing. If we assume that a0/1, d0/1 are trashable, I assume something (excusing bad inline asm syntax, not fully up to speed with it yet) this should work...

Code: [Select]
[size=x-small]
public void Mem::zero(void* src, size_t len)
{
    // move args into d0/a0 and call asm linked
    // function.
    asm("move.l %0, a0\n" \
        "move.l %1, d0\n" \
        "jsr Mem__asmZero__r9Pvr0Uj\n" : src : len);
}
[/size]


Failing that, I can just make the old asm C like and make them retrieve their args from the stack themselves. I dont' really see much of a difference ;-)
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #7 on: March 25, 2004, 07:23:18 PM »
Cool it worked :-D

Ok, just in case anybody else is in the same boat ever...

I found I can indeed make my old asm code work ok in GCC C++ mode. As I expected, I needed to make an inline function that calls the asm.

So, imagine you have some asm, that defines a function with the extported symbol _asmFunction. It takes register d0 and a0, clobbers d0/d1/a0/a1, returns nothing...

To call it (via an inline func in gcc c++ goes a bit like

Code: [Select]
[size=x-small]
inline void func(int i, int* j)
{
    asm("move.l %0, d0\n"
        "move.l %0, a0\n"
        "jsr _asmFunction\n"
        :                         // no outputs
        : "g"(i), "g"(j)          // inputs
        : "d0", "d1", "a0", "a1"  // clobbers
    );
}
[/size]


Right, now that little mystery is sorted, I can get on with stuff :-D
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #8 on: March 25, 2004, 08:20:37 PM »
Hi PiR,

Well extern "C" works, but the only downside is that you simply can't specify which registers the parameters are expected to be passed in, so you have to use the stack and change the assembler side. So work wise, it's swings and roundabouts. Either use the stack and pull the args in the asm, or inline the asm and put args in the register.

Oddly, in C mode, you can indeed specify the registers, just not with C++. Go figure...

-edit-

Slight explanation. In C mode you can have this in myheader.h, which defines your asm function's interface.

void func(int i __asm("d0"), int* j __asm("a0");

Doesn't work in C++ mode.

So you do your usual extern "C" trick to include the header, but it still refuses to take it due to the __asm() stuff.

Hence, back to square 1.

-/edit-

Not sure about your jsr comment there :-?

Every time I look at any compiler produced asm, function calls are always jsr in this fashion. I certianly havent had any problems with relocation.

-edit-

Incidentally, this is all for statically linked library code, not shared library code (if thats what you are hinting at).
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #9 on: March 25, 2004, 09:19:42 PM »
When you do the normal C++ "register" keyword, its only a hint to the compiler. It doesn't have to put the elements in registers, nor do you have any say in which ones..

Anyhow, I always code large data / code model an never had any problems relating to relocation of code at runtime. Even with shared libraries.

I'm no expert, but I believe the jsr doesn't quite evaluate to an absolute fixed address (only fixed for a given instance of the program) - it's an assembler convenience, after all...
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #10 on: March 26, 2004, 02:52:28 PM »
Hi,

The register usage information for the "this" pointer is worth knowing, thanks :-)

Yeah, missing the "register" keyword in (3) was a typo. It was there in the actual sourcecode, honest guv'nor :-)

As for the relocation stuff, what I meant by the "jsr " not being a fixed value was that the expression is handled by he assembler. Jsr can take just about any old effective address you can throw at it.

What I was thinking is that between the assembler and the linker itself doesn't evaluate to a fixed expression and is only resolved to some sort of relocatable value during linking. This doesn't upset the compiler offsets because the compiler itself generates assembler (ready to be assembled and linked) - ie it doesnt generate the object code directly. Also, the code output from the compiler uses the same sort of jsr based function calls too.

However it works, it works, and as you say, it is properly relocated at runtime.

So that's me off the hook for now :lol:
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #11 on: March 26, 2004, 08:45:23 PM »
Hi,

Thanks for the tip there :-) I'm a bit novice with GCC's inline assembler in that I only looked at it's documentation the same day I got the example I put here working ;-)
int p; // A
 

Offline KarlosTopic starter

  • Sockologist
  • Global Moderator
  • Hero Member
  • *****
  • Join Date: Nov 2002
  • Posts: 16879
  • Country: gb
  • Thanked: 5 times
    • Show all replies
Re: Help needed combining GCC/C++ with asm sources
« Reply #12 on: March 26, 2004, 09:44:45 PM »
Hmm, changes no workee...

Since I'm frightfully new to gcc's inline asm, just let me post what I got to make sure I followed (the actual real function here)

Code: [Select]
[size=x-small]
class Mem {
  // big snip...
  public:
    static void copy(void* dst, void* src, size_t len)
    {
       // call asm function...
       asm("\njsr _asmCopy\n"
       :                                   // no outputs
       : "a0"(dst), "a1"(src), "d0"(len)   // inputs
       : "d0", "d1", "a0", "a1", "cc", "m" // muchos clobber
    };
}
[/size]


The original "put the args explicitly into regs" worked fine. I now get a "matching constraint matches invalid operand" error :-?
int p; // A