[llvm-commits] CVS: llvm/lib/Transforms/Scalar/InstructionCombining.cpp

Chris Lattner lattner at cs.uiuc.edu
Fri May 12 19:06:16 PDT 2006



Changes in directory llvm/lib/Transforms/Scalar:

InstructionCombining.cpp updated: 1.479 -> 1.480
---
Log message:

Implement simple promotion for cast elimination in instcombine.  This is
currently very limited, but can be extended in the future.  For example,
we now compile:

uint %test30(uint %c1) {
        %c2 = cast uint %c1 to ubyte
        %c3 = xor ubyte %c2, 1     
        %c4 = cast ubyte %c3 to uint
        ret uint %c4
}

to:

_xor:
        movzbl 4(%esp), %eax
        xorl $1, %eax
        ret

instead of:

_xor:
        movb $1, %al
        xorb 4(%esp), %al
        movzbl %al, %eax
        ret

More impressively, we now compile:

struct B { unsigned bit : 1; };
void xor(struct B *b) { b->bit = b->bit ^ 1; }

To (X86/PPC):

_xor:
        movl 4(%esp), %eax
        xorl $-2147483648, (%eax)
        ret
_xor:
        lwz r2, 0(r3)
        xoris r2, r2, 32768
        stw r2, 0(r3)
        blr

instead of (X86/PPC):

_xor:
        movl 4(%esp), %eax
        movl (%eax), %ecx
        movl %ecx, %edx
        shrl $31, %edx
        # TRUNCATE movb %dl, %dl
        xorb $1, %dl
        movzbl %dl, %edx
        andl $2147483647, %ecx
        shll $31, %edx
        orl %ecx, %edx
        movl %edx, (%eax)
        ret

_xor:
        lwz r2, 0(r3)
        srwi r4, r2, 31
        xori r4, r4, 1
        rlwimi r2, r4, 31, 0, 0
        stw r2, 0(r3)
        blr

This implements InstCombine/cast.ll:test30.


---
Diffs of the changes:  (+119 -0)

 InstructionCombining.cpp |  119 +++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 119 insertions(+)


Index: llvm/lib/Transforms/Scalar/InstructionCombining.cpp
diff -u llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.479 llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.480
--- llvm/lib/Transforms/Scalar/InstructionCombining.cpp:1.479	Thu May 11 12:11:52 2006
+++ llvm/lib/Transforms/Scalar/InstructionCombining.cpp	Fri May 12 21:06:03 2006
@@ -256,6 +256,8 @@
     Instruction *InsertRangeTest(Value *V, Constant *Lo, Constant *Hi,
                                  bool Inside, Instruction &IB);
     Instruction *PromoteCastOfAllocation(CastInst &CI, AllocationInst &AI);
+    
+    Value *EvaluateInDifferentType(Value *V, const Type *Ty);
   };
 
   RegisterOpt<InstCombiner> X("instcombine", "Combine redundant instructions");
@@ -4779,6 +4781,71 @@
   return ReplaceInstUsesWith(CI, New);
 }
 
