Hi Reid, thanks for replying.

> > > Please use APInt's to do the subtraction, instead of constant  
> > > folding.  Reid should be able to help you with this.
> > 
> > I don't understand why.  If APInt's are much more efficient, then
> > shouldn't ConstantExpr:getSub be improved to detect this case and
> > directly use APInts itself? 
> 
> Currently, ConstantInt is implemented in terms of APInt. So, if you
> subtract two ConstantInt (via ConstantExpr), you are in essence just
> doing an APInt subtraction. However, having just looked at the constant
> folding code again, here's what happens:
> 
>      1. Call to ConstantExpr::get which calls ConstantExpr::getTy which
>         calls ConstantFoldBinaryInstruction.
>      2. 5 if statements and a switch in ConstantFoldBinaryInstruction
>      3. Extraction of APInt values from the ConstantInt operands to the
>         ConstantExpr object.
>      4. APInt subtraction.
>      5. Construction of a new ConstantInt which involves at least (a)
>         construction of an IntegerMapKeyType and (b) std::map lookup to
>         see if the value already exists; and, if the value doesn't
>         exist, will also involve (c) instantiation of an integer value
>         representation object and (d) insertion into two maps (one
>         forward, one inverse)
> 
> I think this is Chris' point. You could replace all of that with just
> "APInt subtraction". #5 can be really expensive because of the map
> traversals and insertions, especially in programs with lots of constant
> values.

In most of the switch code #5 cannot be avoided, since the final result
needs to be a ConstantInt.  However Range only needs to be turned into
a ConstantInt if the range is wide, so indeed one instance of #5 can be
avoided in the common case.

> > > +    if (Range->getZExtValue() < 2*HOST_BITS_PER_WIDE_INT) {
> > > 
> > > This is bad because it means llvm-gcc will produce different code  
> > > based on thevalue of HOST_BITS...  Please just say " < 64" or something.
> 
> Since you are working with numbers of bits here and not with values
> requiring that number of bits, the range of values possible will always
> fit in a uint32_t. Is it possible just to use that instead of a
> ConstantInt?  uint32_t Range = X - Y is way cheaper than any of the
> foregoing :)

Range is the case range, which can be arbitrarily big, so I'm afraid not.

> FYI: I'm contemplating making llvm-gcc represent CONSTANT_INT nodes with
> APInt so that it can handle integer constants of any bit width. This is
> a requirement for the work I'm doing for AutoESL.

This would make it hard to merge with mainline.

I am testing the following patch.  While I was there, I made it agnostic
as to the signedness of the switch expression and cases (in Ada they can
be unsigned).

Ciao,

Duncan.
Index: gcc.llvm.master/gcc/llvm-convert.cpp
===================================================================
--- gcc.llvm.master.orig/gcc/llvm-convert.cpp	2007-03-14 18:49:06.000000000 +0100
+++ gcc.llvm.master/gcc/llvm-convert.cpp	2007-03-14 19:03:58.000000000 +0100
@@ -1666,6 +1666,7 @@
   
   // Emit the condition.
   Value *SwitchExp = Emit(SWITCH_COND(exp), 0);
