Implement READPORT/WRITEPORT, implementing the last X86 regression tests
authorChris Lattner <sabre@nondot.org>
Mon, 9 May 2005 21:17:38 +0000 (21:17 +0000)
committerChris Lattner <sabre@nondot.org>
Mon, 9 May 2005 21:17:38 +0000 (21:17 +0000)
that were failing with the pattern selector.  Note that the support that
existed in the simple selector was clearly broken in several ways though
(which has also been fixed).

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

lib/Target/X86/X86ISelPattern.cpp

index 584d4af3ef01b2170365858b92d7ffed0329465a..f9563a091ba151d8e41ebba11f886d4648f70bb2 100644 (file)
@@ -2660,6 +2660,67 @@ unsigned ISel::SelectExpr(SDOperand N) {
       break;
     }
     return Result+N.ResNo;
+  case ISD::READPORT:
+    // First, determine that the size of the operand falls within the acceptable
+    // range for this architecture.
+    //
+    if (Node->getOperand(1).getValueType() != MVT::i16) {
+      std::cerr << "llvm.readport: Address size is not 16 bits\n";
+      exit(1);
+    }
+
+    // Make sure we generate both values.
+    if (Result != 1) {  // Generate the token
+      if (!ExprMap.insert(std::make_pair(N.getValue(1), 1)).second)
+        assert(0 && "readport already emitted!?");
+    } else
+      Result = ExprMap[N.getValue(0)] = MakeReg(N.getValue(0).getValueType());
+    
+    Select(Node->getOperand(0));  // Select the chain.
+
+    // If the port is a single-byte constant, use the immediate form.
+    if (ConstantSDNode *Port = dyn_cast<ConstantSDNode>(Node->getOperand(1)))
+      if ((Port->getValue() & 255) == Port->getValue()) {
+        switch (Node->getValueType(0)) {
+        case MVT::i8:
+          BuildMI(BB, X86::IN8ri, 1).addImm(Port->getValue());
+          BuildMI(BB, X86::MOV8rr, 1, Result).addReg(X86::AL);
+          return Result;
+        case MVT::i16:
+          BuildMI(BB, X86::IN16ri, 1).addImm(Port->getValue());
+          BuildMI(BB, X86::MOV16rr, 1, Result).addReg(X86::AX);
+          return Result;
+        case MVT::i32:
+          BuildMI(BB, X86::IN32ri, 1).addImm(Port->getValue());
+          BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::EAX);
+          return Result;
+        default: break;
+        }
+      }
+
+    // Now, move the I/O port address into the DX register and use the IN
+    // instruction to get the input data.
+    //
+    Tmp1 = SelectExpr(Node->getOperand(1));
+    BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(Tmp1);
+    switch (Node->getValueType(0)) {
+    case MVT::i8:
+      BuildMI(BB, X86::IN8rr, 0);
+      BuildMI(BB, X86::MOV8rr, 1, Result).addReg(X86::AL);
+      return Result;
+    case MVT::i16:
+      BuildMI(BB, X86::IN16rr, 0);
+      BuildMI(BB, X86::MOV16rr, 1, Result).addReg(X86::AX);
+      return Result;
+    case MVT::i32:
+      BuildMI(BB, X86::IN32rr, 0);
+      BuildMI(BB, X86::MOV32rr, 1, Result).addReg(X86::EAX);
+      return Result;
+    default:
+      std::cerr << "Cannot do input on this data type";
+      exit(1);
+    }
+    
   }
 
   return 0;
@@ -3027,7 +3088,7 @@ void ISel::Select(SDOperand N) {
     ExprMap.erase(N);
     SelectExpr(N);
     return;
-
+  case ISD::READPORT:
   case ISD::EXTLOAD:
   case ISD::SEXTLOAD:
   case ISD::ZEXTLOAD:
@@ -3236,7 +3297,7 @@ void ISel::Select(SDOperand N) {
     BuildMI(BB, Opcode, 0);
     return;
   }
-  case ISD::MEMCPY:
+  case ISD::MEMCPY: {
     Select(N.getOperand(0));  // Select the chain.
     unsigned Align =
       (unsigned)cast<ConstantSDNode>(Node->getOperand(4))->getValue();
@@ -3282,6 +3343,45 @@ void ISel::Select(SDOperand N) {
     BuildMI(BB, Opcode, 0);
     return;
   }
+  case ISD::WRITEPORT:
+    if (Node->getOperand(2).getValueType() != MVT::i16) {
+      std::cerr << "llvm.writeport: Address size is not 16 bits\n";
+      exit(1);
+    }
+    Select(Node->getOperand(0)); // Emit the chain.
+
+    Tmp1 = SelectExpr(Node->getOperand(1));
+    switch (Node->getOperand(1).getValueType()) {
+    case MVT::i8:
+      BuildMI(BB, X86::MOV8rr, 1, X86::AL).addReg(Tmp1);
+      Tmp2 = X86::OUT8ir;  Opc = X86::OUT8rr;
+      break;
+    case MVT::i16:
+      BuildMI(BB, X86::MOV16rr, 1, X86::AX).addReg(Tmp1);
+      Tmp2 = X86::OUT16ir; Opc = X86::OUT16rr;
+      break;
+    case MVT::i32:
+      BuildMI(BB, X86::MOV32rr, 1, X86::EAX).addReg(Tmp1);
+      Tmp2 = X86::OUT32ir; Opc = X86::OUT32rr;
+      break;
+    default:
+      std::cerr << "llvm.writeport: invalid data type for X86 target";
+      exit(1);
+    }
+
+    // If the port is a single-byte constant, use the immediate form.
+    if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Node->getOperand(2)))
+      if ((CN->getValue() & 255) == CN->getValue()) {
+        BuildMI(BB, Tmp2, 1).addImm(CN->getValue());
+        return;
+      }
+
+    // Otherwise, move the I/O port address into the DX register.
+    unsigned Reg = SelectExpr(Node->getOperand(2));
+    BuildMI(BB, X86::MOV16rr, 1, X86::DX).addReg(Reg);
+    BuildMI(BB, Opc, 0);
+    return;
+  }
   assert(0 && "Should not be reached!");
 }