+/// CanEvaluateInDifferentType - Return true if we can take the specified value
+/// and return it without inserting any new casts.  This is used by code that
+/// tries to decide whether promoting or shrinking integer operations to wider
+/// or smaller types will allow us to eliminate a truncate or extend.
+static bool CanEvaluateInDifferentType(Value *V, const Type *Ty,
+                                       int &NumCastsRemoved) {
+  if (isa<Constant>(V)) return true;
+  
+  Instruction *I = dyn_cast<Instruction>(V);
+  if (!I || !I->hasOneUse()) return false;
+  
+  switch (I->getOpcode()) {
+  case Instruction::And:
+  case Instruction::Or:
+  case Instruction::Xor:
+    // These operators can all arbitrarily be extended or truncated.
+    return CanEvaluateInDifferentType(I->getOperand(0), Ty, NumCastsRemoved) &&
+           CanEvaluateInDifferentType(I->getOperand(1), Ty, NumCastsRemoved);
+  case Instruction::Cast:
+    // If this is a cast from the destination type, we can trivially eliminate
+    // it, and this will remove a cast overall.
+    if (I->getOperand(0)->getType() == Ty) {
+      ++NumCastsRemoved;
+      return true;
+    }
+    // TODO: Can handle more cases here.
+    break;
+  }
+  
+  return false;
+}
+
+/// EvaluateInDifferentType - Given an expression that 
+/// CanEvaluateInDifferentType returns true for, actually insert the code to
+/// evaluate the expression.
+Value *InstCombiner::EvaluateInDifferentType(Value *V, const Type *Ty) {
+  if (Constant *C = dyn_cast<Constant>(V))
+    return ConstantExpr::getCast(C, Ty);
+
+  // Otherwise, it must be an instruction.
+  Instruction *I = cast<Instruction>(V);
+  Instruction *Res;
+  switch (I->getOpcode()) {
+  case Instruction::And:
+  case Instruction::Or:
+  case Instruction::Xor: {
+    Value *LHS = EvaluateInDifferentType(I->getOperand(0), Ty);
+    Value *RHS = EvaluateInDifferentType(I->getOperand(1), Ty);
+    Res = BinaryOperator::create((Instruction::BinaryOps)I->getOpcode(),
+                                 LHS, RHS, I->getName());
+    break;
+  }
+  case Instruction::Cast:
+    // If this is a cast from the destination type, return the input.
+    if (I->getOperand(0)->getType() == Ty)
+      return I->getOperand(0);
+    
+    // TODO: Can handle more cases here.
+    assert(0 && "Unreachable!");
+    break;
+  }
+  
+  return InsertNewInstBefore(Res, *I);
+}
+
 
 // CastInst simplification
 //
@@ -4906,6 +4973,58 @@
   if (Instruction *SrcI = dyn_cast<Instruction>(Src))
     if (SrcI->hasOneUse() && Src->getType()->isIntegral() &&
         CI.getType()->isInteger()) {  // Don't mess with casts to bool here
+      
+      int NumCastsRemoved = 0;
+      if (CanEvaluateInDifferentType(SrcI, CI.getType(), NumCastsRemoved)) {
+        // If this cast is a truncate, evaluting in a different type always
+        // eliminates the cast, so it is always a win.  If this is a noop-cast
+        // this just removes a noop cast which isn't pointful, but simplifies
+        // the code.  If this is a zero-extension, we need to do an AND to
+        // maintain the clear top-part of the computation, so we require that
+        // the input have eliminated at least one cast.  If this is a sign
+        // extension, we insert two new casts (to do the extension) so we
+        // require that two casts have been eliminated.
+        bool DoXForm;
+        switch (getCastType(Src->getType(), CI.getType())) {
+        default: assert(0 && "Unknown cast type!");
+        case Noop:
+        case Truncate:
+          DoXForm = true;
+          break;
+        case Zeroext:
+          DoXForm = NumCastsRemoved >= 1;
+          break;
+        case Signext:
+          DoXForm = NumCastsRemoved >= 2;
+          break;
+        }
+        
+        if (DoXForm) {
+          Value *Res = EvaluateInDifferentType(SrcI, CI.getType());
+          assert(Res->getType() == CI.getType());
+          switch (getCastType(Src->getType(), CI.getType())) {
+          default: assert(0 && "Unknown cast type!");
+          case Noop:
+          case Truncate:
+            // Just replace this cast with the result.
+            return ReplaceInstUsesWith(CI, Res);
+          case Zeroext: {
+            // We need to emit an AND to clear the high bits.
+            unsigned SrcBitSize = Src->getType()->getPrimitiveSizeInBits();
+            unsigned DestBitSize = CI.getType()->getPrimitiveSizeInBits();
+            assert(SrcBitSize < DestBitSize && "Not a zext?");
+            Constant *C = ConstantUInt::get(Type::ULongTy, (1 << SrcBitSize)-1);
+            C = ConstantExpr::getCast(C, CI.getType());
+            return BinaryOperator::createAnd(Res, C);
+          }
+          case Signext:
+            // We need to emit a cast to truncate, then a cast to sext.
+            return new CastInst(InsertCastBefore(Res, Src->getType(), CI),
+                                CI.getType());
+          }
+        }
+      }
+      
       const Type *DestTy = CI.getType();
       unsigned SrcBitSize = Src->getType()->getPrimitiveSizeInBits();
       unsigned DestBitSize = DestTy->getPrimitiveSizeInBits();






More information about the llvm-commits mailing list