This is the mail archive of the
gcc@gcc.gnu.org
mailing list for the GCC project.
Operator overloading in (MIPS) assembly-language
- From: Barry Wealand <barry dot wealand at lmco dot com>
- To: gcc at gcc dot gnu dot org
- Cc: barry dot wealand at lmco dot com, "Kancler, Cliff" <cliff dot kancler at lmco dot com>, reed at reedkotler dot com
- Date: Mon, 22 Mar 2004 15:38:04 -0800
- Subject: Operator overloading in (MIPS) assembly-language
Hello -
We've been working with a GNU MIPS cross-compiler / toolset, generating
code for MIPS-like hardware to which we've added some new features.
These new features typically take the form of new instructions, and thus
we've needed a way to teach the compiler how to use these new
instructions. We don't have the resources to undertake a genuine
compiler modification, but we've had pretty good success using the
following methodology: We define a new (C++) type (typically a struct)
with a single data member of some built-in type; then we overload the
operators on that new type with inline functions containing
assembly-language statements using the new instructions. Using the
-freg-struct-return compiler flag, the compiler does a pretty good job
of generating code in this fashion... but there's a mystery that's
puzzled me for some time now.
The best way to illustrate is with an example. Assume we wanted to add
a new floating-point type to the MIPS instruction set architecture. The
existing architecture supports single (assembler mnemonic "s"), and
double (assembler mnemonic "d") precisions; assembler mnemonics also
exist for word-with ("w") and double-word-width ("l") fixed-point /
integer data types, which are primarily used in type conversions. For
this example, we'll define a new format that will use the assembler
mnemonic "f", and reuse the basic FPU instructions with this new
format. So, for example, we'll define new instructions: add.f, sub.f,
mul.f, etc. The mapping of these new instructions to machine code need
not be elaborated here - it will suffice to consider the
assembly-language code generated by the compiler.
Next, a header file is created, say new_float.h:
#ifndef _NEW_FLOAT_H
#define _NEW_FLOAT_H
struct new_float {
float value;
new_float() {value = 0.0;}
};
inline new_float operator+(new_float op1, new_float op2)
{
new_float f;
asm("add.f %0,%1,%2" : "=f" (f.value) : "f" (op1.value), "f"
(op2.value));
return f;
}
inline new_float operator-(new_float op1, new_float op2)
{
new_float f;
asm("sub.f %0,%1,%2" : "=f" (f.value) : "f" (op1.value), "f"
(op2.value));
return f;
}
inline new_float operator*(new_float op1, new_float op2)
{
new_float f;
asm("mul.f %0,%1,%2" : "=f" (f.value) : "f" (op1.value), "f"
(op2.value));
return f;
}
#endif
(This is intentionally abbreviated - the full-up version would have a
lot more stuff in it.)
Next, create a short C++ test program, call it new_float_test.C:
#include "new_float.h"
new_float test_func(
new_float a,
new_float b,
new_float c
)
{
new_float d, e;
new_float result;
d = a * b + b * c;
e = a * c - b * d;
result = d * e;
return result;
}
Finally, compile this test program to assembly-language:
mips-elf-g++ -O2 -freg-struct-return -S new_float_test.C
and look at the generated assembly-language file, new_float_test.s:
1 .file 1 "new_float_test.C"
2 .section .mdebug.abi32
3 .previous
4 .text
5 .align 2
6 .globl _Z9test_func9new_floatS_S_
7 $LFB1:
8 .ent _Z9test_func9new_floatS_S_
9 _Z9test_func9new_floatS_S_:
10 .frame $sp,8,$31 # vars= 8, regs= 0/0, args=
0, extra= 0
11 .mask 0x00000000,0
12 .fmask 0x00000000,0
13 subu $sp,$sp,8
14 $LCFI0:
15 mtc1 $6,$f2
16 #APP
17 mul.f $f8,$f12,$f2
18 mul.f $f12,$f12,$f14
19 mul.f $f2,$f14,$f2
20 add.f $f4,$f12,$f2
21 mul.f $f14,$f14,$f4
22 sub.f $f6,$f8,$f14
23 mul.f $f0,$f4,$f6
24 #NO_APP
25 s.s $f12,0($sp)
26 s.s $f2,0($sp)
27 s.s $f4,0($sp)
28 s.s $f8,0($sp)
29 s.s $f14,0($sp)
30 s.s $f6,0($sp)
31 .set noreorder
32 .set nomacro
33 j $31
34 addu $sp,$sp,8
35 .set macro
36 .set reorder
37
38 .end _Z9test_func9new_floatS_S_
39 $LFE1:
(I've added the line numbers for convenience). Everything in this
listing looks perfectly normal except lines 25 through 30. None of
these 6 store instructions serves any purpose at all. First of all,
they all write into the same slot on the stack, effectively clobbering
each other; and then everything in this stack frame is discarded on line
34, and nothing is ever read from it.
So that's the mystery I spoke of. I'd like to find a way to eliminate
these extraneous store instructions. I'm wondering if I might add any
directives, etc., to the operator functions, or whatever else might help
accomplish this. Any insights would be greatly appreciated.
Thanks in advance -
Barry Wealand
Lockheed Martin Space Systems Co.
barry.wealand@lmco.com