Add direct support for integer select instructions, though we still don't support
authorChris Lattner <sabre@nondot.org>
Tue, 30 Mar 2004 21:22:00 +0000 (21:22 +0000)
committerChris Lattner <sabre@nondot.org>
Tue, 30 Mar 2004 21:22:00 +0000 (21:22 +0000)
folding compares into the select yet.

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

lib/Target/X86/InstSelectSimple.cpp
lib/Target/X86/X86ISelSimple.cpp
lib/Target/X86/X86TargetMachine.cpp

index a2eb1a86a2d1821659b35389a6f6c5b433af5e24..6ffddd1bd7392614f6dbf054e090f062a98f2390 100644 (file)
@@ -174,6 +174,8 @@ namespace {
     unsigned EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
                             MachineBasicBlock *MBB,
                             MachineBasicBlock::iterator MBBI);
+    void visitSelectInst(SelectInst &SI);
+    
     
     // Memory Instructions
     void visitLoadInst(LoadInst &I);
@@ -261,6 +263,12 @@ namespace {
                             Value *Op, Value *ShiftAmount, bool isLeftShift,
                             const Type *ResultTy, unsigned DestReg);
       
+    /// emitSelectOperation - Common code shared between visitSelectInst and the
+    /// constant expression support.
+    void emitSelectOperation(MachineBasicBlock *MBB,
+                             MachineBasicBlock::iterator IP,
+                             Value *Cond, Value *TrueVal, Value *FalseVal,
+                             unsigned DestReg);
 
     /// copyConstantToRegister - Output the instructions required to put the
     /// specified constant into the specified register.
@@ -426,6 +434,11 @@ void ISel::copyConstantToRegister(MachineBasicBlock *MBB,
                          CE->getOpcode() == Instruction::Shl, CE->getType(), R);
       return;
 
+    case Instruction::Select:
+      emitSelectOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1),
+                          CE->getOperand(2), R);
+      return;
+
     default:
       std::cerr << "Offending expr: " << C << "\n";
       assert(0 && "Constant expression not yet handled!\n");
@@ -890,7 +903,6 @@ unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
   return OpNum;
 }
 
-
 /// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
 /// register, then move it to wherever the result should be. 
 ///
@@ -927,6 +939,89 @@ void ISel::emitSetCCOperation(MachineBasicBlock *MBB,
   }
 }
 
+void ISel::visitSelectInst(SelectInst &SI) {
+  unsigned DestReg = getReg(SI);
+  MachineBasicBlock::iterator MII = BB->end();
+  emitSelectOperation(BB, MII, SI.getCondition(), SI.getTrueValue(),
+                      SI.getFalseValue(), DestReg);
+}
+/// emitSelect - Common code shared between visitSelectInst and the constant
+/// expression support.
+void ISel::emitSelectOperation(MachineBasicBlock *MBB,
+                               MachineBasicBlock::iterator IP,
+                               Value *Cond, Value *TrueVal, Value *FalseVal,
+                               unsigned DestReg) {
+  unsigned SelectClass = getClassB(TrueVal->getType());
+  
+  // We don't support 8-bit conditional moves.  If we have incoming constants,
+  // transform them into 16-bit constants to avoid having a run-time conversion.
+  if (SelectClass == cByte) {
+    if (Constant *T = dyn_cast<Constant>(TrueVal))
+      TrueVal = ConstantExpr::getCast(T, Type::ShortTy);
+    if (Constant *F = dyn_cast<Constant>(FalseVal))
+      FalseVal = ConstantExpr::getCast(F, Type::ShortTy);
+  }
+
+  // Get the value being branched on, and use it to set the condition codes.
+  unsigned CondReg = getReg(Cond, MBB, IP);
+  BuildMI(*MBB, IP, X86::CMP8ri, 2).addReg(CondReg).addImm(0);
+
+  unsigned TrueReg  = getReg(TrueVal, MBB, IP);
+  unsigned FalseReg = getReg(FalseVal, MBB, IP);
+  unsigned RealDestReg = DestReg;
+  unsigned Opcode;
+
+  switch (SelectClass) {
+  case cFP:
+    assert(0 && "We don't support floating point selects yet, they should "
+           "have been lowered!");
+  case cByte:
+  case cShort:
+    Opcode = X86::CMOVE16rr;
+    break;
+  case cInt:
+  case cLong:
+    Opcode = X86::CMOVE32rr;
+    break;
+  }
+
+  // Annoyingly enough, X86 doesn't HAVE 8-bit conditional moves.  Because of
+  // this, we have to promote the incoming values to 16 bits, perform a 16-bit
+  // cmove, then truncate the result.
+  if (SelectClass == cByte) {
+    DestReg = makeAnotherReg(Type::ShortTy);
+    if (getClassB(TrueVal->getType()) == cByte) {
+      // Promote the true value, by storing it into AL, and reading from AX.
+      BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::AL).addReg(TrueReg);
+      BuildMI(*MBB, IP, X86::MOV8ri, 1, X86::AH).addImm(0);
+      TrueReg = makeAnotherReg(Type::ShortTy);
+      BuildMI(*MBB, IP, X86::MOV16rr, 1, TrueReg).addReg(X86::AX);
+    }
+    if (getClassB(FalseVal->getType()) == cByte) {
+      // Promote the true value, by storing it into CL, and reading from CX.
+      BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(FalseReg);
+      BuildMI(*MBB, IP, X86::MOV8ri, 1, X86::CH).addImm(0);
+      FalseReg = makeAnotherReg(Type::ShortTy);
+      BuildMI(*MBB, IP, X86::MOV16rr, 1, FalseReg).addReg(X86::CX);
+    }
+  }
+
+  BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(TrueReg).addReg(FalseReg);
+
+  switch (SelectClass) {
+  case cByte:
+    // We did the computation with 16-bit registers.  Truncate back to our
+    // result by copying into AX then copying out AL.
+    BuildMI(*MBB, IP, X86::MOV16rr, 1, X86::AX).addReg(DestReg);
+    BuildMI(*MBB, IP, X86::MOV8rr, 1, RealDestReg).addReg(X86::AL);
+    break;
+  case cLong:
+    // Move the upper half of the value as well.
+    BuildMI(*MBB, IP, Opcode, 2,DestReg+1).addReg(TrueReg+1).addReg(FalseReg+1);
+    break;
+  }
+}
 
 
 