+  bool ExpIsSigned = !TYPE_UNSIGNED(TREE_TYPE(SWITCH_COND(exp)));
   
   // Emit the switch instruction.
   SwitchInst *SI = new SwitchInst(SwitchExp, CurBB,
@@ -1673,39 +1674,65 @@
   EmitBlock(new BasicBlock(""));
   SI->setSuccessor(0, CurBB);   // Default location starts out as fall-through
 
-  // Output the body of the switch.
-  if (SWITCH_BODY(exp))
-    Emit(SWITCH_BODY(exp), 0);
-  
+  assert(!SWITCH_BODY(exp) && "not a gimple switch?");
+
+  BasicBlock *DefaultDest = NULL;
   for (unsigned i = 0, e = TREE_VEC_LENGTH(Cases); i != e; ++i) {
     BasicBlock *Dest = getLabelDeclBlock(CASE_LABEL(TREE_VEC_ELT(Cases, i)));
-    if (CASE_LOW(TREE_VEC_ELT(Cases, i)) == 0) {
-      SI->setSuccessor(0, Dest);  // Change the default destination.
+
+    tree low = CASE_LOW(TREE_VEC_ELT(Cases, i));
+    if (!low) {
+      DefaultDest = Dest;
       continue;
     }
 
     // Convert the integer to the right type.
-    Value *Val = Emit(CASE_LOW(TREE_VEC_ELT(Cases, i)), 0);
-    Val = CastToSIntType(Val, SwitchExp->getType());
-    ConstantInt *ValC = cast<ConstantInt>(Val);
-    if (CASE_HIGH(TREE_VEC_ELT(Cases, i)) == 0) {
-      SI->addCase(ValC, Dest); // Single destination.
+    Value *Val = Emit(low, 0);
+    Val = CastToAnyType(Val, !TYPE_UNSIGNED(TREE_TYPE(low)),
+                        SwitchExp->getType(), ExpIsSigned);
+    ConstantInt *LowC = cast<ConstantInt>(Val);
+
+    tree high = CASE_HIGH(TREE_VEC_ELT(Cases, i));
+    if (!high) {
+      SI->addCase(LowC, Dest); // Single destination.
       continue;
     }
 
-    // Otherwise, we have a range, like 'case 1 ... 17'.  Add all of the
-    // necessary successors to the switch.
-    Val = Emit(CASE_HIGH(TREE_VEC_ELT(Cases, i)), 0);
-    // Make sure the case value is the same type as the switch expression (int)
-    Val = CastToSIntType(Val, SwitchExp->getType());
-    ConstantInt *HiC = cast<ConstantInt>(Val);
-    Constant *OneC = ConstantInt::get(ValC->getType(), 1);
-    while (1) {
-      SI->addCase(ValC, Dest);
-      if (ValC == HiC) break;  // Emitted the last one.
-      ValC = cast<ConstantInt>(ConstantExpr::getAdd(ValC, OneC));
+    // Otherwise, we have a range, like 'case 1 ... 17'.
+    Val = Emit(high, 0);
+    // Make sure the case value is the same type as the switch expression
+    Val = CastToAnyType(Val, !TYPE_UNSIGNED(TREE_TYPE(high)),
+                        SwitchExp->getType(), ExpIsSigned);
+    ConstantInt *HighC = cast<ConstantInt>(Val);
+
+    APInt Range = HighC->getValue() - LowC->getValue();
+    if (Range.ult(APInt(Range.getBitWidth(), 64))) {
+      // Add all of the necessary successors to the switch.
+      APInt CurrentValue = LowC->getValue();
+      while (1) {
+        SI->addCase(LowC, Dest);
+        if (LowC == HighC) break;  // Emitted the last one.
+        CurrentValue++;
+        LowC = ConstantInt::get(CurrentValue);
+      }
+    } else {
+      // The range is too big to add to the switch - emit an "if".
+      Value *Diff = BinaryOperator::create(Instruction::Sub, SwitchExp, LowC,
+                                           "tmp", CurBB);
+      Value *Cond = new ICmpInst(ICmpInst::ICMP_ULE, Diff,
+                                 ConstantInt::get(Range), "tmp", CurBB);
+      BasicBlock *False_Block = new BasicBlock("case_false");
+      new BranchInst(Dest, False_Block, Cond, CurBB);
+      EmitBlock(False_Block);
     }
   }
+
+  if (DefaultDest)
+    if (SI->getSuccessor(0) == CurBB)
+      SI->setSuccessor(0, DefaultDest);
+    else
+      new BranchInst(DefaultDest, CurBB);
+
   return 0;
 }
 
_______________________________________________
llvm-commits mailing list
llvm-commits@cs.uiuc.edu
http://lists.cs.uiuc.edu/mailman/listinfo/llvm-commits

Reply via email to