diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 35479fa8097ce..e9e0909d2ae62 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -398,8 +398,13 @@ void CIRGenModule::constructAttributeList( attrs.set(cir::CIRDialect::getSideEffectAttrName(), cir::SideEffectAttr::get(&getMLIRContext(), sideEffect)); - // TODO(cir): When doing 'return attrs' we need to cover the Restrict and - // ReturnsNonNull attributes here. + if (targetDecl->hasAttr()) + retAttrs.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); + + // TODO(cir): Add noalias to returns for malloc-like functions + // (__attribute__((malloc)) / __declspec(restrict)). + if (targetDecl->hasAttr()) addUnitAttr(cir::CIRDialect::getNoCallerSavedRegsAttrName()); // TODO(cir): Implement 'NoCFCheck' attribute here. This requires @@ -490,7 +495,7 @@ void CIRGenModule::constructAttributeList( // TODO(cir): Add loader-replaceable attribute here. constructFunctionReturnAttributes(info, targetDecl, isThunk, retAttrs); - constructFunctionArgumentAttributes(info, isThunk, argAttrs); + constructFunctionArgumentAttributes(info, targetDecl, isThunk, argAttrs); } bool CIRGenModule::hasStrictReturn(QualType retTy, const Decl *targetDecl) { @@ -626,13 +631,13 @@ void CIRGenModule::constructFunctionReturnAttributes( } void CIRGenModule::constructFunctionArgumentAttributes( - const CIRGenFunctionInfo &info, bool isThunk, + const CIRGenFunctionInfo &info, const Decl *targetDecl, bool isThunk, llvm::MutableArrayRef argAttrs) { assert(!cir::MissingFeatures::abiArgInfo()); // TODO(cir): classic codegen does a lot of work here based on the ABIArgInfo // to set things based on calling convention. - // At the moment, only nonnull, dereferenceable, align, and noundef are being - // implemented here, using similar logic to how we do so for return types. + + const auto *fd = dyn_cast_or_null(targetDecl); if (info.isInstanceMethod() && !isThunk) { QualType thisPtrTy = info.arguments()[0]; @@ -708,6 +713,33 @@ void CIRGenModule::constructFunctionArgumentAttributes( builder.getI64IntegerAttr( getNaturalPointeeTypeAlignment(argType).getQuantity())); } + + // Source-level parameter attributes (restrict, nonnull). These + // require the FunctionDecl to access ParmVarDecl info. + if (fd) { + unsigned paramIdx = &argAttrList - argAttrs.data(); + unsigned srcIdx = info.isInstanceMethod() ? paramIdx - 1 : paramIdx; + if (srcIdx < fd->getNumParams()) { + const ParmVarDecl *pvd = fd->getParamDecl(srcIdx); + QualType pvdType = pvd->getType(); + + // restrict on pointer parameters → noalias. + if (pvdType->isPointerType() && pvdType.isRestrictQualified()) + argAttrList.set(mlir::LLVM::LLVMDialect::getNoAliasAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); + + // __attribute__((nonnull)) on pointer parameters. + if (pvdType->isPointerType() && !codeGenOpts.NullPointerIsValid) { + bool hasNonnull = pvd->hasAttr(); + if (!hasNonnull) + if (const auto *nna = fd->getAttr()) + hasNonnull = nna->isNonNull(srcIdx); + if (hasNonnull) + argAttrList.set(mlir::LLVM::LLVMDialect::getNonNullAttrName(), + mlir::UnitAttr::get(&getMLIRContext())); + } + } + } } } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 266510de84fd0..8156276c71c96 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -117,8 +117,8 @@ class CIRGenModule : public CIRGenTypeCache { mlir::NamedAttrList &retAttrs); /// A helper for constructAttributeList that handles argument attributes. void constructFunctionArgumentAttributes( - const CIRGenFunctionInfo &info, bool isThunk, - llvm::MutableArrayRef argAttrs); + const CIRGenFunctionInfo &info, const clang::Decl *targetDecl, + bool isThunk, llvm::MutableArrayRef argAttrs); /// A helper function for constructAttributeList that determines whether a /// return value might have been discarded. bool mayDropFunctionReturn(const ASTContext &context, QualType retTy); diff --git a/clang/test/CIR/CodeGen/coro-task.cpp b/clang/test/CIR/CodeGen/coro-task.cpp index b52f0f1871079..b5dbf5d11df60 100644 --- a/clang/test/CIR/CodeGen/coro-task.cpp +++ b/clang/test/CIR/CodeGen/coro-task.cpp @@ -176,7 +176,7 @@ VoidTask silly_task() { // CIR: cir.store{{.*}} %[[NullPtr]], %[[SavedFrameAddr]] : !cir.ptr, !cir.ptr> // CIR: cir.if %[[ShouldAlloc]] { // CIR: %[[CoroSize:.*]] = cir.call @__builtin_coro_size() : () -> (!u64i {llvm.noundef}) -// CIR: %[[AllocAddr:.*]] = cir.call @_Znwm(%[[CoroSize]]) {allocsize = array} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CIR: %[[AllocAddr:.*]] = cir.call @_Znwm(%[[CoroSize]]) {allocsize = array} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CIR: cir.store{{.*}} %[[AllocAddr]], %[[SavedFrameAddr]] : !cir.ptr, !cir.ptr> // CIR: } // CIR: %[[Load0:.*]] = cir.load{{.*}} %[[SavedFrameAddr]] : !cir.ptr>, !cir.ptr diff --git a/clang/test/CIR/CodeGen/new-delete.cpp b/clang/test/CIR/CodeGen/new-delete.cpp index d0c8c7d851c70..c0cb843d3b68b 100644 --- a/clang/test/CIR/CodeGen/new-delete.cpp +++ b/clang/test/CIR/CodeGen/new-delete.cpp @@ -31,7 +31,7 @@ A *a() { // LLVM: define {{.*}} ptr @_Z1av() {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[RETVAL:.*]] = alloca ptr // LLVM: %[[NEW_RESULT:.*]] = alloca ptr -// LLVM: %[[PTR:.*]] = call ptr @_Znwm(i64 8) #[[ATTR_BUILTIN_NEW:.*]] +// LLVM: %[[PTR:.*]] = call nonnull ptr @_Znwm(i64 8) #[[ATTR_BUILTIN_NEW:.*]] // LLVM: br label %[[EH_SCOPE:.*]] // LLVM: [[EH_SCOPE]]: // LLVM: store ptr %[[PTR]], ptr %[[NEW_RESULT]] @@ -106,7 +106,7 @@ A *b() { // LLVM: define {{.*}} ptr @_Z1bv() {{.*}} personality ptr @__gxx_personality_v0 { // LLVM: %[[RETVAL:.*]] = alloca ptr // LLVM: %[[NEW_RESULT:.*]] = alloca ptr -// LLVM: %[[PTR:.*]] = call ptr @_Znwm(i64 8) #[[ATTR_BUILTIN_NEW]] +// LLVM: %[[PTR:.*]] = call nonnull ptr @_Znwm(i64 8) #[[ATTR_BUILTIN_NEW]] // LLVM: br label %[[EH_SCOPE:.*]] // LLVM: [[EH_SCOPE]]: // LLVM: store ptr %[[PTR]], ptr %[[NEW_RESULT]] diff --git a/clang/test/CIR/CodeGen/new.cpp b/clang/test/CIR/CodeGen/new.cpp index 1062b5867d0d6..4db951322e98c 100644 --- a/clang/test/CIR/CodeGen/new.cpp +++ b/clang/test/CIR/CodeGen/new.cpp @@ -163,7 +163,7 @@ void test_new_with_complex_type() { // CHECK: cir.func{{.*}} @_Z26test_new_with_complex_typev // CHECK: %[[A_ADDR:.*]] = cir.alloca !cir.ptr>, !cir.ptr>>, ["a", init] // CHECK: %[[COMPLEX_SIZE:.*]] = cir.const #cir.int<8> : !u64i -// CHECK: %[[NEW_COMPLEX:.*]] = cir.call @_Znwm(%[[COMPLEX_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[NEW_COMPLEX:.*]] = cir.call @_Znwm(%[[COMPLEX_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[COMPLEX_PTR:.*]] = cir.cast bitcast %[[NEW_COMPLEX]] : !cir.ptr -> !cir.ptr> // CHECK: %[[COMPLEX_VAL:.*]] = cir.const #cir.const_complex<#cir.fp<1.000000e+00> : !cir.float, #cir.fp<2.000000e+00> : !cir.float> : !cir.complex // CHECK: cir.store{{.*}} %[[COMPLEX_VAL]], %[[COMPLEX_PTR]] : !cir.complex, !cir.ptr> @@ -171,7 +171,7 @@ void test_new_with_complex_type() { // LLVM: define{{.*}} void @_Z26test_new_with_complex_typev // LLVM: %[[A_ADDR:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[NEW_COMPLEX:.*]] = call noundef ptr @_Znwm(i64 noundef 8) +// LLVM: %[[NEW_COMPLEX:.*]] = call noundef nonnull ptr @_Znwm(i64 noundef 8) // LLVM: store { float, float } { float 1.000000e+00, float 2.000000e+00 }, ptr %[[NEW_COMPLEX]], align 8 // LLVM: store ptr %[[NEW_COMPLEX]], ptr %[[A_ADDR]], align 8 @@ -191,7 +191,7 @@ void t_new_constant_size() { // CHECK: cir.func{{.*}} @_Z19t_new_constant_sizev() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["p", init] {alignment = 8 : i64} // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<128> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr, !cir.ptr> // CHECK: cir.return @@ -199,7 +199,7 @@ void t_new_constant_size() { // LLVM: define{{.*}} void @_Z19t_new_constant_sizev // LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[CALL:.*]] = call noundef ptr @_Znam(i64 noundef 128) +// LLVM: %[[CALL:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 128) // LLVM: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8 // OGCG: define{{.*}} void @_Z19t_new_constant_sizev @@ -220,7 +220,7 @@ void t_constant_size_nontrivial() { // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["p", init] {alignment = 8 : i64} // CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<11> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr> // CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr> -> !cir.ptr // CHECK: cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr @@ -234,7 +234,7 @@ void t_constant_size_nontrivial() { // LLVM: @_Z26t_constant_size_nontrivialv() // LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[COOKIE_PTR:.*]] = call noundef ptr @_Znam(i64 noundef 11) +// LLVM: %[[COOKIE_PTR:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 11) // LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8 // LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8 // LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 @@ -260,7 +260,7 @@ void t_constant_size_nontrivial2() { // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["p", init] {alignment = 8 : i64} // CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<3> : !u64i // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<20> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr> // CHECK: %[[COOKIE_PTR:.*]] = cir.cast bitcast %[[COOKIE_PTR_BASE]] : !cir.ptr> -> !cir.ptr // CHECK: cir.store align(8) %[[NUM_ELEMENTS]], %[[COOKIE_PTR]] : !u64i, !cir.ptr @@ -274,7 +274,7 @@ void t_constant_size_nontrivial2() { // LLVM: @_Z27t_constant_size_nontrivial2v() // LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[COOKIE_PTR:.*]] = call noundef ptr @_Znam(i64 noundef 20) +// LLVM: %[[COOKIE_PTR:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 20) // LLVM: store i64 3, ptr %[[COOKIE_PTR]], align 8 // LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[COOKIE_PTR]], i64 8 // LLVM: store ptr %[[ALLOCATED_PTR]], ptr %[[ALLOCA]], align 8 @@ -292,7 +292,7 @@ void t_align16_nontrivial() { // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr, !cir.ptr>, ["p", init] {alignment = 8 : i64} // CHECK: %[[NUM_ELEMENTS:.*]] = cir.const #cir.int<2> : !u64i // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<48> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[COOKIE_PTR_BASE:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr> // CHECK: %[[COOKIE_OFFSET:.*]] = cir.const #cir.int<8> : !s32i // CHECK: %[[COOKIE_PTR_RAW:.*]] = cir.ptr_stride %[[COOKIE_PTR_BASE]], %[[COOKIE_OFFSET]] : (!cir.ptr>, !s32i) -> !cir.ptr> @@ -308,7 +308,7 @@ void t_align16_nontrivial() { // LLVM: @_Z20t_align16_nontrivialv() // LLVM: %[[ALLOCA:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[RAW_PTR:.*]] = call noundef ptr @_Znam(i64 noundef 48) +// LLVM: %[[RAW_PTR:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 48) // LLVM: %[[COOKIE_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 8 // LLVM: store i64 2, ptr %[[COOKIE_PTR]], align 8 // LLVM: %[[ALLOCATED_PTR:.*]] = getelementptr ptr, ptr %[[RAW_PTR]], i64 16 @@ -330,14 +330,14 @@ void t_new_multidim_constant_size() { // CHECK: cir.func{{.*}} @_Z28t_new_multidim_constant_sizev() // CHECK: %[[P_ADDR:.*]] = cir.alloca !cir.ptr x 3>>, !cir.ptr x 3>>>, ["p", init] {alignment = 8 : i64} // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<192> : !u64i -// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[RAW_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[TYPED_PTR:.*]] = cir.cast bitcast %[[RAW_PTR]] : !cir.ptr -> !cir.ptr x 3>> // CHECK: cir.store align(8) %[[TYPED_PTR]], %[[P_ADDR]] : !cir.ptr x 3>>, !cir.ptr x 3>>> // CHECK: } // LLVM: define{{.*}} void @_Z28t_new_multidim_constant_sizev // LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[CALL:.*]] = call noundef ptr @_Znam(i64 noundef 192) +// LLVM: %[[CALL:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 192) // LLVM: store ptr %[[CALL]], ptr %[[P_ADDR]], align 8 // OGCG: define{{.*}} void @_Z28t_new_multidim_constant_sizev @@ -351,14 +351,14 @@ void t_constant_size_memset_init() { // CHECK: cir.func {{.*}} @_Z27t_constant_size_memset_initv() // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i -// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[ELEM_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[VOID_PTR:.*]] = cir.cast bitcast %[[ELEM_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[ZERO:.*]] = cir.const #cir.int<0> : !u8i // CHECK: cir.libc.memset %[[ALLOCATION_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: define {{.*}} void @_Z27t_constant_size_memset_initv() -// LLVM: %[[P:.*]] = call noundef ptr @_Znam(i64 noundef 64) +// LLVM: %[[P:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 64) // LLVM: call void @llvm.memset.p0.i64(ptr %[[P]], i8 0, i64 64, i1 false) // OGCG: define {{.*}} void @_Z27t_constant_size_memset_initv() @@ -371,7 +371,7 @@ void t_constant_size_full_init() { // CHECK: cir.func {{.*}} @_Z25t_constant_size_full_initv() // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<16> : !u64i -// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i // CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr @@ -389,7 +389,7 @@ void t_constant_size_full_init() { // CHECK: cir.store{{.*}} %[[CONST_FOUR]], %[[ELEM_3_PTR]] : !s32i, !cir.ptr // LLVM: define {{.*}} void @_Z25t_constant_size_full_initv() -// LLVM: %[[P:.*]] = call noundef ptr @_Znam(i64 noundef 16) +// LLVM: %[[P:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 16) // LLVM: store i32 1, ptr %[[CALL]] // LLVM: %[[ELEM_1:.*]] = getelementptr i32, ptr %[[P]], i64 1 // LLVM: store i32 2, ptr %[[ELEM_1]] @@ -414,7 +414,7 @@ void t_constant_size_partial_init() { // CHECK: cir.func {{.*}} @_Z28t_constant_size_partial_initv() // CHECK: %[[ALLOCATION_SIZE:.*]] = cir.const #cir.int<64> : !u64i -// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) +// CHECK: %[[ALLOC_PTR:.*]] = cir.call @_Znam(%[[ALLOCATION_SIZE]]) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CHECK: %[[ELEM_0_PTR:.*]] = cir.cast bitcast %[[ALLOC_PTR]] : !cir.ptr -> !cir.ptr // CHECK: %[[CONST_ONE:.*]] = cir.const #cir.int<1> : !s32i // CHECK: cir.store{{.*}} %[[CONST_ONE]], %[[ELEM_0_PTR]] : !s32i, !cir.ptr @@ -435,7 +435,7 @@ void t_constant_size_partial_init() { // CHECK: cir.libc.memset %[[REMAINING_SIZE]] bytes at %[[VOID_PTR]] to %[[ZERO]] : !cir.ptr, !u8i, !u64i // LLVM: define {{.*}} void @_Z28t_constant_size_partial_initv() -// LLVM: %[[P:.*]] = call noundef ptr @_Znam(i64 {{.*}} 64) +// LLVM: %[[P:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} 64) // LLVM: store i32 1, ptr %[[P]] // LLVM: %[[ELEM_1:.*]] = getelementptr i32, ptr %[[P]], i64 1 // LLVM: store i32 2, ptr %[[ELEM_1]] @@ -464,7 +464,7 @@ void t_new_var_size(size_t n) { // LLVM: define{{.*}} void @_Z14t_new_var_sizem // LLVM: %[[N:.*]] = load i64, ptr %{{.+}} -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[N]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[N]]) // OGCG: define{{.*}} void @_Z14t_new_var_sizem // OGCG: %[[N:.*]] = load i64, ptr %{{.+}} @@ -482,7 +482,7 @@ void t_new_var_size2(int n) { // LLVM: define{{.*}} void @_Z15t_new_var_size2i // LLVM: %[[N:.*]] = load i32, ptr %{{.+}} // LLVM: %[[N_SIZE_T:.*]] = sext i32 %[[N]] to i64 -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[N_SIZE_T]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[N_SIZE_T]]) // OGCG: define{{.*}} void @_Z15t_new_var_size2i // OGCG: %[[N:.*]] = load i32, ptr %{{.+}} @@ -507,7 +507,7 @@ void t_new_var_size3(size_t n) { // LLVM: %[[ELEMENT_SIZE:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 0 // LLVM: %[[OVERFLOW:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 1 // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[RESULT:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[RESULT:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // OGCG: define{{.*}} void @_Z15t_new_var_size3m // OGCG: %[[N:.*]] = load i64, ptr %{{.+}} @@ -537,7 +537,7 @@ void t_new_var_size4(int n) { // LLVM: %[[ELEMENT_SIZE:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 0 // LLVM: %[[OVERFLOW:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 1 // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // OGCG: define{{.*}} void @_Z15t_new_var_size4i // OGCG: %[[N:.*]] = load i32, ptr %{{.+}} @@ -571,7 +571,7 @@ void t_new_var_size5(int n) { // LLVM: %[[ELEMENT_SIZE:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 0 // LLVM: %[[OVERFLOW:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 1 // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // OGCG: define{{.*}} void @_Z15t_new_var_size5i // OGCG: %[[N:.*]] = load i32, ptr %{{.+}} @@ -625,7 +625,7 @@ void t_new_var_size6(int n) { // LLVM: %[[OVERFLOW:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 1 // LLVM: %[[ANY_OVERFLOW:.*]] = or i1 %[[LT_MIN_SIZE]], %[[OVERFLOW]] // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[ANY_OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // LLVM: store double 1.000000e+00, ptr %[[PTR]], align 8 // LLVM: %[[ELEM_1:.*]] = getelementptr double, ptr %[[PTR]], i64 1 // LLVM: store double 2.000000e+00, ptr %[[ELEM_1]], align 8 @@ -674,7 +674,7 @@ void t_new_var_size7(__int128 n) { // LLVM: %[[ELEMENT_SIZE:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 0 // LLVM: %[[OVERFLOW:.*]] = extractvalue { i64, i1 } %[[MUL_OVERFLOW]], 1 // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // OGCG: define{{.*}} void @_Z15t_new_var_size7n // OGCG: %[[N:.*]] = load i128, ptr %{{.+}} @@ -710,7 +710,7 @@ void t_new_var_size_nontrivial(size_t n) { // LLVM: %[[OVERFLOW_ADD:.*]] = extractvalue { i64, i1 } %[[ADD_OVERFLOW]], 1 // LLVM: %[[ANY_OVERFLOW:.*]] = or i1 %[[OVERFLOW]], %[[OVERFLOW_ADD]] // LLVM: %[[ALLOC_SIZE:.*]] = select i1 %[[ANY_OVERFLOW]], i64 -1, i64 %[[ELEMENT_SIZE]] -// LLVM: %[[PTR:.*]] = call noundef ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) +// LLVM: %[[PTR:.*]] = call noundef nonnull ptr @_Znam(i64 {{.*}} %[[ALLOC_SIZE]]) // OGCG: define{{.*}} void @_Z25t_new_var_size_nontrivialm // OGCG: %[[N:.*]] = load i64, ptr %{{.+}} @@ -775,7 +775,7 @@ void test_array_new_with_ctor_init() { // LLVM: define{{.*}} void @_Z29test_array_new_with_ctor_initv // LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[RAW_PTR:.*]] = call noundef ptr @_Znam(i64 noundef 3) +// LLVM: %[[RAW_PTR:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 3) // LLVM: %[[BEGIN:.*]] = getelementptr %class.F, ptr %[[RAW_PTR]], i32 0 // LLVM: %[[ARRAY_END:.*]] = getelementptr %class.F, ptr %[[BEGIN]], i64 3 // LLVM: %[[IDX_ADDR:.*]] = alloca ptr, i64 1, align 1 @@ -874,7 +874,7 @@ void test_array_new_with_ctor_partial_init_list() { // LLVM: define{{.*}} void @_Z42test_array_new_with_ctor_partial_init_listv // LLVM: %[[P_ADDR:.*]] = alloca ptr, i64 1, align 8 -// LLVM: %[[RAW_PTR:.*]] = call noundef ptr @_Znam(i64 noundef 8) +// LLVM: %[[RAW_PTR:.*]] = call noundef nonnull ptr @_Znam(i64 noundef 8) // LLVM: call void @_ZN1GC1Ei(ptr noundef nonnull align 1 dereferenceable(1) %[[RAW_PTR]], i32 noundef 1) // LLVM: %[[SECOND:.*]] = getelementptr %class.G, ptr %[[RAW_PTR]], i64 1 // LLVM: call void @_ZN1GC1Ei(ptr noundef nonnull align 1 dereferenceable(1) %[[SECOND]], i32 noundef 2) diff --git a/clang/test/CIR/CodeGen/restrict-nonnull.c b/clang/test/CIR/CodeGen/restrict-nonnull.c new file mode 100644 index 0000000000000..d391ac1b36809 --- /dev/null +++ b/clang/test/CIR/CodeGen/restrict-nonnull.c @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t-cir.ll %s +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// restrict on pointer params adds noalias. +void take_restrict(int *restrict p) { *p = 42; } +// CIR: cir.func {{.*}} @take_restrict(%arg0: !cir.ptr +// CIR-SAME: {llvm.noalias, llvm.noundef} +// LLVM: define {{.*}} void @take_restrict(ptr noalias noundef %{{.*}}) +// OGCG: define {{.*}} void @take_restrict(ptr noalias noundef %{{.*}}) + +// __attribute__((nonnull)) on individual parameter. +void take_nonnull(int *p) __attribute__((nonnull(1))); +void take_nonnull(int *p) { *p = 42; } +// CIR: cir.func {{.*}} @take_nonnull(%arg0: !cir.ptr +// CIR-SAME: {llvm.nonnull, llvm.noundef} +// LLVM: define {{.*}} void @take_nonnull(ptr noundef nonnull %{{.*}}) +// OGCG: define {{.*}} void @take_nonnull(ptr noundef nonnull %{{.*}}) + +// restrict + nonnull together. +void take_both(int *restrict p) __attribute__((nonnull(1))); +void take_both(int *restrict p) { *p = 42; } +// CIR: cir.func {{.*}} @take_both(%arg0: !cir.ptr +// CIR-SAME: {llvm.noalias, llvm.nonnull, llvm.noundef} +// LLVM: define {{.*}} void @take_both(ptr noalias noundef nonnull %{{.*}}) +// OGCG: define {{.*}} void @take_both(ptr noalias noundef nonnull %{{.*}}) diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-call.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-call.cpp index d6f72b115f183..0efb6c7ae78ef 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-call.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtin-call.cpp @@ -85,11 +85,11 @@ void library_builtins() { // CIR: cir.func{{.*}} @_Z16library_builtinsv() // CIR: %[[NULL:.+]] = cir.const #cir.ptr : !cir.ptr -// CIR: cir.call @printf(%[[NULL]]) nothrow : (!cir.ptr {llvm.noundef}) -> !s32i +// CIR: cir.call @printf(%[[NULL]]) nothrow : (!cir.ptr {llvm.noalias, llvm.noundef}) -> !s32i // CIR: cir.call @abort() nothrow {noreturn} : () -> () // LLVM: define{{.*}} void @_Z16library_builtinsv() -// LLVM: call i32 (ptr, ...) @printf(ptr noundef null) +// LLVM: call i32 (ptr, ...) @printf(ptr noalias noundef null) // LLVM: call void @abort() // OGCG: define{{.*}} void @_Z16library_builtinsv() diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-new-delete.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-new-delete.cpp index fdb4250af06d6..3ddf165e767c2 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-new-delete.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtin-new-delete.cpp @@ -9,12 +9,12 @@ void test_builtins_basic() { __builtin_operator_delete(__builtin_operator_new(4)); // CIR-LABEL: test_builtins_basic - // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) + // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CIR: cir.call @_ZdlPv([[P]]) {{.*}}builtin{{.*}} : (!cir.ptr {llvm.noundef}) -> () // CIR: cir.return // LLVM-LABEL: test_builtins_basic - // LLVM: [[P:%.*]] = call noundef ptr @_Znwm(i64 {{.*}} 4) #[[ATTR_BUILTIN_NEW:.*]] + // LLVM: [[P:%.*]] = call noundef nonnull ptr @_Znwm(i64 {{.*}} 4) #[[ATTR_BUILTIN_NEW:.*]] // LLVM: call void @_ZdlPv(ptr {{.*}} [[P]]) #[[ATTR_BUILTIN_DEL:.*]] // LLVM: ret void @@ -28,12 +28,12 @@ void test_sized_delete() { __builtin_operator_delete(__builtin_operator_new(4), 4); // CIR-LABEL: test_sized_delete - // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.noundef}) + // CIR: [[P:%.*]] = cir.call @_Znwm({{%.*}}) {allocsize = array, builtin} : (!u64i {llvm.noundef}) -> (!cir.ptr {llvm.nonnull, llvm.noundef}) // CIR: cir.call @_ZdlPvm([[P]], {{%.*}}) {{.*}}builtin{{.*}} : (!cir.ptr {llvm.noundef}, !u64i {llvm.noundef}) -> () // CIR: cir.return // LLVM-LABEL: test_sized_delete - // LLVM: [[P:%.*]] = call noundef ptr @_Znwm(i64 {{.*}} 4) #[[ATTR_BUILTIN_NEW]] + // LLVM: [[P:%.*]] = call noundef nonnull ptr @_Znwm(i64 {{.*}} 4) #[[ATTR_BUILTIN_NEW]] // LLVM: call void @_ZdlPvm(ptr {{.*}} [[P]], i64 {{.*}} 4) #[[ATTR_BUILTIN_DEL]] // LLVM: ret void diff --git a/clang/test/CIR/CodeGenBuiltins/builtin-printf.cpp b/clang/test/CIR/CodeGenBuiltins/builtin-printf.cpp index 2a0f5c4196a8d..5c2ee802f7076 100644 --- a/clang/test/CIR/CodeGenBuiltins/builtin-printf.cpp +++ b/clang/test/CIR/CodeGenBuiltins/builtin-printf.cpp @@ -26,16 +26,16 @@ void func(char const * const str, int i) { // CIR: cir.store %[[arg0]], %[[str_ptr]] : !cir.ptr, !cir.ptr> // CIR: cir.store %[[arg1]], %[[i_ptr]] : !s32i, !cir.ptr // CIR: %[[null_ptr:.+]] = cir.const #cir.ptr : !cir.ptr -// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) nothrow : (!cir.ptr {llvm.noundef}) -> !s32i +// CIR: %[[printf_result1:.+]] = cir.call @printf(%[[null_ptr]]) nothrow : (!cir.ptr {llvm.noalias, llvm.noundef}) -> !s32i // CIR: %[[str_fmt_global:.+]] = cir.get_global @".str" : !cir.ptr> // CIR: %[[str_fmt_ptr:.+]] = cir.cast array_to_ptrdecay %[[str_fmt_global]] : !cir.ptr> -> !cir.ptr // CIR: %[[str_val:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr>, !cir.ptr -// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) nothrow : (!cir.ptr {llvm.noundef}, !cir.ptr {llvm.noundef}) -> !s32i +// CIR: %[[printf_result2:.+]] = cir.call @printf(%[[str_fmt_ptr]], %[[str_val]]) nothrow : (!cir.ptr {llvm.noalias, llvm.noundef}, !cir.ptr {llvm.noundef}) -> !s32i // CIR: %[[full_fmt_global:.+]] = cir.get_global @".str.1" : !cir.ptr> // CIR: %[[full_fmt_ptr:.+]] = cir.cast array_to_ptrdecay %[[full_fmt_global]] : !cir.ptr> -> !cir.ptr // CIR: %[[str_val2:.+]] = cir.load{{.*}} %[[str_ptr]] : !cir.ptr>, !cir.ptr // CIR: %[[i_val:.+]] = cir.load{{.*}} %[[i_ptr]] : !cir.ptr, !s32i -// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) nothrow : (!cir.ptr {llvm.noundef}, !cir.ptr {llvm.noundef}, !s32i {llvm.noundef}) -> !s32i +// CIR: %[[printf_result3:.+]] = cir.call @printf(%[[full_fmt_ptr]], %[[str_val2]], %[[i_val]]) nothrow : (!cir.ptr {llvm.noalias, llvm.noundef}, !cir.ptr {llvm.noundef}, !s32i {llvm.noundef}) -> !s32i // CIR: cir.return // LLVM: define{{.*}} void @_Z4funcPKci(ptr noundef %[[arg0:.+]], i32 noundef %[[arg1:.+]]) @@ -43,12 +43,12 @@ void func(char const * const str, int i) { // LLVM: %[[i_ptr:.+]] = alloca i32 // LLVM: store ptr %[[arg0]], ptr %[[str_ptr]]{{.*}} // LLVM: store i32 %[[arg1]], ptr %[[i_ptr]]{{.*}} -// LLVM: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr noundef null) +// LLVM: %[[printf_result1:.+]] = call i32 (ptr, ...) @printf(ptr noalias noundef null) // LLVM: %[[str_val:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} -// LLVM: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str, ptr noundef %[[str_val]]) +// LLVM: %[[printf_result2:.+]] = call i32 (ptr, ...) @printf(ptr noalias noundef @.str, ptr noundef %[[str_val]]) // LLVM: %[[str_val2:.+]] = load ptr, ptr %[[str_ptr]]{{.*}} // LLVM: %[[i_val:.+]] = load i32, ptr %[[i_ptr]]{{.*}} -// LLVM: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr noundef @.str.1, ptr noundef %[[str_val2]], i32 noundef %[[i_val]]) +// LLVM: %[[printf_result3:.+]] = call i32 (ptr, ...) @printf(ptr noalias noundef @.str.1, ptr noundef %[[str_val2]], i32 noundef %[[i_val]]) // LLVM: ret void // OGCG: define{{.*}} void @_Z4funcPKci(ptr noundef %[[arg0:.+]], i32 noundef %[[arg1:.+]])