mirror of
				https://github.com/c64scene-ar/llvm-6502.git
				synced 2025-10-30 16:17:05 +00:00 
			
		
		
		
	GVN: Enable value forwarding for calloc
Enable value forwarding for loads from `calloc()` without an intervening
store.
This change extends GVN to handle the following case:
    %1 = tail call noalias i8* @calloc(i64 1, i64 4)
    %2 = bitcast i8* %1 to i32*
    ; This load is trivially constant zero
    %3 = load i32* %2, align 4
This is analogous to the handling for `malloc()` in the same places.
`malloc()` returns `undef`; `calloc()` returns a zero value.  Note that
it is correct to return zero even for out of bounds GEPs since the
result of such a GEP would be undefined.
Patch by Philip Reames!
git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@210828 91177308-0d34-0410-b5e6-96231b3b80d8
			
			
This commit is contained in:
		| @@ -1464,6 +1464,13 @@ void GVN::AnalyzeLoadAvailability(LoadInst *LI, LoadDepVect &Deps, | |||||||
|       continue; |       continue; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|  |     // Loading from calloc (which zero initializes memory) -> zero | ||||||
|  |     if (isCallocLikeFn(DepInst, TLI)) { | ||||||
|  |       ValuesPerBlock.push_back(AvailableValueInBlock::get( | ||||||
|  |           DepBB, Constant::getNullValue(LI->getType()))); | ||||||
|  |       continue; | ||||||
|  |     } | ||||||
|  |  | ||||||
|     if (StoreInst *S = dyn_cast<StoreInst>(DepInst)) { |     if (StoreInst *S = dyn_cast<StoreInst>(DepInst)) { | ||||||
|       // Reject loads and stores that are to the same address but are of |       // Reject loads and stores that are to the same address but are of | ||||||
|       // different types if we have to. |       // different types if we have to. | ||||||
| @@ -1988,6 +1995,15 @@ bool GVN::processLoad(LoadInst *L) { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  |  | ||||||
|  |   // If this load follows a calloc (which zero initializes memory), | ||||||
|  |   // then the loaded value is zero | ||||||
|  |   if (isCallocLikeFn(DepInst, TLI)) { | ||||||
|  |     L->replaceAllUsesWith(Constant::getNullValue(L->getType())); | ||||||
|  |     markInstructionForDeletion(L); | ||||||
|  |     ++NumGVNLoad; | ||||||
|  |     return true; | ||||||
|  |   } | ||||||
|  |  | ||||||
|   return false; |   return false; | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
							
								
								
									
										25
									
								
								test/Transforms/GVN/calloc-load-removal.ll
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								test/Transforms/GVN/calloc-load-removal.ll
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | |||||||
|  | ; RUN: opt -S -basicaa -gvn < %s | FileCheck %s | ||||||
|  | ; RUN: opt -S -basicaa -gvn -disable-simplify-libcalls < %s | FileCheck %s -check-prefix=CHECK_NO_LIBCALLS | ||||||
|  | ; Check that loads from calloc are recognized as being zero. | ||||||
|  |  | ||||||
|  | target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128" | ||||||
|  |  | ||||||
|  | ; Function Attrs: nounwind uwtable | ||||||
|  | define i32 @test1() { | ||||||
|  |   %1 = tail call noalias i8* @calloc(i64 1, i64 4) | ||||||
|  |   %2 = bitcast i8* %1 to i32* | ||||||
|  |   ; This load is trivially constant zero | ||||||
|  |   %3 = load i32* %2, align 4 | ||||||
|  |   ret i32 %3 | ||||||
|  |  | ||||||
|  | ; CHECK-LABEL: @test1( | ||||||
|  | ; CHECK-NOT: %3 = load i32* %2, align 4 | ||||||
|  | ; CHECK: ret i32 0 | ||||||
|  |  | ||||||
|  | ; CHECK_NO_LIBCALLS-LABEL: @test1( | ||||||
|  | ; CHECK_NO_LIBCALLS: load | ||||||
|  | ; CHECK_NO_LIBCALLS: ret i32 % | ||||||
|  |  | ||||||
|  | } | ||||||
|  |  | ||||||
|  | declare noalias i8* @calloc(i64, i64) | ||||||
		Reference in New Issue
	
	Block a user