Changeset 1297:8e8552601ecd
- Timestamp:
- 05/03/09 12:01:45
(3 years ago)
- Author:
- Frits van Bommel <fvbommel wxs.nl>
- branch:
- default
- Message:
Stack promotion for _d_newarrayvT. Array literals, concatenations (a ~ b) and
such are eligible for stack-allocation now.
-
Files:
-
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
| r1295 |
r1297 |
|
| 30 | 30 | #include "llvm/Support/IRBuilder.h" |
|---|
| 31 | 31 | #include "llvm/Analysis/CaptureTracking.h" |
|---|
| | 32 | #include "llvm/Analysis/ValueTracking.h" |
|---|
| 32 | 33 | #include "llvm/Analysis/LoopInfo.h" |
|---|
| 33 | 34 | #include "llvm/Target/TargetData.h" |
|---|
| … | … | |
| 38 | 39 | using namespace llvm; |
|---|
| 39 | 40 | |
|---|
| 40 | | STATISTIC(NumGcToStack, "Number of GC calls promoted to stack allocations"); |
|---|
| | 41 | STATISTIC(NumGcToStack, "Number of calls promoted to constant-size allocas"); |
|---|
| | 42 | STATISTIC(NumToDynSize, "Number of calls promoted to dynamically-sized allocas"); |
|---|
| 41 | 43 | STATISTIC(NumDeleted, "Number of GC calls deleted because the return value was unused"); |
|---|
| 42 | 44 | |
|---|
| … | … | |
| 48 | 50 | struct FunctionInfo { |
|---|
| 49 | 51 | unsigned TypeInfoArgNr; |
|---|
| | 52 | int ArrSizeArgNr; |
|---|
| 50 | 53 | bool SafeToDelete; |
|---|
| 51 | 54 | |
|---|
| 52 | | FunctionInfo(unsigned typeInfoArgNr, bool safeToDelete) |
|---|
| 53 | | : TypeInfoArgNr(typeInfoArgNr), SafeToDelete(safeToDelete) {} |
|---|
| 54 | | |
|---|
| 55 | | Value* getArraySize(CallSite CS) { |
|---|
| 56 | | return 0; |
|---|
| 57 | | } |
|---|
| | 55 | FunctionInfo(unsigned typeInfoArgNr, int arrSizeArgNr, bool safeToDelete) |
|---|
| | 56 | : TypeInfoArgNr(typeInfoArgNr), ArrSizeArgNr(arrSizeArgNr), |
|---|
| | 57 | SafeToDelete(safeToDelete) {} |
|---|
| 58 | 58 | }; |
|---|
| 59 | 59 | |
|---|
| … | … | |
| 93 | 93 | bool GarbageCollect2Stack::doInitialization(Module &M) { |
|---|
| 94 | 94 | this->M = &M; |
|---|
| 95 | | KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, true); |
|---|
| | 95 | KnownFunctions["_d_allocmemoryT"] = new FunctionInfo(0, -1, true); |
|---|
| | 96 | KnownFunctions["_d_newarrayvT"] = new FunctionInfo(0, 1, true); |
|---|
| 96 | 97 | } |
|---|
| 97 | 98 | |
|---|
| … | … | |
| 101 | 102 | DEBUG(DOUT << "Running -dgc2stack on function " << F.getName() << '\n'); |
|---|
| 102 | 103 | |
|---|
| 103 | | const TargetData &TD = getAnalysis<TargetData>(); |
|---|
| | 104 | TargetData &TD = getAnalysis<TargetData>(); |
|---|
| 104 | 105 | const LoopInfo &LI = getAnalysis<LoopInfo>(); |
|---|
| 105 | 106 | |
|---|
| … | … | |
| 162 | 163 | } |
|---|
| 163 | 164 | |
|---|
| | 165 | Value* arrSize = 0; |
|---|
| | 166 | if (info->ArrSizeArgNr != -1) { |
|---|
| | 167 | arrSize = CS.getArgument(info->ArrSizeArgNr); |
|---|
| | 168 | const IntegerType* SizeType = |
|---|
| | 169 | dyn_cast<IntegerType>(arrSize->getType()); |
|---|
| | 170 | if (!SizeType) |
|---|
| | 171 | continue; |
|---|
| | 172 | unsigned bits = SizeType->getBitWidth(); |
|---|
| | 173 | if (bits > 32) { |
|---|
| | 174 | // The array size of an alloca must be an i32, so make sure |
|---|
| | 175 | // the conversion is safe. |
|---|
| | 176 | APInt Mask = APInt::getHighBitsSet(bits, bits - 32); |
|---|
| | 177 | APInt KnownZero(bits, 0), KnownOne(bits, 0); |
|---|
| | 178 | ComputeMaskedBits(arrSize, Mask, KnownZero, KnownOne, &TD); |
|---|
| | 179 | if ((KnownZero & Mask) != Mask) |
|---|
| | 180 | continue; |
|---|
| | 181 | } |
|---|
| | 182 | // Extract the element type from the array type. |
|---|
| | 183 | const StructType* ArrTy = dyn_cast<StructType>(Ty); |
|---|
| | 184 | assert(ArrTy && "Dynamic array type not a struct?"); |
|---|
| | 185 | assert(isa<IntegerType>(ArrTy->getElementType(0))); |
|---|
| | 186 | const PointerType* PtrTy = |
|---|
| | 187 | cast<PointerType>(ArrTy->getElementType(1)); |
|---|
| | 188 | Ty = PtrTy->getElementType(); |
|---|
| | 189 | } |
|---|
| | 190 | |
|---|
| 164 | 191 | // Let's alloca this! |
|---|
| 165 | 192 | Changed = true; |
|---|
| 166 | | NumGcToStack++; |
|---|
| 167 | | |
|---|
| 168 | | Value* arrSize = info->getArraySize(CS); |
|---|
| 169 | | Value* newVal = AllocaBuilder.CreateAlloca(Ty, arrSize, ".nongc_mem"); |
|---|
| 170 | | |
|---|
| | 193 | |
|---|
| | 194 | IRBuilder<> Builder(BB, I); |
|---|
| | 195 | |
|---|
| | 196 | // If the allocation is of constant size it's best to put it in the |
|---|
| | 197 | // entry block, so do so if we're not already there. |
|---|
| | 198 | // For dynamically-sized allocations it's best to avoid the overhead |
|---|
| | 199 | // of allocating them if possible, so leave those where they are. |
|---|
| | 200 | // While we're at it, update statistics too. |
|---|
| | 201 | if (!arrSize || isa<Constant>(arrSize)) { |
|---|
| | 202 | if (&*BB != &Entry) |
|---|
| | 203 | Builder = AllocaBuilder; |
|---|
| | 204 | NumGcToStack++; |
|---|
| | 205 | } else { |
|---|
| | 206 | NumToDynSize++; |
|---|
| | 207 | } |
|---|
| | 208 | |
|---|
| | 209 | // Convert array size to 32 bits if necessary |
|---|
| | 210 | if (arrSize) |
|---|
| | 211 | arrSize = Builder.CreateIntCast(arrSize, Type::Int32Ty, false); |
|---|
| | 212 | |
|---|
| | 213 | Value* newVal = Builder.CreateAlloca(Ty, arrSize, ".nongc_mem"); |
|---|
| | 214 | |
|---|
| | 215 | // Make sure the type is the same as it was before, and replace all |
|---|
| | 216 | // uses of the runtime call with the alloca. |
|---|
| 171 | 217 | if (newVal->getType() != Inst->getType()) |
|---|
| 172 | | newVal = AllocaBuilder.CreateBitCast(newVal, Inst->getType()); |
|---|
| 173 | | |
|---|
| | 218 | newVal = Builder.CreateBitCast(newVal, Inst->getType()); |
|---|
| 174 | 219 | Inst->replaceAllUsesWith(newVal); |
|---|
| 175 | 220 | |
|---|
| | 221 | // If this was an invoke instruction, update the control flow. |
|---|
| 176 | 222 | if (InvokeInst* Invoke = dyn_cast<InvokeInst>(Inst)) { |
|---|
| | 223 | // Notify the exception landing pad block that we won't be |
|---|
| | 224 | // going there anymore. |
|---|
| 177 | 225 | Invoke->getUnwindDest()->removePredecessor(Invoke->getParent()); |
|---|
| 178 | 226 | // Create a branch to the "normal" destination. |
|---|
| 179 | 227 | BranchInst::Create(Invoke->getNormalDest(), Invoke->getParent()); |
|---|
| 180 | 228 | } |
|---|
| | 229 | |
|---|
| | 230 | // Finally, remove the runtime call. |
|---|
| 181 | 231 | Inst->eraseFromParent(); |
|---|
| 182 | 232 | } |
|---|
| 183 | 233 | } |
|---|
| | 234 | |
|---|
| 184 | 235 | return Changed; |
|---|
| 185 | 236 | } |
|---|