implement function calling of functions with up to 4 arguments
authorRafael Espindola <rafael.espindola@gmail.com>
Tue, 25 Jul 2006 20:17:20 +0000 (20:17 +0000)
committerRafael Espindola <rafael.espindola@gmail.com>
Tue, 25 Jul 2006 20:17:20 +0000 (20:17 +0000)
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@29274 91177308-0d34-0410-b5e6-96231b3b80d8

lib/Target/ARM/ARMISelDAGToDAG.cpp
test/CodeGen/ARM/call.ll [new file with mode: 0644]

index 2eb89b7997205bc53746985249f1693cb06515ee..8ca7c0b40c0a7c9e45413bd0e7ec1629fd2917e1 100644 (file)
@@ -75,17 +75,38 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   assert(isTailCall == false && "tail call not supported");
   SDOperand Callee   = Op.getOperand(4);
   unsigned NumOps    = (Op.getNumOperands() - 5) / 2;
-  assert(NumOps == 0);
 
   // Count how many bytes are to be pushed on the stack. Initially
   // only the link register.
   unsigned NumBytes = 4;
 
+  assert(NumOps <= 4); //no args on the stack
+
   // Adjust the stack pointer for the new arguments...
   // These operations are automatically eliminated by the prolog/epilog pass
   Chain = DAG.getCALLSEQ_START(Chain,
                                DAG.getConstant(NumBytes, MVT::i32));
 
+  static const unsigned regs[] = {
+    ARM::R0, ARM::R1, ARM::R2, ARM::R3
+  };
+
+  std::vector<std::pair<unsigned, SDOperand> > RegsToPass;
+
+  for (unsigned i = 0; i != NumOps; ++i) {
+    SDOperand Arg = Op.getOperand(5+2*i);
+    RegsToPass.push_back(std::make_pair(regs[i], Arg));
+  }
+
+  // Build a sequence of copy-to-reg nodes chained together with token chain
+  // and flag operands which copy the outgoing args into the appropriate regs.
+  SDOperand InFlag;
+  for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
+    Chain = DAG.getCopyToReg(Chain, RegsToPass[i].first, RegsToPass[i].second,
+                             InFlag);
+    InFlag = Chain.getValue(1);
+  }
+
   std::vector<MVT::ValueType> NodeTys;
   NodeTys.push_back(MVT::Other);   // Returns a chain
   NodeTys.push_back(MVT::Flag);    // Returns a flag for retval copy to use.
@@ -103,14 +124,35 @@ static SDOperand LowerCALL(SDOperand Op, SelectionDAG &DAG) {
   Ops.push_back(Callee);
 
   unsigned CallOpc = ARMISD::CALL;
+  if (InFlag.Val)
+    Ops.push_back(InFlag);
   Chain = DAG.getNode(CallOpc, NodeTys, Ops);
+  InFlag = Chain.getValue(1);
+
+  std::vector<SDOperand> ResultVals;
+  NodeTys.clear();
 
-  assert(Op.Val->getValueType(0) == MVT::Other);
+  // If the call has results, copy the values out of the ret val registers.
+  switch (Op.Val->getValueType(0)) {
+  default: assert(0 && "Unexpected ret value!");
+  case MVT::Other:
+    break;
+  case MVT::i32:
+    Chain = DAG.getCopyFromReg(Chain, ARM::R0, MVT::i32, InFlag).getValue(1);
+    ResultVals.push_back(Chain.getValue(0));
+    NodeTys.push_back(MVT::i32);
+  }
 
   Chain = DAG.getNode(ISD::CALLSEQ_END, MVT::Other, Chain,
                       DAG.getConstant(NumBytes, MVT::i32));
+  NodeTys.push_back(MVT::Other);
+
+  if (ResultVals.empty())
+    return Chain;
 
-  return Chain;
+  ResultVals.push_back(Chain);
+  SDOperand Res = DAG.getNode(ISD::MERGE_VALUES, NodeTys, ResultVals);
+  return Res.getValue(Op.ResNo);
 }
 
 static SDOperand LowerRET(SDOperand Op, SelectionDAG &DAG) {
diff --git a/test/CodeGen/ARM/call.ll b/test/CodeGen/ARM/call.ll
new file mode 100644 (file)
index 0000000..cfffa99
--- /dev/null
@@ -0,0 +1,8 @@
+; RUN: llvm-as < %s | llc -march=arm
+void %f() {
+entry:
+       call void %g( int 1, int 2, int 3, int 4 )
+       ret void
+}
+
+declare void %g(int, int, int, int)