llvm.org GIT mirror llvm / ea4b6df
Rework constant expr and array handling for objectsize instcombining. Fix bugs where we would compute out of bounds as in bounds, and where we couldn't know that the linker could override the size of an array. Add a few new testcases, change existing testcase to use a private global array instead of extern. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@95283 91177308-0d34-0410-b5e6-96231b3b80d8 Eric Christopher 10 years ago
2 changed file(s) with 66 addition(s) and 30 deletion(s). Raw diff Collapse all Expand all
634634 case Intrinsic::objectsize: {
635635 const Type *ReturnTy = CI.getType();
636636 Value *Op1 = II->getOperand(1);
637
638 // If we're a constant expr then we just return the number of bytes
639 // left in whatever we're indexing. Since it's constant there's no
640 // need for maximum or minimum bytes.
637
638 // If we've got a GEP we're going to do some calculations
639 size_t GEPindex = 0;
640
641 // Strip any casts we see and continue processing.
642 Op1 = Op1->stripPointerCasts();
643
644 // Make sure we can reliably know the size.
645 if (GlobalVariable *GV = dyn_cast(Op1))
646 if (!GV->hasDefinitiveInitializer()) break;
647
641648 if (ConstantExpr *CE = dyn_cast(Op1)) {
642 // If this isn't a GEP give up.
643 if (CE->getOpcode() != Instruction::GetElementPtr) return 0;
644
645 const PointerType *ObjTy =
646 reinterpret_cast(CE->getOperand(0)->getType());
647
648 if (const ArrayType *AT = dyn_cast(ObjTy->getElementType())) {
649 // If this isn't a GEP give up.
650 if (CE->getOpcode() != Instruction::GetElementPtr) break;
651
652 // If this isn't guaranteed to be inbounds, give up.
653 bool OOB = false;
654 GEPOperator *GEPO = cast(Op1);
655 if (!GEPO->isInBounds()) OOB = true;
656
657 for (int i = GEPO->getNumIndices() - 1; i > 0; i--) {
658 if (Constant *C = dyn_cast(GEPO->getOperand(i)))
659 if (C->isNullValue())
660 continue;
661
662 OOB = true;
663 }
664
665 // If we're guaranteed to be out of bounds just return that there's
666 // no room left.
667 if (OOB) return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, 0));
668
669 // Tell the later calculation that we have an offset and what
670 // it is.
671 Op1 = CE->getOperand(0);
672 ConstantInt *Const =
673 cast(CE->getOperand(CE->getNumOperands() - 1));
674 GEPindex = Const->getZExtValue();
675 }
676
677 // This may be a pointer to an array. If we have an index from earlier
678 // use that too.
679 if (const PointerType *PT = dyn_cast(Op1->getType())) {
680 if (const ArrayType *AT = dyn_cast(PT->getElementType())) {
649681
650682 // Deal with multi-dimensional arrays
651683 const ArrayType *SAT = AT;
652684 while ((AT = dyn_cast(AT->getElementType())))
653685 SAT = AT;
654
655 size_t numElems = SAT->getNumElements();
656
657 // If numElems is 0, we don't know how large the array is so we can't
658 // make any determinations yet.
659 if (numElems == 0) break;
660686
661687 // We return the remaining bytes, so grab the size of an element
662 // in bytes.
663 size_t sizeofElem = SAT->getElementType()->getPrimitiveSizeInBits() / 8;
664
665 ConstantInt *Const =
666 cast(CE->getOperand(CE->getNumOperands() - 1));
667 size_t indx = Const->getZExtValue();
668 return ReplaceInstUsesWith(CI,
669 ConstantInt::get(ReturnTy,
670 ((numElems - indx) * sizeofElem)));
671 }
672 }
688 // in bytes and the number of elements.
689 if (!SAT->isSized() || !TD) break;
690
691 size_t sizeofElem = TD->getTypeAllocSize(SAT->getElementType());
692 size_t numElems = SAT->getNumElements();
693 size_t remSize = (numElems - GEPindex) * sizeofElem;
694 return ReplaceInstUsesWith(CI, ConstantInt::get(ReturnTy, remSize));
695 }
696 }
697
673698 // TODO: Add more types here.
699 // TODO: Check for type isSized() here as well.
674700 }
675701 }
676702
0 ; Test a pile of objectsize bounds checking.
1 ; RUN: opt < %s -instcombine -S | FileCheck %s
1 @a = common global [60 x i8] zeroinitializer, align 1 ; <[60 x i8]*>
2 ; We need target data to get the sizes of the arrays and structures.
3 target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"
4
5 @a = private global [60 x i8] zeroinitializer, align 1 ; <[60 x i8]*>
26 @.str = private constant [8 x i8] c"abcdefg\00" ; <[8 x i8]*>
37
48 define i32 @foo() nounwind {
2630 ret i8* %2;
2731 }
2832
33 define i32 @f() nounwind {
34 ; CHECK: @f
35 ; CHECK-NEXT: ret i32 0
36 %1 = call i32 @llvm.objectsize.i32(i8* getelementptr ([60 x i8]* @a, i32 1, i32 0), i1 false)
37 ret i32 %1
38 }
39
2940 @window = external global [0 x i8]
3041
3142 define i1 @baz() nounwind {
3647 ret i1 %2
3748 }
3849
39
4050 declare i32 @llvm.objectsize.i32(i8*, i1) nounwind readonly