index a2eb1a86a2d1821659b35389a6f6c5b433af5e24..6ffddd1bd7392614f6dbf054e090f062a98f2390 100644 (file)
@@ -174,6 +174,8 @@ namespace {
     unsigned EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
                             MachineBasicBlock *MBB,
                             MachineBasicBlock::iterator MBBI);
+    void visitSelectInst(SelectInst &SI);
+    
     
     // Memory Instructions
     void visitLoadInst(LoadInst &I);
@@ -261,6 +263,12 @@ namespace {
                             Value *Op, Value *ShiftAmount, bool isLeftShift,
                             const Type *ResultTy, unsigned DestReg);
       
+    /// emitSelectOperation - Common code shared between visitSelectInst and the
+    /// constant expression support.
+    void emitSelectOperation(MachineBasicBlock *MBB,
+                             MachineBasicBlock::iterator IP,
+                             Value *Cond, Value *TrueVal, Value *FalseVal,
+                             unsigned DestReg);
 
     /// copyConstantToRegister - Output the instructions required to put the
     /// specified constant into the specified register.
@@ -426,6 +434,11 @@ void ISel::copyConstantToRegister(MachineBasicBlock *MBB,
                          CE->getOpcode() == Instruction::Shl, CE->getType(), R);
       return;
 
+    case Instruction::Select:
+      emitSelectOperation(MBB, IP, CE->getOperand(0), CE->getOperand(1),
+                          CE->getOperand(2), R);
+      return;
+
     default:
       std::cerr << "Offending expr: " << C << "\n";
       assert(0 && "Constant expression not yet handled!\n");
@@ -890,7 +903,6 @@ unsigned ISel::EmitComparison(unsigned OpNum, Value *Op0, Value *Op1,
   return OpNum;
 }
 
-
 /// SetCC instructions - Here we just emit boilerplate code to set a byte-sized
 /// register, then move it to wherever the result should be. 
 ///
@@ -927,6 +939,89 @@ void ISel::emitSetCCOperation(MachineBasicBlock *MBB,
   }
 }
 
