[MIPS] How can I add a constraint to LLVM/Clang for MIPS BE?

Jia,

Try this in : lib/Basic/Targets.cpp ~line 4390

virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default:
return false;

case ‘r’: // CPU registers.
case ‘d’: // Equivalent to “r” unless generating MIPS16 code.
case ‘y’: // Equivalent to “r”, backwards compatibility only.
case ‘f’: // floating-point registers.
case ‘c’: // $25 for indirect jumps
case ‘l’: // lo register
case ‘x’: // hilo register pair
Info.setAllowsRegister();
return true;
case ‘R’: // An address tha can be sued in a non-macro load or store
Info.setAllowsMemory();
return true;
}

Jack

On 02/28/2013 08:12 AM, Jia Liu wrote:> Hi all,

Jia,

Try this in : lib/Basic/Targets.cpp ~line 4390

virtual bool validateAsmConstraint(const char *&Name,
TargetInfo::ConstraintInfo &Info) const {
switch (*Name) {
default:
return false;

case ‘r’: // CPU registers.
case ‘d’: // Equivalent to “r” unless generating MIPS16 code.
case ‘y’: // Equivalent to “r”, backwards compatibility only.
case ‘f’: // floating-point registers.
case ‘c’: // $25 for indirect jumps
case ‘l’: // lo register
case ‘x’: // hilo register pair
Info.setAllowsRegister();
return true;
case ‘R’: // An address tha can be sued in a non-macro load or store
Info.setAllowsMemory();
return true;
}

Jack

On 02/28/2013 08:12 AM, Jia Liu wrote:> Hi all,

Hi Jack,

Jia,

Try this in : lib/Basic/Targets.cpp ~line 4390

  virtual bool validateAsmConstraint(const char *&Name,
                                     TargetInfo::ConstraintInfo &Info) const
{
    switch (*Name) {
    default:
      return false;

    case 'r': // CPU registers.
    case 'd': // Equivalent to "r" unless generating MIPS16 code.
    case 'y': // Equivalent to "r", backwards compatibility only.
    case 'f': // floating-point registers.
    case 'c': // $25 for indirect jumps
    case 'l': // lo register

    case 'x': // hilo register pair
      Info.setAllowsRegister();
      return true;
    case 'R': // An address tha can be sued in a non-macro load or store
      Info.setAllowsMemory();
      return true;
    }

This is what exactly I did, I've attach my clang patch in the mail like this:
diff --git a/lib/Basic/Targets.cpp b/lib/Basic/Targets.cpp
index 24a69ee..854e12b 100644
--- a/lib/Basic/Targets.cpp
+++ b/lib/Basic/Targets.cpp
@@ -4393,6 +4393,9 @@ public:
     case 'x': // hilo register pair
       Info.setAllowsRegister();
       return true;
+ case 'R': // An address that can be used in a non-macro load or store
+ Info.setAllowsMemory();
+ return true;
     }
   }

Then I get wrong generated code, more ideas, please?

Jack

On 02/28/2013 08:12 AM, Jia Liu wrote:> Hi all,

I find clang-mips doesn't support constraint 'R' and I'm trying make
LLVM/Clang support it.
I did a little job, but Clang can not generate right code, it use the
same register in inline asm,
and the binary will segment fault in MIPS environment.

Regards,
Jia

Jia,

I made what I believe to be the correct changes and rebuilt clang and llc. Are the results what you expected? I so I will prepare the patches for commitment.

Jack

clang ../mips_R_JiaLiu.c -o mips_R_JiaLiu.ll -emit-llvm -O3 -S -target mipsel-unknown-linux -std=gnu89
llc mips_R_JiaLiu.ll -o mips_R_JiaLiu.o -mcpu=mips32r2 -march=mipsel -filetype=obj
mips-linux-gnu-gcc -mips32r2 -O3 -EL -fPIC -o mips_R_JiaLiu.exe mips_R_JiaLiu.o

inline_asm: run *.exe
out is 4
out is 10
out is ccddffbb
inline_asm:

Hi Jack

Jia,

I made what I believe to be the correct changes and rebuilt clang and llc. Are the results what you expected? I so I will prepare the patches for commitment.

Jack

clang ../mips_R_JiaLiu.c -o mips_R_JiaLiu.ll -emit-llvm -O3 -S -target mipsel-unknown-linux -std=gnu89
llc mips_R_JiaLiu.ll -o mips_R_JiaLiu.o -mcpu=mips32r2 -march=mipsel -filetype=obj
mips-linux-gnu-gcc -mips32r2 -O3 -EL -fPIC -o mips_R_JiaLiu.exe mips_R_JiaLiu.o

inline_asm: run *.exe
out is 4
out is 10
out is ccddffbb
inline_asm:

llvm-install/bin/clang -target mipsel-unknown-linux-gnu -gcc-toolchain
$SDK/mipsel-linux-gnu --sysroot $SDK/mipsel-gnu-rootfs -S
constraints.c

inline_asm:
  #APP
  lw $2, 0($2)
  #NO_APP

  #APP
  lw $1, 0($1)
  #NO_APP

  #APP
  lwl $1, 1 + 0($1)
  lwr $1, 2 + 0($1)
  #NO_APP

Please cc me if you will send the patches, I wanna know what I missed.

And, will you please point what is wrong with my patches in my first mail?
I wonder how can I make it right.

Regards,
Jia

Hi Jack,

Jia,

I made what I believe to be the correct changes and rebuilt clang and llc. Are the results what you expected? I so I will prepare the patches for commitment.

Jack

clang ../mips_R_JiaLiu.c -o mips_R_JiaLiu.ll -emit-llvm -O3 -S -target mipsel-unknown-linux -std=gnu89
llc mips_R_JiaLiu.ll -o mips_R_JiaLiu.o -mcpu=mips32r2 -march=mipsel -filetype=obj
mips-linux-gnu-gcc -mips32r2 -O3 -EL -fPIC -o mips_R_JiaLiu.exe mips_R_JiaLiu.o

I use your way to compile test case:
llvm-install/bin/clang constraints.c -o constraints.ll -emit-llvm -O3
-S -target mipsel-unknown-linux -std=gnu89 --sysroot
/Users/jia/project/Cross-SDK/sdk/mipsel-gnu-rootfs
llvm-install/bin/llc constraints.ll -o constraints.llc.s
-mcpu=mips32r2 -march=mipsel -filetype=asm
llvm-install/bin/llc constraints.ll -o constraints.o -mcpu=mips32r2
-march=mipsel -filetype=obj
mipsel-unknown-linux-gnu-gcc -mips32r2 -O3 -EL -fPIC -static -o
constraints.exe constraints.o

the inline-asm is:
  #APP
  lw $5, 0($1)
  #NO_APP

  #APP
  lw $5, 0($1)
  #NO_APP

  #APP
  lwl $5, 1 + 0($1)
  lwr $5, 2 + 0($1)
  #NO_APP

It use different registers, but $1, that is $AT, cann't be used, it is
reserved for $AS using.
any ideas?

inline_asm: run *.exe
out is 4
out is 10
out is ccddffbb
inline_asm:

Regards,
Jia

Maybe try:

.set noat

AT is needed to create certain instructions from pseudo instructions, so you have to be careful how you use this. Some instructions that you can use in Mips assembler are in fact pseudos.

While AT is not available to it (.set noat), the assembler can not assemble certain pseudos for you.

Here is part of the problem...

Gcc does not try to be creative with AT. It's a reserved register just like it is with gas by default.

We use AT as an allocatable register and never emit instructions that would require the assembler to be need to use AT.

By default we have :

.set noat

So if you try and use assembly instructions that need AT you will have a problem.

So you could add

.set at

and at AT to the clobber list.

Quite possibly it would be more correct for use to do this for you when inline assembly is present.

I.e.

.set AT
and add AT to the clobber list

however we don't do that at this time.