Handle physreg input/outputs. We now compile this:
authorChris Lattner <sabre@nondot.org>
Tue, 31 Jan 2006 02:03:41 +0000 (02:03 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 31 Jan 2006 02:03:41 +0000 (02:03 +0000)
int %test_cpuid(int %op) {
        %B = alloca int
        %C = alloca int
        %D = alloca int
        %A = call int asm "cpuid", "=eax,==ebx,==ecx,==edx,eax"(int* %B, int* %C, int* %D, int %op)
        %Bv = load int* %B
        %Cv = load int* %C
        %Dv = load int* %D
        %x = add int %A, %Bv
        %y = add int %x, %Cv
        %z = add int %y, %Dv
        ret int %z
}

to this:

_test_cpuid:
        sub %ESP, 16
        mov DWORD PTR [%ESP], %EBX
        mov %EAX, DWORD PTR [%ESP + 20]
        cpuid
        mov DWORD PTR [%ESP + 8], %ECX
        mov DWORD PTR [%ESP + 12], %EBX
        mov DWORD PTR [%ESP + 4], %EDX
        mov %ECX, DWORD PTR [%ESP + 12]
        add %EAX, %ECX
        mov %ECX, DWORD PTR [%ESP + 8]
        add %EAX, %ECX
        mov %ECX, DWORD PTR [%ESP + 4]
        add %EAX, %ECX
        mov %EBX, DWORD PTR [%ESP]
        add %ESP, 16
        ret

... note the proper register allocation.  :)

it is unclear to me why the loads aren't folded into the adds.

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@25827 91177308-0d34-0410-b5e6-96231b3b80d8

lib/CodeGen/SelectionDAG/ScheduleDAG.cpp
lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp

