diff --git a/lib/Target/Blackfin/BlackfinISelLowering.cpp b/lib/Target/Blackfin/BlackfinISelLowering.cpp index a4af0ad9e79..4b1bd9d9244 100644 --- a/lib/Target/Blackfin/BlackfinISelLowering.cpp +++ b/lib/Target/Blackfin/BlackfinISelLowering.cpp @@ -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>(); } diff --git a/lib/Target/Blackfin/BlackfinRegisterInfo.td b/lib/Target/Blackfin/BlackfinRegisterInfo.td index 2b06fe34964..642d10f5aa6 100644 --- a/lib/Target/Blackfin/BlackfinRegisterInfo.td +++ b/lib/Target/Blackfin/BlackfinRegisterInfo.td @@ -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]>; diff --git a/lib/Target/Blackfin/README.txt b/lib/Target/Blackfin/README.txt index 4631c12f7e7..67c1e514bc7 100644 --- a/lib/Target/Blackfin/README.txt +++ b/lib/Target/Blackfin/README.txt @@ -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 diff --git a/test/CodeGen/Blackfin/inline-asm.ll b/test/CodeGen/Blackfin/inline-asm.ll new file mode 100644 index 00000000000..ee8fbb01604 --- /dev/null +++ b/test/CodeGen/Blackfin/inline-asm.ll @@ -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 +} +