[Sparc] Add support for inline assembly constraint 'I'.
authorVenkatraman Govindaraju <venkatra@cs.wisc.edu>
Wed, 22 Jan 2014 01:29:51 +0000 (01:29 +0000)
committerVenkatraman Govindaraju <venkatra@cs.wisc.edu>
Wed, 22 Jan 2014 01:29:51 +0000 (01:29 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@199781 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/Sparc/SparcISelLowering.cpp
lib/Target/Sparc/SparcISelLowering.h
test/CodeGen/SPARC/inlineasm.ll [new file with mode: 0644]

index 3abccdef6ef931d7f97b26b9f6d7c475b5fe9b84..6dae29c45c07555b09646a640a641a6004512bb0 100644 (file)
@@ -2923,12 +2923,72 @@ SparcTargetLowering::getConstraintType(const std::string &Constraint) const {
     switch (Constraint[0]) {
     default:  break;
     case 'r': return C_RegisterClass;
+    case 'I': // SIMM13
+      return C_Other;
     }
   }
 
   return TargetLowering::getConstraintType(Constraint);
 }
 
+TargetLowering::ConstraintWeight SparcTargetLowering::
+getSingleConstraintMatchWeight(AsmOperandInfo &info,
+                               const char *constraint) const {
+  ConstraintWeight weight = CW_Invalid;
+  Value *CallOperandVal = info.CallOperandVal;
+  // If we don't have a value, we can't do a match,
+  // but allow it at the lowest weight.
+  if (CallOperandVal == NULL)
+    return CW_Default;
+
+  // Look at the constraint type.
+  switch (*constraint) {
+  default:
+    weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
+    break;
+  case 'I': // SIMM13
+    if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) {
+      if (isInt<13>(C->getSExtValue()))
+        weight = CW_Constant;
+    }
+    break;
+  }
+  return weight;
+}
+
+/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
+/// vector.  If it is invalid, don't add anything to Ops.
+void SparcTargetLowering::
+LowerAsmOperandForConstraint(SDValue Op,
+                             std::string &Constraint,
+                             std::vector<SDValue> &Ops,
+                             SelectionDAG &DAG) const {
+  SDValue Result(0, 0);
+
+  // Only support length 1 constraints for now.
+  if (Constraint.length() > 1)
+    return;
+
+  char ConstraintLetter = Constraint[0];
+  switch (ConstraintLetter) {
+  default: break;
+  case 'I':
+    if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
+      if (isInt<13>(C->getSExtValue())) {
+        Result = DAG.getTargetConstant(C->getSExtValue(), Op.getValueType());
+        break;
+      }
+      return;
+    }
+  }
+
+  if (Result.getNode()) {
+    Ops.push_back(Result);
+    return;
+  }
+  TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
 std::pair<unsigned, const TargetRegisterClass*>
 SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
                                                   MVT VT) const {
index 2659fc89501de3a029aa599bc99a8d29375eefe7..36d569e3b6917d30c386dd103b958a8ef1a79193 100644 (file)
@@ -73,6 +73,13 @@ namespace llvm {
     virtual const char *getTargetNodeName(unsigned Opcode) const;
 
     ConstraintType getConstraintType(const std::string &Constraint) const;
+    ConstraintWeight
+    getSingleConstraintMatchWeight(AsmOperandInfo &info,
+                                   const char *constraint) const;
+    void LowerAsmOperandForConstraint(SDValue Op,
+                                      std::string &Constraint,
+                                      std::vector<SDValue> &Ops,
+                                      SelectionDAG &DAG) const;
     std::pair<unsigned, const TargetRegisterClass*>
     getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const;
 
diff --git a/test/CodeGen/SPARC/inlineasm.ll b/test/CodeGen/SPARC/inlineasm.ll
new file mode 100644 (file)
index 0000000..7ecdd67
--- /dev/null
@@ -0,0 +1,35 @@
+; RUN: llc -march=sparc <%s | FileCheck %s
+
+; CHECK-LABEL: test_constraint_r
+; CHECK:       add %o1, %o0, %o0
+define i32 @test_constraint_r(i32 %a, i32 %b) {
+entry:
+  %0 = tail call i32 asm sideeffect "add $2, $1, $0", "=r,r,r"(i32 %a, i32 %b)
+  ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I
+; CHECK:       add %o0, 1023, %o0
+define i32 @test_constraint_I(i32 %a) {
+entry:
+  %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 1023)
+  ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I_neg
+; CHECK:       add %o0, -4096, %o0
+define i32 @test_constraint_I_neg(i32 %a) {
+entry:
+  %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 -4096)
+  ret i32 %0
+}
+
+; CHECK-LABEL: test_constraint_I_largeimm
+; CHECK:       sethi 9, [[R0:%[gilo][0-7]]]
+; CHECK:       or [[R0]], 784, [[R1:%[gilo][0-7]]]
+; CHECK:       add %o0, [[R1]], %o0
+define i32 @test_constraint_I_largeimm(i32 %a) {
+entry:
+  %0 = tail call i32 asm sideeffect "add $1, $2, $0", "=r,r,rI"(i32 %a, i32 10000)
+  ret i32 %0
+}