Index: clang/test/CodeGen/aggregate-assign-call.c =================================================================== --- clang/test/CodeGen/aggregate-assign-call.c +++ clang/test/CodeGen/aggregate-assign-call.c @@ -60,7 +60,7 @@ // O1-LEGACY: %[[P:[^ ]+]] = bitcast %struct.S* %[[TMP1_ALLOCA]] to i8* // O1-LEGACY: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* %[[P]]) // O1-NEWPM: %[[TMP3:.*]] = bitcast %struct.S* %[[TMP2_ALLOCA]] to i8* - // O1-NEWPM: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %[[P]]) + // O1-NEWPM: call void @llvm.lifetime.end.p0i8({{[^,]*}}, i8* nonnull %{{[0-9]}}) // // O1-LEGACY: call void @foo_int(%struct.S* sret align 4 %[[TMP1_ALLOCA]], // O1-NEWPM: call void @foo_int(%struct.S* nonnull sret align 4 %[[TMP1_ALLOCA]], Index: clang/test/CodeGen/temporary-lifetime-exceptions.cpp =================================================================== --- clang/test/CodeGen/temporary-lifetime-exceptions.cpp +++ clang/test/CodeGen/temporary-lifetime-exceptions.cpp @@ -8,9 +8,10 @@ void Test1() { // CHECK-LABEL: @_Z5Test1v( - // CHECK: getelementptr + // CHECK: entry + // CHECK: bitcast // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP:[^ ]+]]) - // CHECK-NEXT: getelementptr + // CHECK-NEXT: bitcast // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[TMP1:[^ ]+]]) // Normal exit Index: clang/test/CodeGenCXX/auto-var-init.cpp =================================================================== --- clang/test/CodeGenCXX/auto-var-init.cpp +++ clang/test/CodeGenCXX/auto-var-init.cpp @@ -830,7 +830,7 @@ // PATTERN-LABEL: @test_paddedpackednested_uninit() // PATTERN-O0: call void @llvm.memcpy{{.*}} @__const.test_paddedpackednested_uninit.uninit // PATTERN-O1: getelementptr -// PATTERN-O1: call void @llvm.memset.p0i8.i64(i8* nonnull align 1 dereferenceable(10) %0, i8 [[I8]], i64 10, i1 false +// PATTERN-O1: call void @llvm.memset.p0i8.i64(i8* nonnull align 1 dereferenceable(10) %1, i8 [[I8]], i64 10, i1 false // ZERO-LABEL: @test_paddedpackednested_uninit() // ZERO: call void @llvm.memset{{.*}}, i8 0, @@ -1067,7 +1067,7 @@ // PATTERN-LABEL: @test_tailpad4_uninit() // PATTERN-O0: call void @llvm.memcpy{{.*}} @__const.test_tailpad4_uninit.uninit // PATTERN-O1: bitcast -// PATTERN-O1: call void @llvm.memset{{.*}}({{.*}}0, i8 [[I8]], i64 16 +// PATTERN-O1: call void @llvm.memset{{.*}}({{.*}}1, i8 [[I8]], i64 16 // ZERO-LABEL: @test_tailpad4_uninit() // ZERO: call void @llvm.memset{{.*}}, i8 0, Index: clang/test/CodeGenCXX/nrvo.cpp =================================================================== --- clang/test/CodeGenCXX/nrvo.cpp +++ clang/test/CodeGenCXX/nrvo.cpp @@ -56,7 +56,7 @@ return x; // CHECK: call {{.*}} @_ZN1XC1Ev - // CHECK-NEXT: {{.*}} getelementptr inbounds %class.X, %class.X* %y, i32 0, i32 0 + // CHECK-NEXT: {{.*}} bitcast %class.X* %y to i8* // CHECK-NEXT: call void @llvm.lifetime.start // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev // CHECK: call {{.*}} @_ZN1XC1ERKS_ @@ -180,7 +180,7 @@ X a __attribute__((aligned(8))); return a; // CHECK: [[A:%.*]] = alloca [[X:%.*]], align 8 - // CHECK-NEXT: [[PTR:%.*]] = getelementptr inbounds %class.X, %class.X* [[A]], i32 0, i32 0 + // CHECK-NEXT: [[PTR:%.*]] = bitcast %class.X* [[A]] to i8* // CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 1, i8* nonnull [[PTR]]) // CHECK-NEXT: call {{.*}} @_ZN1XC1Ev([[X]]* nonnull [[A]]) // CHECK-NEXT: call {{.*}} @_ZN1XC1ERKS_([[X]]* {{%.*}}, [[X]]* nonnull align {{[0-9]+}} dereferenceable({{[0-9]+}}) [[A]]) Index: llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp =================================================================== --- llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp +++ llvm/lib/Transforms/InstCombine/InstCombineCasts.cpp @@ -2489,6 +2489,40 @@ } Instruction *InstCombinerImpl::visitBitCast(BitCastInst &CI) { + auto isLifetimeMarker = [&](auto I){ + if (IntrinsicInst* II = dyn_cast(I)) + if (II->isLifetimeStartOrEnd()) + return true; + return false; + /// Is this a bette style? + /// return isa(I) && + // cast(I)->isLifetimeStartOrEnd(); + }; + + /// If all the users of BitCast is lifetime marker, + /// don't change it. + if (all_of(CI.users(), isLifetimeMarker)) + return nullptr; + + /// Clone CI for other User than lifetime marker to + /// enable possible optimization. + if (any_of(CI.users(), isLifetimeMarker)) + { + /// Here must be some user of CI is not lifetime marker + BitCastInst* NewBitCast = cast(CI.clone()); + NewBitCast->insertAfter(&CI); + SmallVector UsersNotLifetimeMarker; + for (User* U:CI.users()) + if (!isLifetimeMarker(U)) + UsersNotLifetimeMarker.push_back(U); + + for (User* U:UsersNotLifetimeMarker) + U->replaceUsesOfWith(&CI, NewBitCast); + + Worklist.add(NewBitCast); + return nullptr; + } + // If the operands are integer typed then apply the integer transforms, // otherwise just apply the common ones. Value *Src = CI.getOperand(0); Index: llvm/test/Transforms/InstCombine/bitcast-lifetime.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/InstCombine/bitcast-lifetime.ll @@ -0,0 +1,34 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s + +%char.array = type { [500 x i8] } +declare void @consume(%char.array*) +declare void @consume.i8.ptr(i8*) + +; CHECK-LABEL: @bitcast_to_lifetime_marker_i8_array( +; CHECK: %cast = bitcast %char.array* %a to i8* + +define void @bitcast_to_lifetime_marker_i8_array(){ + %a = alloca %char.array + %cast = bitcast %char.array* %a to i8* + call void @llvm.lifetime.start.p0i8(i64 500, i8* %cast) + call void @consume(%char.array* %a) + call void @llvm.lifetime.end.p0i8(i64 500, i8* %cast) + ret void +} + +; CHECK-LABEL: @bitcast_to_lifetime_marker_other_use( +; CHECK: %cast = bitcast %char.array* %a to i8* +; CHECK: %{{.*}} = getelementptr inbounds %char.array, %char.array* + +define void @bitcast_to_lifetime_marker_other_use(){ + %a = alloca %char.array + %cast = bitcast %char.array* %a to i8* + call void @llvm.lifetime.start.p0i8(i64 500, i8* %cast) + call void @consume(%char.array* %a) + call void @consume.i8.ptr(i8* %cast) + call void @llvm.lifetime.end.p0i8(i64 500, i8* %cast) + ret void +} + +declare void @llvm.lifetime.start.p0i8(i64, i8* nocapture) +declare void @llvm.lifetime.end.p0i8(i64, i8* nocapture) \ No newline at end of file Index: llvm/test/Transforms/MemCpyOpt/memcpy-to-memset-with-lifetimes.ll =================================================================== --- llvm/test/Transforms/MemCpyOpt/memcpy-to-memset-with-lifetimes.ll +++ llvm/test/Transforms/MemCpyOpt/memcpy-to-memset-with-lifetimes.ll @@ -28,13 +28,14 @@ ; CHECK-NEXT: entry-block: ; CHECK-NEXT: [[A:%.*]] = alloca [8 x i64], align 8 ; CHECK-NEXT: [[A_CAST:%.*]] = bitcast [8 x i64]* [[A]] to i8* +; CHECK-NEXT: [[A_CAST_COPY:%.*]] = bitcast ; CHECK-NEXT: call void @llvm.lifetime.start.p0i8(i64 64, i8* nonnull [[A_CAST]]) -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(64) [[A_CAST]], i8 0, i64 64, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(64) [[A_CAST_COPY]], i8 0, i64 64, i1 false) ; CHECK-NEXT: [[SRET_CAST:%.*]] = bitcast [8 x i64]* [[SRET:%.*]] to i8* ; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(64) [[SRET_CAST]], i8 0, i64 64, i1 false) -; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(32) [[A_CAST]], i8 42, i64 32, i1 false) +; CHECK-NEXT: call void @llvm.memset.p0i8.i64(i8* nonnull align 8 dereferenceable(32) [[A_CAST_COPY]], i8 42, i64 32, i1 false) ; CHECK-NEXT: [[OUT_CAST:%.*]] = bitcast [8 x i64]* [[OUT:%.*]] to i8* -; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 dereferenceable(64) [[OUT_CAST]], i8* nonnull align 8 dereferenceable(64) [[A_CAST]], i64 64, i1 false) +; CHECK-NEXT: call void @llvm.memcpy.p0i8.p0i8.i64(i8* nonnull align 8 dereferenceable(64) [[OUT_CAST]], i8* nonnull align 8 dereferenceable(64) [[A_CAST_COPY]], i64 64, i1 false) ; CHECK-NEXT: call void @llvm.lifetime.end.p0i8(i64 64, i8* nonnull [[A_CAST]]) ; CHECK-NEXT: ret void ;