+void ISel::visitSelectInst(SelectInst &SI) {
+  unsigned DestReg = getReg(SI);
+  MachineBasicBlock::iterator MII = BB->end();
+  emitSelectOperation(BB, MII, SI.getCondition(), SI.getTrueValue(),
+                      SI.getFalseValue(), DestReg);
+}
+/// emitSelect - Common code shared between visitSelectInst and the constant
+/// expression support.
+void ISel::emitSelectOperation(MachineBasicBlock *MBB,
+                               MachineBasicBlock::iterator IP,
+                               Value *Cond, Value *TrueVal, Value *FalseVal,
+                               unsigned DestReg) {
+  unsigned SelectClass = getClassB(TrueVal->getType());
+  
+  // We don't support 8-bit conditional moves.  If we have incoming constants,
+  // transform them into 16-bit constants to avoid having a run-time conversion.
+  if (SelectClass == cByte) {
+    if (Constant *T = dyn_cast<Constant>(TrueVal))
+      TrueVal = ConstantExpr::getCast(T, Type::ShortTy);
+    if (Constant *F = dyn_cast<Constant>(FalseVal))
+      FalseVal = ConstantExpr::getCast(F, Type::ShortTy);
+  }
+
+  // Get the value being branched on, and use it to set the condition codes.
+  unsigned CondReg = getReg(Cond, MBB, IP);
+  BuildMI(*MBB, IP, X86::CMP8ri, 2).addReg(CondReg).addImm(0);
+
+  unsigned TrueReg  = getReg(TrueVal, MBB, IP);
+  unsigned FalseReg = getReg(FalseVal, MBB, IP);
+  unsigned RealDestReg = DestReg;
+  unsigned Opcode;
+
+  switch (SelectClass) {
+  case cFP:
+    assert(0 && "We don't support floating point selects yet, they should "
+           "have been lowered!");
+  case cByte:
+  case cShort:
+    Opcode = X86::CMOVE16rr;
+    break;
+  case cInt:
+  case cLong:
+    Opcode = X86::CMOVE32rr;
+    break;
+  }
+
+  // Annoyingly enough, X86 doesn't HAVE 8-bit conditional moves.  Because of
+  // this, we have to promote the incoming values to 16 bits, perform a 16-bit
+  // cmove, then truncate the result.
+  if (SelectClass == cByte) {
+    DestReg = makeAnotherReg(Type::ShortTy);
+    if (getClassB(TrueVal->getType()) == cByte) {
+      // Promote the true value, by storing it into AL, and reading from AX.
+      BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::AL).addReg(TrueReg);
+      BuildMI(*MBB, IP, X86::MOV8ri, 1, X86::AH).addImm(0);
+      TrueReg = makeAnotherReg(Type::ShortTy);
+      BuildMI(*MBB, IP, X86::MOV16rr, 1, TrueReg).addReg(X86::AX);
+    }
+    if (getClassB(FalseVal->getType()) == cByte) {
+      // Promote the true value, by storing it into CL, and reading from CX.
+      BuildMI(*MBB, IP, X86::MOV8rr, 1, X86::CL).addReg(FalseReg);
+      BuildMI(*MBB, IP, X86::MOV8ri, 1, X86::CH).addImm(0);
+      FalseReg = makeAnotherReg(Type::ShortTy);
+      BuildMI(*MBB, IP, X86::MOV16rr, 1, FalseReg).addReg(X86::CX);
+    }
+  }
+
+  BuildMI(*MBB, IP, Opcode, 2, DestReg).addReg(TrueReg).addReg(FalseReg);
+
+  switch (SelectClass) {
+  case cByte:
+    // We did the computation with 16-bit registers.  Truncate back to our
+    // result by copying into AX then copying out AL.
+    BuildMI(*MBB, IP, X86::MOV16rr, 1, X86::AX).addReg(DestReg);
+    BuildMI(*MBB, IP, X86::MOV8rr, 1, RealDestReg).addReg(X86::AL);
+    break;
+  case cLong:
+    // Move the upper half of the value as well.
+    BuildMI(*MBB, IP, Opcode, 2,DestReg+1).addReg(TrueReg+1).addReg(FalseReg+1);
+    break;
+  }
+}
 
 
 
index 56e9eab263d2d689f8cd984d2b414819c6ae5617..dcd265ef80f865417905c43cea964c2ed681ac6e 100644 (file)
@@ -68,7 +68,7 @@ bool X86TargetMachine::addPassesToEmitAssembly(PassManager &PM,
   PM.add(createLowerSwitchPass());
 
   // FIXME: Add support for the select instruction natively.
-  PM.add(createLowerSelectPass());
+  PM.add(createLowerSelectPass(true));
 
   if (NoPatternISel)
     PM.add(createX86SimpleInstructionSelector(*this));
@@ -128,7 +128,7 @@ void X86JITInfo::addPassesToJITCompile(FunctionPassManager &PM) {
   PM.add(createLowerSwitchPass());
 
   // FIXME: Add support for the select instruction natively.
-  PM.add(createLowerSelectPass());
+  PM.add(createLowerSelectPass(true));
 
   if (NoPatternISel)
     PM.add(createX86SimpleInstructionSelector(TM));