Index: llvm/include/llvm/IR/LLVMContext.h =================================================================== --- llvm/include/llvm/IR/LLVMContext.h +++ llvm/include/llvm/IR/LLVMContext.h @@ -305,6 +305,9 @@ /// LLVMContext is used by compilation. void setOptPassGate(OptPassGate&); + /// Whether typed pointers are supported. If false, all pointers are opaque. + bool supportsTypedPointers() const; + private: // Module needs access to the add/removeModule methods. friend class Module; Index: llvm/lib/IR/Function.cpp =================================================================== --- llvm/lib/IR/Function.cpp +++ llvm/lib/IR/Function.cpp @@ -1404,9 +1404,21 @@ } case IITDescriptor::Pointer: { PointerType *PT = dyn_cast(Ty); - return !PT || PT->getAddressSpace() != D.Pointer_AddressSpace || - matchIntrinsicType(PT->getElementType(), Infos, ArgTys, - DeferredChecks, IsDeferredCheck); + if (!PT || PT->getAddressSpace() != D.Pointer_AddressSpace) + return true; + if (!PT->isOpaque()) + return matchIntrinsicType(PT->getElementType(), Infos, ArgTys, + DeferredChecks, IsDeferredCheck); + // If typed pointers are supported, do not allow using opaque pointer in + // place of fixed pointer type. This would make the intrinsic signature + // non-unique. + if (Ty->getContext().supportsTypedPointers()) + return true; + // Consume IIT descriptors relating to the pointer element type. + while (Infos.front().Kind == IITDescriptor::Pointer) + Infos = Infos.slice(1); + Infos = Infos.slice(1); + return false; } case IITDescriptor::Struct: { @@ -1517,8 +1529,13 @@ dyn_cast (ArgTys[D.getArgumentNumber()]); PointerType *ThisArgType = dyn_cast(Ty); - return (!ThisArgType || !ReferenceType || - ThisArgType->getElementType() != ReferenceType->getElementType()); + if (!ThisArgType || !ReferenceType) + return true; + if (!ThisArgType->isOpaque()) + return ThisArgType->getElementType() != ReferenceType->getElementType(); + // If typed pointers are supported, do not allow opaque pointer to ensure + // uniqueness. + return Ty->getContext().supportsTypedPointers(); } case IITDescriptor::VecOfAnyPtrsToElt: { unsigned RefArgNumber = D.getRefArgNumber(); Index: llvm/lib/IR/LLVMContext.cpp =================================================================== --- llvm/lib/IR/LLVMContext.cpp +++ llvm/lib/IR/LLVMContext.cpp @@ -347,3 +347,7 @@ std::unique_ptr LLVMContext::getDiagnosticHandler() { return std::move(pImpl->DiagHandler); } + +bool LLVMContext::supportsTypedPointers() const { + return !pImpl->ForceOpaquePointers; +} Index: llvm/test/Assembler/remangle-intrinsic-opaque-ptr.ll =================================================================== --- /dev/null +++ llvm/test/Assembler/remangle-intrinsic-opaque-ptr.ll @@ -0,0 +1,20 @@ +; RUN: not llvm-as < %s -disable-output 2>&1 | FileCheck %s --check-prefix=TYPED +; RUN: llvm-as --force-opaque-pointers < %s | llvm-dis --force-opaque-pointers | FileCheck %s --check-prefix=OPAQUE + +; An opaque pointer type should not be accepted for an intrinsic that +; specifies a fixed pointer type, outside of --force-opaque-pointers mode. + +define void @test() { +; TYPED: Intrinsic has incorrect return type! +; OPAQUE: call ptr @llvm.stacksave() + call ptr @llvm.stacksave() + +; TYPED: Intrinsic has incorrect argument type! +; OPAQUE: call <2 x i64> @llvm.masked.expandload.v2i64(ptr null, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) + call <2 x i64> @llvm.masked.expandload.v2i64(ptr null, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) + + ret void +} + +declare ptr @llvm.stacksave() +declare <2 x i64> @llvm.masked.expandload.v2i64(ptr, <2 x i1>, <2 x i64>) Index: llvm/test/Other/force-opaque-ptrs.ll =================================================================== --- llvm/test/Other/force-opaque-ptrs.ll +++ llvm/test/Other/force-opaque-ptrs.ll @@ -48,3 +48,22 @@ ; unreachable } + +define void @remangle_intrinsic() { +; CHECK-LABEL: define {{[^@]+}}@remangle_intrinsic() { +; CHECK-NEXT: [[A:%.*]] = alloca ptr, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = call ptr @llvm.stacksave() +; CHECK-NEXT: call void @llvm.stackprotector(ptr null, ptr [[A]]) +; CHECK-NEXT: [[TMP2:%.*]] = call <2 x i64> @llvm.masked.expandload.v2i64(ptr null, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) +; CHECK-NEXT: ret void +; + %a = alloca i8* + call i8* @llvm.stacksave() + call void @llvm.stackprotector(i8* null, i8** %a) + call <2 x i64> @llvm.masked.expandload.v2i64(i64* null, <2 x i1> zeroinitializer, <2 x i64> zeroinitializer) + ret void +} + +declare i8* @llvm.stacksave() +declare void @llvm.stackprotector(i8*, i8**) +declare <2 x i64> @llvm.masked.expandload.v2i64(i64*, <2 x i1>, <2 x i64>)