Inline assembly support for Blackfin.

We use the same constraints as GCC, including those that are slightly insane for inline assembler.

llvm-svn: 77899
This commit is contained in:
Jakob Stoklund Olesen 2009-08-02 17:39:17 +00:00
parent 526e803f6a
commit b052972a58
4 changed files with 175 additions and 12 deletions

View File

@ -498,34 +498,104 @@ unsigned BlackfinTargetLowering::getFunctionAlignment(const Function *F) const {
/// constraint it is for this target.
BlackfinTargetLowering::ConstraintType
BlackfinTargetLowering::getConstraintType(const std::string &Constraint) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
default: break;
case 'r': return C_RegisterClass;
}
if (Constraint.size() != 1)
return TargetLowering::getConstraintType(Constraint);
switch (Constraint[0]) {
// Standard constraints
case 'r':
return C_RegisterClass;
// Blackfin-specific constraints
case 'a':
case 'd':
case 'z':
case 'D':
case 'W':
case 'e':
case 'b':
case 'v':
case 'f':
case 'c':
case 't':
case 'u':
case 'k':
case 'x':
case 'y':
case 'w':
return C_RegisterClass;
case 'A':
case 'B':
case 'C':
case 'Z':
case 'Y':
return C_Register;
}
// Not implemented: q0-q7, qA. Use {R2} etc instead
return TargetLowering::getConstraintType(Constraint);
}
/// getRegForInlineAsmConstraint - Return register no and class for a C_Register
/// constraint.
std::pair<unsigned, const TargetRegisterClass*> BlackfinTargetLowering::
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const {
if (Constraint.size() == 1) {
switch (Constraint[0]) {
case 'r':
return std::make_pair(0U, BF::DRegisterClass);
}
typedef std::pair<unsigned, const TargetRegisterClass*> Pair;
using namespace BF;
if (Constraint.size() != 1)
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
switch (Constraint[0]) {
// Standard constraints
case 'r':
return Pair(0U, VT == MVT::i16 ? D16RegisterClass : DPRegisterClass);
// Blackfin-specific constraints
case 'a': return Pair(0U, PRegisterClass);
case 'd': return Pair(0U, DRegisterClass);
case 'e': return Pair(0U, AccuRegisterClass);
case 'A': return Pair(A0, AccuRegisterClass);
case 'B': return Pair(A1, AccuRegisterClass);
case 'b': return Pair(0U, IRegisterClass);
case 'v': return Pair(0U, BRegisterClass);
case 'f': return Pair(0U, MRegisterClass);
case 'C': return Pair(CC, JustCCRegisterClass);
case 'x': return Pair(0U, GRRegisterClass);
case 'w': return Pair(0U, ALLRegisterClass);
case 'Z': return Pair(P3, PRegisterClass);
case 'Y': return Pair(P1, PRegisterClass);
}
// Not implemented: q0-q7, qA. Use {R2} etc instead.
// Constraints z, D, W, c, t, u, k, and y use non-existing classes, defer to
// getRegClassForInlineAsmConstraint()
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
}
std::vector<unsigned> BlackfinTargetLowering::
getRegClassForInlineAsmConstraint(const std::string &Constraint,
MVT VT) const {
getRegClassForInlineAsmConstraint(const std::string &Constraint, MVT VT) const {
using namespace BF;
if (Constraint.size() != 1)
return std::vector<unsigned>();
switch (Constraint[0]) {
case 'z': return make_vector<unsigned>(P0, P1, P2, 0);
case 'D': return make_vector<unsigned>(R0, R2, R4, R6, 0);
case 'W': return make_vector<unsigned>(R1, R3, R5, R7, 0);
case 'c': return make_vector<unsigned>(I0, I1, I2, I3,
B0, B1, B2, B3,
L0, L1, L2, L3, 0);
case 't': return make_vector<unsigned>(LT0, LT1, 0);
case 'u': return make_vector<unsigned>(LB0, LB1, 0);
case 'k': return make_vector<unsigned>(LC0, LC1, 0);
case 'y': return make_vector<unsigned>(RETS, RETN, RETI, RETX, RETE,
ASTAT, SEQSTAT, USP, 0);
}
return std::vector<unsigned>();
}

View File

@ -281,6 +281,8 @@ def P : RegisterClass<"BF", [i32], 32, [P0, P1, P2, P3, P4, P5, FP, SP]> {
def I : RegisterClass<"BF", [i32], 32, [I0, I1, I2, I3]>;
def M : RegisterClass<"BF", [i32], 32, [M0, M1, M2, M3]>;
def B : RegisterClass<"BF", [i32], 32, [B0, B1, B2, B3]>;
def L : RegisterClass<"BF", [i32], 32, [L0, L1, L2, L3]>;
def DP : RegisterClass<"BF", [i32], 32,
[R0, R1, R2, R3, R4, R5, R6, R7,
@ -378,3 +380,6 @@ def AnyCC : RegisterClass<"BF", [i32], 8, [CC, NCC]> {
def StatBit : RegisterClass<"BF", [i1], 8,
[AZ, AN, CC, AQ, AC0, AC1, AV0, AV0S, AV1, AV1S, V, VS]>;
}
// Should be i40, but that isn't defined. It is not a legal type yet anyway.
def Accu : RegisterClass<"BF", [i64], 64, [A0, A1]>;

View File

@ -41,6 +41,56 @@ should keep track of:
It's a hack combining two instructions by concatenation.
* Inline Assembly
These are the GCC constraints from bfin/constraints.md:
| Code | Register class | LLVM |
|-------+-------------------------------------------+------|
| a | P | C |
| d | D | C |
| z | Call clobbered P (P0, P1, P2) | X |
| D | EvenD | X |
| W | OddD | X |
| e | Accu | C |
| A | A0 | S |
| B | A1 | S |
| b | I | C |
| v | B | C |
| f | M | C |
| c | Circular I, B, L | X |
| C | JustCC | S |
| t | LoopTop | X |
| u | LoopBottom | X |
| k | LoopCount | X |
| x | GR | C |
| y | RET*, ASTAT, SEQSTAT, USP | X |
| w | ALL | C |
| Z | The FD-PIC GOT pointer (P3) | S |
| Y | The FD-PIC function pointer register (P1) | S |
| q0-q7 | R0-R7 individually | |
| qA | P0 | |
|-------+-------------------------------------------+------|
| Code | Constant | |
|-------+-------------------------------------------+------|
| J | 1<<N, N<32 | |
| Ks3 | imm3 | |
| Ku3 | uimm3 | |
| Ks4 | imm4 | |
| Ku4 | uimm4 | |
| Ks5 | imm5 | |
| Ku5 | uimm5 | |
| Ks7 | imm7 | |
| KN7 | -imm7 | |
| Ksh | imm16 | |
| Kuh | uimm16 | |
| L | ~(1<<N) | |
| M1 | 0xff | |
| M2 | 0xffff | |
| P0-P4 | 0-4 | |
| PA | Macflag, not M | |
| PB | Macflag, only M | |
| Q | Symbol | |
** TODO Support all register classes
* DAG combiner
** Create test case for each Illegal SETCC case

View File

@ -0,0 +1,38 @@
; RUN: llvm-as < %s | llc -march=bfin | FileCheck %s
; Standard "r"
; CHECK: r0 = r0 + r1;
define i32 @add_r(i32 %A, i32 %B) {
%R = call i32 asm "$0 = $1 + $2;", "=r,r,r"( i32 %A, i32 %B ) nounwind
ret i32 %R
}
; Target "d"
; CHECK: r0 = r0 - r1;
define i32 @add_d(i32 %A, i32 %B) {
%R = call i32 asm "$0 = $1 - $2;", "=d,d,d"( i32 %A, i32 %B ) nounwind
ret i32 %R
}
; Target "a" for P-regs
; CHECK: p0 = (p0 + p1) << 1;
define i32 @add_a(i32 %A, i32 %B) {
%R = call i32 asm "$0 = ($1 + $2) << 1;", "=a,a,a"( i32 %A, i32 %B ) nounwind
ret i32 %R
}
; Target "z" for P0, P1, P2. This is not a real regclass
; CHECK: p0 = (p0 + p1) << 2;
define i32 @add_Z(i32 %A, i32 %B) {
%R = call i32 asm "$0 = ($1 + $2) << 2;", "=z,z,z"( i32 %A, i32 %B ) nounwind
ret i32 %R
}
; Target "C" for CC. This is a single register
; CHECK: cc = p0 < p1;
; CHECK: r0 = cc;
define i32 @add_C(i32 %A, i32 %B) {
%R = call i32 asm "$0 = $1 < $2;", "=C,z,z"( i32 %A, i32 %B ) nounwind
ret i32 %R
}