index 4e45bd65646b1b537801a235c2afc29448848ae3..9f285d5c9c96d44bc24b1803a7371c7d2454e5df 100644 (file)
@@ -300,7 +300,7 @@ void ScheduleDAG::EmitNode(NodeInfo *NI) {
       // Add all of the operand registers to the instruction.
       for (unsigned i = 2; i != NumOps; i += 2) {
         unsigned Reg = cast<RegisterSDNode>(Node->getOperand(i))->getReg();
-        unsigned Flags = cast<ConstantSDNode>(Node->getOperand(i))->getValue();
+        unsigned Flags =cast<ConstantSDNode>(Node->getOperand(i+1))->getValue();
         MachineOperand::UseType UseTy;
         switch (Flags) {
         default: assert(0 && "Bad flags!");
index 78db4554dae5408ec1bed2a491f4bf86356154e4..32fff90e966013b2be1cbd3df2e4de16d454cb4d 100644 (file)
@@ -1158,7 +1158,6 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
 
   std::vector<std::pair<InlineAsm::ConstraintPrefix, std::string> > 
     Constraints = IA->ParseConstraints();
-
   
   /// AsmNodeOperands - A list of pairs.  The first element is a register, the
   /// second is a bitfield where bit #0 is set if it is a use and bit #1 is set
@@ -1170,7 +1169,69 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
   SDOperand Chain = getRoot();
   SDOperand Flag;
   
-  // FIXME: input copies.
+  // Loop over all of the inputs, copying the operand values into the
+  // appropriate registers and processing the output regs.
+  unsigned RetValReg = 0;
+  std::vector<std::pair<unsigned, Value*> > IndirectStoresToEmit;
+  unsigned OpNum = 1;
+  bool FoundOutputConstraint = false;
+  for (unsigned i = 0, e = Constraints.size(); i != e; ++i) {
+    switch (Constraints[i].first) {
+      case InlineAsm::isOutput: {
+      assert(!FoundOutputConstraint &&
+             "Cannot have multiple output constraints yet!");
+      FoundOutputConstraint = true;
+      assert(I.getType() != Type::VoidTy && "Bad inline asm!");
+      // Copy the output from the appropriate register.
+      std::vector<unsigned> Regs =
+      TLI.getRegForInlineAsmConstraint(Constraints[i].second);
+      assert(Regs.size() == 1 && "Only handle simple regs right now!");
+      RetValReg = Regs[0];
+      
+      // Add information to the INLINEASM node to know that this register is
+      // set.
+      AsmNodeOperands.push_back(DAG.getRegister(RetValReg,
+                                                TLI.getValueType(I.getType())));
+      AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF
+      break;
+    }
+    case InlineAsm::isIndirectOutput: {
+      // Copy the output from the appropriate register.
+      std::vector<unsigned> Regs =
+        TLI.getRegForInlineAsmConstraint(Constraints[i].second);
+      assert(Regs.size() == 1 && "Only handle simple regs right now!");
+      IndirectStoresToEmit.push_back(std::make_pair(Regs[0],
+                                                    I.getOperand(OpNum)));
+      OpNum++;  // Consumes a call operand.
+      
+      // Add information to the INLINEASM node to know that this register is
+      // set.
+      AsmNodeOperands.push_back(DAG.getRegister(Regs[0],
+                                                TLI.getValueType(I.getType())));
+      AsmNodeOperands.push_back(DAG.getConstant(2, MVT::i32)); // ISDEF
+      break;
+    }
+    case InlineAsm::isInput: {
+      // Copy the input into the appropriate register.
+      std::vector<unsigned> Regs =
+        TLI.getRegForInlineAsmConstraint(Constraints[i].second);
+      assert(Regs.size() == 1 && "Only handle simple regs right now!");
+      Chain = DAG.getCopyToReg(Chain, Regs[0], 
+                               getValue(I.getOperand(OpNum)), Flag);
+      Flag = Chain.getValue(1);
+      
+      // Add information to the INLINEASM node to know that this register is
+      // read.
+      AsmNodeOperands.push_back(DAG.getRegister(Regs[0],
+                                                TLI.getValueType(I.getType())));
+      AsmNodeOperands.push_back(DAG.getConstant(1, MVT::i32)); // ISUSE
+      break;
+    }
+    case InlineAsm::isClobber:
+      // Nothing to do.
+      break;
+    }
+  }
   
   // Finish up input operands.
   AsmNodeOperands[0] = Chain;
@@ -1182,8 +1243,40 @@ void SelectionDAGLowering::visitInlineAsm(CallInst &I) {
   Chain = DAG.getNode(ISD::INLINEASM, VTs, AsmNodeOperands);
   Flag = Chain.getValue(1);
 
-  // FIXME: Copies out of registers here, setValue(CI).
+  // If this asm returns a register value, copy the result from that register
+  // and set it as the value of the call.
+  if (RetValReg) {
+    SDOperand Val = DAG.getCopyFromReg(Chain, RetValReg,
+                                       TLI.getValueType(I.getType()), Flag);
+    Chain = Val.getValue(1);
+    Flag  = Val.getValue(2);
+    setValue(&I, Val);
+  }
+  
+  std::vector<std::pair<SDOperand, Value*> > StoresToEmit;
+  
+  // Process indirect outputs, first output all of the flagged copies out of
+  // physregs.
+  for (unsigned i = 0, e = IndirectStoresToEmit.size(); i != e; ++i) {
+    Value *Ptr = IndirectStoresToEmit[i].second;
+    const Type *Ty = cast<PointerType>(Ptr->getType())->getElementType();
+    SDOperand Val = DAG.getCopyFromReg(Chain, IndirectStoresToEmit[i].first, 
+                                       TLI.getValueType(Ty), Flag);
+    Chain = Val.getValue(1);
+    Flag  = Val.getValue(2);
+    StoresToEmit.push_back(std::make_pair(Val, Ptr));
+    OpNum++;  // Consumes a call operand.
+  }
   
+  // Emit the non-flagged stores from the physregs.
+  std::vector<SDOperand> OutChains;
+  for (unsigned i = 0, e = StoresToEmit.size(); i != e; ++i)
+    OutChains.push_back(DAG.getNode(ISD::STORE, MVT::Other, Chain, 
+                                    StoresToEmit[i].first,
+                                    getValue(StoresToEmit[i].second),
+                                    DAG.getSrcValue(StoresToEmit[i].second)));
+  if (!OutChains.empty())
+    Chain = DAG.getNode(ISD::TokenFactor, MVT::Other, OutChains);
   DAG.setRoot(Chain);
 }