Index: llvm/lib/Transforms/Scalar/GVNHoist.cpp =================================================================== --- llvm/lib/Transforms/Scalar/GVNHoist.cpp +++ llvm/lib/Transforms/Scalar/GVNHoist.cpp @@ -185,7 +185,13 @@ void insert(LoadInst *Load, GVNPass::ValueTable &VN) { if (Load->isSimple()) { unsigned V = VN.lookupOrAdd(Load->getPointerOperand()); - VNtoLoads[{V, InvalidVN}].push_back(Load); + // Hash the load's pointer value, result base type, and result size. + // With opaque pointers we may have loads from the same pointer with + // different result types, which should be disambiguated. + Type *LT = Load->getType(); + // "0" size for pointers is OK, as pointer loads are equivalent. + unsigned TypeHash = LT->getTypeID() + (LT->getPrimitiveSizeInBits() << 8); + VNtoLoads[{V, TypeHash}].push_back(Load); } } Index: llvm/test/Transforms/GVNHoist/opaque-diff-type.ll =================================================================== --- /dev/null +++ llvm/test/Transforms/GVNHoist/opaque-diff-type.ll @@ -0,0 +1,64 @@ +; RUN: opt -opaque-pointers -passes="gvn-hoist" -S %s | FileCheck %s + +; Checks that gvn-hoist does not try to merge loads of the same source pointer +; when the results are different types. + +; CHECK: load i16 +; CHECK: load i32 +define linkonce_odr void @i16i32(ptr %arg) { +bb: + br i1 false, label %bb1, label %bb2 + +bb1: ; preds = %bb + %tmp = load i16, ptr %arg, align 4 + br label %bb2 + +bb2: ; preds = %bb1, %bb + %tmp3 = load i32, ptr %arg, align 8 + ret void +} + +; CHECK: load i32 +; CHECK: load float +define linkonce_odr void @i32f32(ptr %arg) { +bb: + br i1 false, label %bb1, label %bb2 + +bb1: ; preds = %bb + %tmp = load i32, ptr %arg, align 4 + br label %bb2 + +bb2: ; preds = %bb1, %bb + %tmp3 = load float, ptr %arg, align 8 + ret void +} + +; CHECK: load i64 +; CHECK: load ptr +define linkonce_odr void @i64ptr(ptr %arg) { +bb: + br i1 false, label %bb1, label %bb2 + +bb1: ; preds = %bb + %tmp = load i64, ptr %arg, align 4 + br label %bb2 + +bb2: ; preds = %bb1, %bb + %tmp3 = load ptr, ptr %arg, align 8 + ret void +} + +; CHECK: load ptr +; CHECK-NOT: load ptr +define linkonce_odr void @ptrptr(ptr %arg) { +bb: + br i1 false, label %bb1, label %bb2 + +bb1: ; preds = %bb + %tmp = load ptr, ptr %arg, align 4 + br label %bb2 + +bb2: ; preds = %bb1, %bb + %tmp3 = load ptr, ptr %arg, align 8 + ret void +}