Reland "[flang] Added noalias attribute to function arguments. (#140803)"

This helps to disambiguate accesses in the caller and the callee
after LLVM inlining in some apps. I did not see any performance
changes, but this is one step towards enabling other optimizations
in the apps that I am looking at.

The definition of llvm.noalias says:
```
... indicates that memory locations accessed via pointer values based on the argument or return value are not also accessed, during the execution of the function, via pointer values not based on the argument or return value. This guarantee only holds for memory locations that are modified, by any means, during the execution of the function.
```

I believe this exactly matches Fortran rules for the dummy arguments
that are modified during their subprogram execution.

I also set llvm.noalias and llvm.nocapture on the !fir.box<> arguments,
because the corresponding descriptors cannot be captured and cannot
alias anything (not based on them) during the execution of the
subprogram.
This commit is contained in:
Slava Zakharin 2025-05-28 17:18:04 -07:00
parent 55c7d5cdad
commit a0d699a8e6
30 changed files with 265 additions and 112 deletions

View File

@ -431,6 +431,12 @@ def FunctionAttr : Pass<"function-attr", "mlir::func::FuncOp"> {
"Set the unsafe-fp-math attribute on functions in the module.">,
Option<"tuneCPU", "tune-cpu", "std::string", /*default=*/"",
"Set the tune-cpu attribute on functions in the module.">,
Option<"setNoCapture", "set-nocapture", "bool", /*default=*/"false",
"Set LLVM nocapture attribute on function arguments, "
"if possible">,
Option<"setNoAlias", "set-noalias", "bool", /*default=*/"false",
"Set LLVM noalias attribute on function arguments, "
"if possible">,
];
}

View File

@ -350,11 +350,15 @@ void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
else
framePointerKind = mlir::LLVM::framePointerKind::FramePointerKind::None;
bool setNoCapture = false, setNoAlias = false;
if (config.OptLevel.isOptimizingForSpeed())
setNoCapture = setNoAlias = true;
pm.addPass(fir::createFunctionAttr(
{framePointerKind, config.InstrumentFunctionEntry,
config.InstrumentFunctionExit, config.NoInfsFPMath, config.NoNaNsFPMath,
config.ApproxFuncFPMath, config.NoSignedZerosFPMath, config.UnsafeFPMath,
""}));
/*tuneCPU=*/"", setNoCapture, setNoAlias}));
if (config.EnableOpenMP) {
pm.addNestedPass<mlir::func::FuncOp>(

View File

@ -27,17 +27,8 @@ namespace {
class FunctionAttrPass : public fir::impl::FunctionAttrBase<FunctionAttrPass> {
public:
FunctionAttrPass(const fir::FunctionAttrOptions &options) {
instrumentFunctionEntry = options.instrumentFunctionEntry;
instrumentFunctionExit = options.instrumentFunctionExit;
framePointerKind = options.framePointerKind;
noInfsFPMath = options.noInfsFPMath;
noNaNsFPMath = options.noNaNsFPMath;
approxFuncFPMath = options.approxFuncFPMath;
noSignedZerosFPMath = options.noSignedZerosFPMath;
unsafeFPMath = options.unsafeFPMath;
}
FunctionAttrPass() {}
FunctionAttrPass(const fir::FunctionAttrOptions &options) : Base{options} {}
FunctionAttrPass() = default;
void runOnOperation() override;
};
@ -56,14 +47,28 @@ void FunctionAttrPass::runOnOperation() {
if ((isFromModule || !func.isDeclaration()) &&
!fir::hasBindcAttr(func.getOperation())) {
llvm::StringRef nocapture = mlir::LLVM::LLVMDialect::getNoCaptureAttrName();
llvm::StringRef noalias = mlir::LLVM::LLVMDialect::getNoAliasAttrName();
mlir::UnitAttr unitAttr = mlir::UnitAttr::get(func.getContext());
for (auto [index, argType] : llvm::enumerate(func.getArgumentTypes())) {
bool isNoCapture = false;
bool isNoAlias = false;
if (mlir::isa<fir::ReferenceType>(argType) &&
!func.getArgAttr(index, fir::getTargetAttrName()) &&
!func.getArgAttr(index, fir::getAsynchronousAttrName()) &&
!func.getArgAttr(index, fir::getVolatileAttrName()))
!func.getArgAttr(index, fir::getVolatileAttrName())) {
isNoCapture = true;
isNoAlias = !fir::isPointerType(argType);
} else if (mlir::isa<fir::BaseBoxType>(argType)) {
// !fir.box arguments will be passed as descriptor pointers
// at LLVM IR dialect level - they cannot be captured,
// and cannot alias with anything within the function.
isNoCapture = isNoAlias = true;
}
if (isNoCapture && setNoCapture)
func.setArgAttr(index, nocapture, unitAttr);
if (isNoAlias && setNoAlias)
func.setArgAttr(index, noalias, unitAttr);
}
}

View File

@ -33,7 +33,7 @@ func.func @test_array_coor_box_component_slice(%arg0: !fir.box<!fir.array<2x!fir
func.func private @take_int(%arg0: !fir.ref<i32>) -> ()
// CHECK-LABEL: define void @test_array_coor_box_component_slice(
// CHECK-SAME: ptr %[[VAL_0:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[VAL_0:.*]])
// CHECK: %[[VAL_1:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[VAL_0]], i32 0, i32 7, i32 0, i32 2
// CHECK: %[[VAL_2:.*]] = load i64, ptr %[[VAL_1]]
// CHECK: %[[VAL_3:.*]] = mul nsw i64 1, %[[VAL_2]]

View File

@ -1,7 +1,7 @@
// RUN: tco %s | FileCheck %s
// RUN: %flang_fc1 -emit-llvm %s -o - | FileCheck %s
// CHECK-LABEL: define void @x(ptr captures(none) %0)
// CHECK-LABEL: define void @x(
func.func @x(%arr : !fir.ref<!fir.array<10xf32>>) {
%1 = arith.constant 0 : index
%2 = arith.constant 9 : index

View File

@ -1,7 +1,7 @@
// RUN: tco %s | FileCheck %s
// CHECK-LABEL: define void @f1
// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:[^,]*]], {{.*}}, float %[[F:.*]])
func.func @f1(%a : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
%c1 = arith.constant 1 : index
%s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
@ -23,7 +23,7 @@ func.func @f1(%a : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : i
}
// CHECK-LABEL: define void @f2
// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:[^,]*]], {{.*}}, float %[[F:.*]])
func.func @f2(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
%c1 = arith.constant 1 : index
%s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
@ -47,7 +47,7 @@ func.func @f2(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf
}
// CHECK-LABEL: define void @f3
// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:[^,]*]], {{.*}}, float %[[F:.*]])
func.func @f3(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
%c1 = arith.constant 1 : index
%s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
@ -72,7 +72,7 @@ func.func @f3(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf
}
// CHECK-LABEL: define void @f4
// CHECK: (ptr captures(none) %[[A:[^,]*]], {{.*}}, float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:[^,]*]], {{.*}}, float %[[F:.*]])
func.func @f4(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf32>>, %n : index, %m : index, %o : index, %p : index, %f : f32) {
%c1 = arith.constant 1 : index
%s = fir.shape_shift %o, %n, %p, %m : (index, index, index, index) -> !fir.shapeshift<2>
@ -102,7 +102,7 @@ func.func @f4(%a : !fir.ref<!fir.array<?x?xf32>>, %b : !fir.ref<!fir.array<?x?xf
// `a = b + f`, with and v assumed shapes.
// Tests that the stride from the descriptor is used.
// CHECK-LABEL: define void @f5
// CHECK: (ptr %[[A:.*]], ptr %[[B:.*]], float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:.*]], ptr {{[^%]*}}%[[B:.*]], float %[[F:.*]])
func.func @f5(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: !fir.box<!fir.array<?xf32>>, %arg2: f32) {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
@ -135,7 +135,7 @@ func.func @f5(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: !fir.box<!fir.array<?xf
// contiguous array (e.g. `a(2:10:1) = a(1:9:1) + f`, with a assumed shape).
// Test that a temp is created.
// CHECK-LABEL: define void @f6
// CHECK: (ptr %[[A:[^,]*]], float %[[F:.*]])
// CHECK: (ptr {{[^%]*}}%[[A:[^,]*]], float %[[F:.*]])
func.func @f6(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: f32) {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
@ -165,7 +165,7 @@ func.func @f6(%arg0: !fir.box<!fir.array<?xf32>>, %arg1: f32) {
// Non contiguous array with lower bounds (x = y(100), with y(4:))
// Test array_coor offset computation.
// CHECK-LABEL: define void @f7(
// CHECK: ptr captures(none) %[[X:[^,]*]], ptr %[[Y:.*]])
// CHECK: ptr {{[^%]*}}%[[X:[^,]*]], ptr {{[^%]*}}%[[Y:.*]])
func.func @f7(%arg0: !fir.ref<f32>, %arg1: !fir.box<!fir.array<?xf32>>) {
%c4 = arith.constant 4 : index
%c100 = arith.constant 100 : index
@ -181,7 +181,7 @@ func.func @f7(%arg0: !fir.ref<f32>, %arg1: !fir.box<!fir.array<?xf32>>) {
// Test A(:, :)%x reference codegen with A constant shape.
// CHECK-LABEL: define void @f8(
// CHECK-SAME: ptr captures(none) %[[A:.*]], i32 %[[I:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[A:.*]], i32 %[[I:.*]])
func.func @f8(%a : !fir.ref<!fir.array<2x2x!fir.type<t{i:i32}>>>, %i : i32) {
%c0 = arith.constant 0 : index
%c1 = arith.constant 1 : index
@ -198,7 +198,7 @@ func.func @f8(%a : !fir.ref<!fir.array<2x2x!fir.type<t{i:i32}>>>, %i : i32) {
// Test casts in in array_coor offset computation when type parameters are not i64
// CHECK-LABEL: define ptr @f9(
// CHECK-SAME: i32 %[[I:.*]], i64 %{{.*}}, i64 %{{.*}}, ptr captures(none) %[[C:.*]])
// CHECK-SAME: i32 %[[I:.*]], i64 %{{.*}}, i64 %{{.*}}, ptr {{[^%]*}}%[[C:.*]])
func.func @f9(%i: i32, %e : i64, %j: i64, %c: !fir.ref<!fir.array<?x?x!fir.char<1,?>>>) -> !fir.ref<!fir.char<1,?>> {
%s = fir.shape %e, %e : (i64, i64) -> !fir.shape<2>
// CHECK: %[[CAST:.*]] = sext i32 %[[I]] to i64

View File

@ -7,7 +7,7 @@ func.func @scalar_addr(%scalar : !fir.ref<!fir.box<!fir.type<t>>>) -> !fir.llvm_
return %addr : !fir.llvm_ptr<!fir.ref<!fir.type<t>>>
}
// CHECK-LABEL: define ptr @scalar_addr(
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[BOX:.*]]){{.*}}{
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 0
// CHECK: ret ptr %[[VAL_0]]
@ -16,7 +16,7 @@ func.func @scalar_tdesc(%scalar : !fir.ref<!fir.box<!fir.type<t>>>) -> !fir.llvm
return %tdesc : !fir.llvm_ptr<!fir.tdesc<!fir.type<t>>>
}
// CHECK-LABEL: define ptr @scalar_tdesc(
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[BOX:.*]]){{.*}}{
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 7
// CHECK: ret ptr %[[VAL_0]]
@ -25,7 +25,7 @@ func.func @array_addr(%array : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.ty
return %addr : !fir.llvm_ptr<!fir.ptr<!fir.array<?x!fir.type<t>>>>
}
// CHECK-LABEL: define ptr @array_addr(
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[BOX:.*]]){{.*}}{
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 0
// CHECK: ret ptr %[[VAL_0]]
@ -34,6 +34,6 @@ func.func @array_tdesc(%array : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.t
return %tdesc : !fir.llvm_ptr<!fir.tdesc<!fir.type<t>>>
}
// CHECK-LABEL: define ptr @array_tdesc(
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[BOX:.*]]){{.*}}{
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 8
// CHECK: ret ptr %[[VAL_0]]

View File

@ -6,7 +6,7 @@ func.func @test_box_typecode(%a: !fir.class<none>) -> i32 {
}
// CHECK-LABEL: @test_box_typecode(
// CHECK-SAME: ptr %[[BOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[BOX:.*]])
// CHECK: %[[GEP:.*]] = getelementptr { ptr, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}}, i{{.*}} }, ptr %[[BOX]], i32 0, i32 4
// CHECK: %[[TYPE_CODE:.*]] = load i8, ptr %[[GEP]]
// CHECK: %[[TYPE_CODE_CONV:.*]] = sext i8 %[[TYPE_CODE]] to i32

View File

@ -24,7 +24,7 @@ func.func private @g(%b : !fir.box<f32>)
func.func private @ga(%b : !fir.box<!fir.array<?xf32>>)
// CHECK-LABEL: define void @f
// CHECK: (ptr captures(none) %[[ARG:.*]])
// CHECK: (ptr {{[^%]*}}%[[ARG:.*]])
func.func @f(%a : !fir.ref<f32>) {
// CHECK: %[[DESC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
// CHECK: %[[INS0:.*]] = insertvalue {{.*}} { ptr undef, i64 4, i32 20240719, i8 0, i8 27, i8 0, i8 0 }, ptr %[[ARG]], 0
@ -38,7 +38,7 @@ func.func @f(%a : !fir.ref<f32>) {
}
// CHECK-LABEL: define void @fa
// CHECK: (ptr captures(none) %[[ARG:.*]])
// CHECK: (ptr {{[^%]*}}%[[ARG:.*]])
func.func @fa(%a : !fir.ref<!fir.array<100xf32>>) {
%c = fir.convert %a : (!fir.ref<!fir.array<100xf32>>) -> !fir.ref<!fir.array<?xf32>>
%c1 = arith.constant 1 : index
@ -54,7 +54,7 @@ func.func @fa(%a : !fir.ref<!fir.array<100xf32>>) {
// Boxing of a scalar character of dynamic length
// CHECK-LABEL: define void @b1(
// CHECK-SAME: ptr captures(none) %[[res:.*]], ptr captures(none) %[[arg0:.*]], i64 %[[arg1:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[res:.*]], ptr {{[^%]*}}%[[arg0:.*]], i64 %[[arg1:.*]])
func.func @b1(%arg0 : !fir.ref<!fir.char<1,?>>, %arg1 : index) -> !fir.box<!fir.char<1,?>> {
// CHECK: %[[alloca:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8 }
// CHECK: %[[size:.*]] = mul i64 1, %[[arg1]]
@ -69,8 +69,8 @@ func.func @b1(%arg0 : !fir.ref<!fir.char<1,?>>, %arg1 : index) -> !fir.box<!fir.
// Boxing of a dynamic array of character with static length (5)
// CHECK-LABEL: define void @b2(
// CHECK-SAME: ptr captures(none) %[[res]],
// CHECK-SAME: ptr captures(none) %[[arg0:.*]], i64 %[[arg1:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[res]],
// CHECK-SAME: ptr {{[^%]*}}%[[arg0:.*]], i64 %[[arg1:.*]])
func.func @b2(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,5>>>, %arg1 : index) -> !fir.box<!fir.array<?x!fir.char<1,5>>> {
%1 = fir.shape %arg1 : (index) -> !fir.shape<1>
// CHECK: %[[alloca:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
@ -85,7 +85,7 @@ func.func @b2(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,5>>>, %arg1 : index) ->
// Boxing of a dynamic array of character of dynamic length
// CHECK-LABEL: define void @b3(
// CHECK-SAME: ptr captures(none) %[[res:.*]], ptr captures(none) %[[arg0:.*]], i64 %[[arg1:.*]], i64 %[[arg2:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[res:.*]], ptr {{[^%]*}}%[[arg0:.*]], i64 %[[arg1:.*]], i64 %[[arg2:.*]])
func.func @b3(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,?>>>, %arg1 : index, %arg2 : index) -> !fir.box<!fir.array<?x!fir.char<1,?>>> {
%1 = fir.shape %arg2 : (index) -> !fir.shape<1>
// CHECK: %[[alloca:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
@ -103,7 +103,7 @@ func.func @b3(%arg0 : !fir.ref<!fir.array<?x!fir.char<1,?>>>, %arg1 : index, %ar
// Boxing of a static array of character of dynamic length
// CHECK-LABEL: define void @b4(
// CHECK-SAME: ptr captures(none) %[[res:.*]], ptr captures(none) %[[arg0:.*]], i64 %[[arg1:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[res:.*]], ptr {{[^%]*}}%[[arg0:.*]], i64 %[[arg1:.*]])
func.func @b4(%arg0 : !fir.ref<!fir.array<7x!fir.char<1,?>>>, %arg1 : index) -> !fir.box<!fir.array<7x!fir.char<1,?>>> {
%c_7 = arith.constant 7 : index
%1 = fir.shape %c_7 : (index) -> !fir.shape<1>
@ -122,7 +122,7 @@ func.func @b4(%arg0 : !fir.ref<!fir.array<7x!fir.char<1,?>>>, %arg1 : index) ->
// Storing a fir.box into a fir.ref<fir.box> (modifying descriptors).
// CHECK-LABEL: define void @b5(
// CHECK-SAME: ptr captures(none) %[[arg0:.*]], ptr %[[arg1:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[arg0:.*]], ptr {{[^%]*}}%[[arg1:.*]])
func.func @b5(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xf32>>>>, %arg1 : !fir.box<!fir.heap<!fir.array<?x?xf32>>>) {
fir.store %arg1 to %arg0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xf32>>>>
// CHECK: call void @llvm.memcpy.p0.p0.i32(ptr %0, ptr %1, i32 72, i1 false)
@ -132,7 +132,7 @@ func.func @b5(%arg0 : !fir.ref<!fir.box<!fir.heap<!fir.array<?x?xf32>>>>, %arg1
func.func private @callee6(!fir.box<none>) -> i32
// CHECK-LABEL: define i32 @box6(
// CHECK-SAME: ptr captures(none) %[[ARG0:.*]], i64 %[[ARG1:.*]], i64 %[[ARG2:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[ARG0:.*]], i64 %[[ARG1:.*]], i64 %[[ARG2:.*]])
func.func @box6(%0 : !fir.ref<!fir.array<?x?x?x?xf32>>, %1 : index, %2 : index) -> i32 {
%c100 = arith.constant 100 : index
%c50 = arith.constant 50 : index

View File

@ -16,7 +16,7 @@
// CHECK: call void @_QPtest_proc_dummy_other(ptr %[[VAL_6]])
// CHECK-LABEL: define void @_QFtest_proc_dummyPtest_proc_dummy_a(ptr
// CHECK-SAME: captures(none) %[[VAL_0:.*]], ptr nest captures(none) %[[VAL_1:.*]])
// CHECK-SAME: {{[^%]*}}%[[VAL_0:.*]], ptr nest {{[^%]*}}%[[VAL_1:.*]])
// CHECK-LABEL: define void @_QPtest_proc_dummy_other(ptr
// CHECK-SAME: %[[VAL_0:.*]])
@ -92,7 +92,7 @@ func.func @_QPtest_proc_dummy_other(%arg0: !fir.boxproc<() -> ()>) {
// CHECK: call void @llvm.stackrestore.p0(ptr %[[VAL_27]])
// CHECK-LABEL: define { ptr, i64 } @_QFtest_proc_dummy_charPgen_message(ptr
// CHECK-SAME: captures(none) %[[VAL_0:.*]], i64 %[[VAL_1:.*]], ptr nest captures(none) %[[VAL_2:.*]])
// CHECK-SAME: {{[^%]*}}%[[VAL_0:.*]], i64 %[[VAL_1:.*]], ptr nest {{[^%]*}}%[[VAL_2:.*]])
// CHECK: %[[VAL_3:.*]] = getelementptr { { ptr, i64 } }, ptr %[[VAL_2]], i32 0, i32 0
// CHECK: %[[VAL_4:.*]] = load { ptr, i64 }, ptr %[[VAL_3]], align 8
// CHECK: %[[VAL_5:.*]] = extractvalue { ptr, i64 } %[[VAL_4]], 0

View File

@ -11,7 +11,7 @@ func.func @f1(%a : i32, %b : i32) -> i32 {
return %3 : i32
}
// CHECK-LABEL: define i32 @f2(ptr captures(none) %0)
// CHECK-LABEL: define i32 @f2(ptr {{[^%]*}}%0)
func.func @f2(%a : !fir.ref<i32>) -> i32 {
%1 = fir.load %a : !fir.ref<i32>
// CHECK: %[[r2:.*]] = load

View File

@ -62,7 +62,7 @@ func.func @foo5(%box : !fir.box<!fir.ptr<!fir.array<?xi32>>>, %i : index) -> i32
}
// CHECK-LABEL: @foo6
// CHECK-SAME: (ptr %[[box:.*]], i64 %{{.*}}, ptr captures(none) %{{.*}})
// CHECK-SAME: (ptr {{[^%]*}}%[[box:.*]], i64 %{{.*}}, ptr {{[^%]*}}%{{.*}})
func.func @foo6(%box : !fir.box<!fir.ptr<!fir.array<?x!fir.char<1>>>>, %i : i64 , %res : !fir.ref<!fir.char<1>>) {
// CHECK: %[[addr_gep:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[box]], i32 0, i32 0
// CHECK: %[[addr:.*]] = load ptr, ptr %[[addr_gep]]

View File

@ -2,7 +2,7 @@
// RUN: %flang_fc1 -mmlir -disable-external-name-interop -emit-llvm %s -o -| FileCheck %s
// CHECK-LABEL: define void @_QPtest_callee(ptr %0)
// CHECK-LABEL: define void @_QPtest_callee(
func.func @_QPtest_callee(%arg0: !fir.box<!fir.array<?xi32>>) {
return
}
@ -29,7 +29,7 @@ func.func @_QPtest_slice() {
return
}
// CHECK-LABEL: define void @_QPtest_dt_callee(ptr %0)
// CHECK-LABEL: define void @_QPtest_dt_callee(
func.func @_QPtest_dt_callee(%arg0: !fir.box<!fir.array<?xi32>>) {
return
}
@ -63,7 +63,7 @@ func.func @_QPtest_dt_slice() {
func.func private @takesRank2CharBox(!fir.box<!fir.array<?x?x!fir.char<1,?>>>)
// CHECK-LABEL: define void @emboxSubstring(
// CHECK-SAME: ptr captures(none) %[[arg0:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[arg0:.*]])
func.func @emboxSubstring(%arg0: !fir.ref<!fir.array<2x3x!fir.char<1,4>>>) {
%c2 = arith.constant 2 : index
%c3 = arith.constant 3 : index
@ -84,7 +84,7 @@ func.func @emboxSubstring(%arg0: !fir.ref<!fir.array<2x3x!fir.char<1,4>>>) {
func.func private @do_something(!fir.box<!fir.array<?xf32>>) -> ()
// CHECK: define void @fir_dev_issue_1416
// CHECK-SAME: ptr captures(none) %[[base_addr:.*]], i64 %[[low:.*]], i64 %[[up:.*]], i64 %[[at:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[base_addr:.*]], i64 %[[low:.*]], i64 %[[up:.*]], i64 %[[at:.*]])
func.func @fir_dev_issue_1416(%arg0: !fir.ref<!fir.array<40x?xf32>>, %low: index, %up: index, %at : index) {
// Test fir.embox with a constant interior array shape.
%c1 = arith.constant 1 : index

View File

@ -7,7 +7,7 @@
// CHECK-DAG: %[[c:.*]] = type { float, %[[b]] }
// CHECK-LABEL: @simple_field
// CHECK-SAME: (ptr captures(none) %[[arg0:.*]])
// CHECK-SAME: (ptr {{[^%]*}}%[[arg0:.*]])
func.func @simple_field(%arg0: !fir.ref<!fir.type<a{x:f32,i:i32}>>) -> i32 {
// CHECK: %[[GEP:.*]] = getelementptr %a, ptr %[[arg0]], i32 0, i32 1
%2 = fir.coordinate_of %arg0, i : (!fir.ref<!fir.type<a{x:f32,i:i32}>>) -> !fir.ref<i32>
@ -17,7 +17,7 @@ func.func @simple_field(%arg0: !fir.ref<!fir.type<a{x:f32,i:i32}>>) -> i32 {
}
// CHECK-LABEL: @derived_field
// CHECK-SAME: (ptr captures(none) %[[arg0:.*]])
// CHECK-SAME: (ptr {{[^%]*}}%[[arg0:.*]])
func.func @derived_field(%arg0: !fir.ref<!fir.type<c{x:f32,some_b:!fir.type<b{x:f32,i:i32}>}>>) -> i32 {
// CHECK: %[[GEP:.*]] = getelementptr %c, ptr %[[arg0]], i32 0, i32 1, i32 1
%3 = fir.coordinate_of %arg0, some_b, i : (!fir.ref<!fir.type<c{x:f32,some_b:!fir.type<b{x:f32,i:i32}>}>>) -> !fir.ref<i32>

View File

@ -15,7 +15,7 @@ func.func @test_embox(%addr: !fir.ref<!some_freestyle_type>) {
return
}
// CHECK-LABEL: define void @test_embox(
// CHECK-SAME: ptr captures(none) %[[ADDR:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[ADDR:.*]])
// CHECK: insertvalue { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }
// CHECK-SAME: { ptr undef, i64 4,
// CHECK-SAME: i32 20240719, i8 0, i8 42, i8 0, i8 1, ptr null, [1 x i64] zeroinitializer },

View File

@ -86,7 +86,7 @@ func.func @_QMunlimitedPsub1(%arg0: !fir.class<!fir.array<?xnone>> {fir.bindc_na
}
// CHECK-LABEL: define void @_QMunlimitedPsub1(
// CHECK-SAME: ptr %[[ARRAY:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[ARRAY:.*]]){{.*}}{
// CHECK: %[[BOX:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, ptr, [1 x i64] }
// CHECK: %{{.}} = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ARRAY]], i32 0, i32 7, i32 0, i32 2
// CHECK: %[[TYPE_DESC_GEP:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[ARRAY]], i32 0, i32 8

View File

@ -9,7 +9,7 @@
func.func private @bar1(!fir.box<!fir.array<?xf32>>)
// CHECK-LABEL: define void @test_rebox_1(
// CHECK-SAME: ptr %[[INBOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INBOX:.*]])
func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
// CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
%c2 = arith.constant 2 : index
@ -54,7 +54,7 @@ func.func @test_rebox_1(%arg0: !fir.box<!fir.array<?x?xf32>>) {
func.func private @bar_rebox_test2(!fir.box<!fir.array<?x?x!fir.char<1,?>>>)
// CHECK-LABEL: define void @test_rebox_2(
// CHECK-SAME: ptr %[[INBOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INBOX:.*]])
func.func @test_rebox_2(%arg0: !fir.box<!fir.array<?x?x!fir.char<1,?>>>) {
%c1 = arith.constant 1 : index
%c4 = arith.constant 4 : index
@ -82,7 +82,7 @@ func.func @test_rebox_2(%arg0: !fir.box<!fir.array<?x?x!fir.char<1,?>>>) {
func.func private @bar_rebox_test3(!fir.box<!fir.array<?x?x?xf32>>)
// CHECK-LABEL: define void @test_rebox_3(
// CHECK-SAME: ptr %[[INBOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INBOX:.*]])
func.func @test_rebox_3(%arg0: !fir.box<!fir.array<?xf32>>) {
// CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [3 x [3 x i64]] }
%c2 = arith.constant 2 : index
@ -116,7 +116,7 @@ func.func @test_rebox_3(%arg0: !fir.box<!fir.array<?xf32>>) {
// time constant length.
// CHECK-LABEL: define void @test_rebox_4(
// CHECK-SAME: ptr %[[INPUT:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INPUT:.*]])
func.func @test_rebox_4(%arg0: !fir.box<!fir.array<?x!fir.char<1,?>>>) {
// CHECK: %[[NEWBOX_STORAGE:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
// CHECK: %[[EXTENT_GEP:.*]] = getelementptr {{{.*}}}, ptr %[[INPUT]], i32 0, i32 7, i32 0, i32 1
@ -144,7 +144,7 @@ func.func private @bar_test_rebox_4(!fir.box<!fir.ptr<!fir.array<?x!fir.char<1,1
// end subroutine
// CHECK-LABEL: define void @test_cmplx_1(
// CHECK-SAME: ptr %[[INBOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INBOX:.*]])
func.func @test_cmplx_1(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) {
// CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
%c1 = arith.constant 1 : index
@ -184,7 +184,7 @@ func.func @test_cmplx_1(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) {
// end subroutine
// CHECK-LABEL: define void @test_cmplx_2(
// CHECK-SAME: ptr %[[INBOX:.*]])
// CHECK-SAME: ptr {{[^%]*}}%[[INBOX:.*]])
func.func @test_cmplx_2(%arg0: !fir.box<!fir.array<?xcomplex<f32>>>) {
// CHECK: %[[OUTBOX_ALLOC:.*]] = alloca { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }
%c7 = arith.constant 7 : index

View File

@ -80,27 +80,27 @@ func.func @not_enough_int_reg_3(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: i32,
}
}
// CHECK: define void @takes_toobig(ptr byval(%toobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @takes_toobig_align16(ptr byval(%toobig_align16) align 16 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_1b(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}}, ptr byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_2(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%fits_in_2_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @ftakes_toobig(ptr byval(%ftoobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @ftakes_toobig_align16(ptr byval(%ftoobig_align16) align 16 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1b(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, ptr byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1c(double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, ptr byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_2(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr byval(%fits_in_2_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_contains_x87(ptr byval(%contains_x87) align 16 captures(none) %{{.*}}) {
// CHECK: define void @test_contains_complex_x87(ptr byval(%contains_complex_x87) align 16 captures(none) %{{.*}}) {
// CHECK: define void @test_nested_toobig(ptr byval(%nested_toobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_badly_aligned(ptr byval(%badly_aligned) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_logical_toobig(ptr byval(%logical_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @l_not_enough_int_reg(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%l_fits_in_2_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_complex_toobig(ptr byval(%complex_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @cplx_not_enough_sse_reg_1(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr byval(%cplx_fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_char_to_big(ptr byval(%char_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @char_not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%char_fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @mix_not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%mix_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @mix_not_enough_sse_reg_2(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr byval(%mix_in_1_int_reg_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_3(ptr sret({ fp128, fp128 }) align 16 captures(none) %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}})
// CHECK: define void @takes_toobig(ptr noalias byval(%toobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @takes_toobig_align16(ptr noalias byval(%toobig_align16) align 16 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_1b(ptr noalias captures(none) %{{.*}}, ptr noalias captures(none) %{{.*}}, ptr noalias captures(none) %{{.*}}, ptr noalias captures(none) %{{.*}}, ptr noalias captures(none) %{{.*}}, ptr noalias captures(none) %{{.*}}, ptr noalias byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_2(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%fits_in_2_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @ftakes_toobig(ptr noalias byval(%ftoobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @ftakes_toobig_align16(ptr noalias byval(%ftoobig_align16) align 16 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr noalias byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1b(<2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, <2 x float> %{{.*}}, ptr noalias byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_1c(double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, double %{{.*}}, ptr noalias byval(%fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_sse_reg_2(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr noalias byval(%fits_in_2_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_contains_x87(ptr noalias byval(%contains_x87) align 16 captures(none) %{{.*}}) {
// CHECK: define void @test_contains_complex_x87(ptr noalias byval(%contains_complex_x87) align 16 captures(none) %{{.*}}) {
// CHECK: define void @test_nested_toobig(ptr noalias byval(%nested_toobig) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_badly_aligned(ptr noalias byval(%badly_aligned) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_logical_toobig(ptr noalias byval(%logical_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @l_not_enough_int_reg(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%l_fits_in_2_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_complex_toobig(ptr noalias byval(%complex_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @cplx_not_enough_sse_reg_1(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr noalias byval(%cplx_fits_in_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @test_char_to_big(ptr noalias byval(%char_too_big) align 8 captures(none) %{{.*}}) {
// CHECK: define void @char_not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%char_fits_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @mix_not_enough_int_reg_1(i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%mix_in_1_int_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @mix_not_enough_sse_reg_2(float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, float %{{.*}}, ptr noalias byval(%mix_in_1_int_reg_1_sse_reg) align 8 captures(none) %{{.*}}) {
// CHECK: define void @not_enough_int_reg_3(ptr noalias sret({ fp128, fp128 }) align 16 captures(none) %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, i32 %{{.*}}, ptr noalias byval(%fits_in_1_int_reg) align 8 captures(none) %{{.*}})

View File

@ -30,5 +30,5 @@ func.func @takecomplex10(%z: complex<f80>) {
// AMD64: %[[VAL_3:.*]] = fir.alloca complex<f80>
// AMD64: fir.store %[[VAL_2]] to %[[VAL_3]] : !fir.ref<complex<f80>>
// AMD64_LLVM: define void @takecomplex10(ptr byval({ x86_fp80, x86_fp80 }) align 16 captures(none) %0)
// AMD64_LLVM: define void @takecomplex10(ptr noalias byval({ x86_fp80, x86_fp80 }) align 16 captures(none) %0)
}

View File

@ -26,7 +26,7 @@ func.func @gen4() -> complex<f32> {
return %6 : complex<f32>
}
// I32-LABEL: define void @gen8(ptr sret({ double, double }) align 4 captures(none) %
// I32-LABEL: define void @gen8(ptr noalias sret({ double, double }) align 4 captures(none) %
// X64-LABEL: define { double, double } @gen8()
// AARCH64-LABEL: define { double, double } @gen8()
// PPC-LABEL: define { double, double } @gen8()
@ -93,9 +93,9 @@ func.func @call8() {
return
}
// I32-LABEL: define i64 @char1lensum(ptr captures(none) %0, ptr captures(none) %1, i32 %2, i32 %3)
// X64-LABEL: define i64 @char1lensum(ptr captures(none) %0, ptr captures(none) %1, i64 %2, i64 %3)
// PPC-LABEL: define i64 @char1lensum(ptr captures(none) %0, ptr captures(none) %1, i64 %2, i64 %3)
// I32-LABEL: define i64 @char1lensum(ptr {{[^%]*}}%0, ptr {{[^%]*}}%1, i32 %2, i32 %3)
// X64-LABEL: define i64 @char1lensum(ptr {{[^%]*}}%0, ptr {{[^%]*}}%1, i64 %2, i64 %3)
// PPC-LABEL: define i64 @char1lensum(ptr {{[^%]*}}%0, ptr {{[^%]*}}%1, i64 %2, i64 %3)
func.func @char1lensum(%arg0 : !fir.boxchar<1>, %arg1 : !fir.boxchar<1>) -> i64 {
// X64-DAG: %[[p0:.*]] = insertvalue { ptr, i64 } undef, ptr %1, 0
// X64-DAG: = insertvalue { ptr, i64 } %[[p0]], i64 %3, 1

View File

@ -28,7 +28,7 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.targ
}
// CHECK-LABEL: define void @_QPsimple(
// CHECK-SAME: ptr %[[ARG0:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[ARG0:.*]]){{.*}}{
// [...]
// load a(2):
// CHECK: %[[VAL20:.*]] = getelementptr i8, ptr %{{.*}}, i64 %{{.*}}

View File

@ -60,7 +60,7 @@ module attributes {fir.defaultkind = "a1c4d8i4l4r4", fir.kindmap = "", llvm.targ
}
}
// CHECK-LABEL: define void @_QPfunc(
// CHECK-SAME: ptr %[[ARG0:.*]]){{.*}}{
// CHECK-SAME: ptr {{[^%]*}}%[[ARG0:.*]]){{.*}}{
// [...]
// CHECK: %[[VAL5:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]] }, ptr %[[ARG0]], i32 0, i32 7, i32 0, i32 0
// box access:

View File

@ -8,25 +8,25 @@
!RUN: %flang_fc1 -emit-llvm -fopenmp %s -o - | FileCheck %s
!CHECK-DAG: define internal void @_copy_box_Uxi32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xi32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_i64(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_Uxi64(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_f32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_2x3xf32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_z32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xz32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_l32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_5xl32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_c8x8(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xc8x8(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_c16x5(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_rec__QFtest_typesTdt(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_heap_Uxi32(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_ptr_Uxc8x9(ptr captures(none) %{{.*}}, ptr captures(none) %{{.*}})
!CHECK-DAG: define internal void @_copy_box_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_i64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_Uxi64(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_f32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_2x3xf32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_z32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xz32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_l32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_5xl32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_c8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_10xc8x8(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_c16x5(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_rec__QFtest_typesTdt(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_heap_Uxi32(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-DAG: define internal void @_copy_box_ptr_Uxc8x9(ptr {{[^%]*}}%{{.*}}, ptr {{[^%]*}}%{{.*}})
!CHECK-LABEL: define internal void @_copy_i32(
!CHECK-SAME: ptr captures(none) %[[DST:.*]], ptr captures(none) %[[SRC:.*]]){{.*}} {
!CHECK-SAME: ptr {{[^%]*}}%[[DST:.*]], ptr {{[^%]*}}%[[SRC:.*]]){{.*}} {
!CHECK-NEXT: %[[SRC_VAL:.*]] = load i32, ptr %[[SRC]]
!CHECK-NEXT: store i32 %[[SRC_VAL]], ptr %[[DST]]
!CHECK-NEXT: ret void

View File

@ -20,7 +20,7 @@
! BOTH-LABEL: }
! BOTH-LABEL: define {{.*}}i64 @_QFPfn1
! BOTH-SAME: (ptr captures(none) %[[ARG1:.*]], ptr captures(none) %[[ARG2:.*]], ptr captures(none) %[[ARG3:.*]])
! BOTH-SAME: (ptr {{[^%]*}}%[[ARG1:.*]], ptr {{[^%]*}}%[[ARG2:.*]], ptr {{[^%]*}}%[[ARG3:.*]])
! RECORDS-DAG: #dbg_declare(ptr %[[ARG1]], ![[A1:.*]], !DIExpression(), !{{.*}})
! RECORDS-DAG: #dbg_declare(ptr %[[ARG2]], ![[B1:.*]], !DIExpression(), !{{.*}})
! RECORDS-DAG: #dbg_declare(ptr %[[ARG3]], ![[C1:.*]], !DIExpression(), !{{.*}})
@ -29,7 +29,7 @@
! BOTH-LABEL: }
! BOTH-LABEL: define {{.*}}i32 @_QFPfn2
! BOTH-SAME: (ptr captures(none) %[[FN2ARG1:.*]], ptr captures(none) %[[FN2ARG2:.*]], ptr captures(none) %[[FN2ARG3:.*]])
! BOTH-SAME: (ptr {{[^%]*}}%[[FN2ARG1:.*]], ptr {{[^%]*}}%[[FN2ARG2:.*]], ptr {{[^%]*}}%[[FN2ARG3:.*]])
! RECORDS-DAG: #dbg_declare(ptr %[[FN2ARG1]], ![[A2:.*]], !DIExpression(), !{{.*}})
! RECORDS-DAG: #dbg_declare(ptr %[[FN2ARG2]], ![[B2:.*]], !DIExpression(), !{{.*}})
! RECORDS-DAG: #dbg_declare(ptr %[[FN2ARG3]], ![[C2:.*]], !DIExpression(), !{{.*}})

View File

@ -13,7 +13,7 @@
! RUN: %if x86-registered-target %{ %{check-nounroll} %}
!
! CHECK-LABEL: @unroll
! CHECK-SAME: (ptr writeonly captures(none) %[[ARG0:.*]])
! CHECK-SAME: (ptr {{[^%]*}}%[[ARG0:.*]])
subroutine unroll(a)
integer(kind=8), intent(out) :: a(1000)
integer(kind=8) :: i

View File

@ -11,7 +11,7 @@
// RUN: %if x86-registered-target %{ %{check-nounroll} %}
// CHECK-LABEL: @unroll
// CHECK-SAME: (ptr writeonly captures(none) %[[ARG0:.*]])
// CHECK-SAME: (ptr {{[^%]*}}%[[ARG0:.*]])
func.func @unroll(%arg0: !fir.ref<!fir.array<1000 x index>> {fir.bindc_name = "a"}) {
%scope = fir.dummy_scope : !fir.dscope
%c1000 = arith.constant 1000 : index

View File

@ -22,7 +22,7 @@ contains
end program test
! CHECK-LABEL: define internal void @_QFPsub(
! CHECK-SAME: ptr %[[arg:.*]])
! CHECK-SAME: ptr {{[^%]*}}%[[arg:.*]])
! CHECK: %[[extent:.*]] = getelementptr { {{.*}}, [1 x [3 x i64]] }, ptr %[[arg]], i32 0, i32 7, i64 0, i32 1
! CHECK: %[[extval:.*]] = load i64, ptr %[[extent]]
! CHECK: %[[elesize:.*]] = getelementptr { {{.*}}, [1 x [3 x i64]] }, ptr %[[arg]], i32 0, i32 1

View File

@ -49,8 +49,8 @@ module {
// DISABLE-LABEL: ; ModuleID =
// DISABLE-NOT: @_extruded
// DISABLE: define void @sub1(
// DISABLE-SAME: ptr captures(none) [[ARG0:%.*]],
// DISABLE-SAME: ptr captures(none) [[ARG1:%.*]])
// DISABLE-SAME: ptr {{[^%]*}}[[ARG0:%.*]],
// DISABLE-SAME: ptr {{[^%]*}}[[ARG1:%.*]])
// DISABLE-SAME: {
// DISABLE: [[CONST_R0:%.*]] = alloca double
// DISABLE: [[CONST_R1:%.*]] = alloca double

View File

@ -0,0 +1,113 @@
// RUN: fir-opt --function-attr="set-noalias=true" %s | FileCheck %s
// Test the annotation of function arguments with llvm.noalias.
// Test !fir.ref arguments.
// CHECK-LABEL: func.func private @test_ref(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32> {llvm.noalias}) {
func.func private @test_ref(%arg0: !fir.ref<i32>) {
return
}
// CHECK-LABEL: func.func private @test_ref_target(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32> {fir.target}) {
func.func private @test_ref_target(%arg0: !fir.ref<i32> {fir.target}) {
return
}
// CHECK-LABEL: func.func private @test_ref_volatile(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32> {fir.volatile}) {
func.func private @test_ref_volatile(%arg0: !fir.ref<i32> {fir.volatile}) {
return
}
// CHECK-LABEL: func.func private @test_ref_asynchronous(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32> {fir.asynchronous}) {
func.func private @test_ref_asynchronous(%arg0: !fir.ref<i32> {fir.asynchronous}) {
return
}
// CHECK-LABEL: func.func private @test_ref_box(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<i32>> {llvm.noalias}) {
// Test !fir.ref<!fir.box<>> arguments:
func.func private @test_ref_box(%arg0: !fir.ref<!fir.box<i32>>) {
return
}
// CHECK-LABEL: func.func private @test_ref_box_target(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<i32>> {fir.target}) {
func.func private @test_ref_box_target(%arg0: !fir.ref<!fir.box<i32>> {fir.target}) {
return
}
// CHECK-LABEL: func.func private @test_ref_box_volatile(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<i32>> {fir.volatile}) {
func.func private @test_ref_box_volatile(%arg0: !fir.ref<!fir.box<i32>> {fir.volatile}) {
return
}
// CHECK-LABEL: func.func private @test_ref_box_asynchronous(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<i32>> {fir.asynchronous}) {
func.func private @test_ref_box_asynchronous(%arg0: !fir.ref<!fir.box<i32>> {fir.asynchronous}) {
return
}
// Test POINTER arguments.
// CHECK-LABEL: func.func private @test_ref_box_ptr(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.ptr<i32>>>) {
func.func private @test_ref_box_ptr(%arg0: !fir.ref<!fir.box<!fir.ptr<i32>>>) {
return
}
// Test ALLOCATABLE arguments.
// CHECK-LABEL: func.func private @test_ref_box_heap(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<!fir.box<!fir.heap<i32>>> {llvm.noalias}) {
func.func private @test_ref_box_heap(%arg0: !fir.ref<!fir.box<!fir.heap<i32>>>) {
return
}
// BIND(C) functions are not annotated.
// CHECK-LABEL: func.func private @test_ref_bindc(
// CHECK-SAME: %[[ARG0:.*]]: !fir.ref<i32>)
func.func private @test_ref_bindc(%arg0: !fir.ref<i32>) attributes {fir.bindc_name = "test_ref_bindc", fir.proc_attrs = #fir.proc_attrs<bind_c>} {
return
}
// Test function declaration from a module.
// CHECK-LABEL: func.func private @_QMtest_modPcheck_module(
// CHECK-SAME: !fir.ref<i32> {llvm.noalias})
func.func private @_QMtest_modPcheck_module(!fir.ref<i32>)
// Test !fir.box arguments:
// CHECK-LABEL: func.func private @test_box(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {llvm.noalias}) {
func.func private @test_box(%arg0: !fir.box<i32>) {
return
}
// CHECK-LABEL: func.func private @test_box_target(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.target, llvm.noalias}) {
func.func private @test_box_target(%arg0: !fir.box<i32> {fir.target}) {
return
}
// CHECK-LABEL: func.func private @test_box_volatile(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.volatile, llvm.noalias}) {
func.func private @test_box_volatile(%arg0: !fir.box<i32> {fir.volatile}) {
return
}
// CHECK-LABEL: func.func private @test_box_asynchronous(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.asynchronous, llvm.noalias}) {
func.func private @test_box_asynchronous(%arg0: !fir.box<i32> {fir.asynchronous}) {
return
}
// !fir.boxchar<> is lowered before FunctionAttrPass, but let's
// make sure we do not annotate it.
// CHECK-LABEL: func.func private @test_boxchar(
// CHECK-SAME: %[[ARG0:.*]]: !fir.boxchar<1>) {
func.func private @test_boxchar(%arg0: !fir.boxchar<1>) {
return
}

View File

@ -1,4 +1,4 @@
// RUN: fir-opt --function-attr %s | FileCheck %s
// RUN: fir-opt --function-attr="set-nocapture=true" %s | FileCheck %s
// If a function has a body and is not bind(c), and if the dummy argument doesn't have the target,
// asynchronous, volatile, or pointer attribute, then add llvm.nocapture to the dummy argument.
@ -43,3 +43,28 @@ func.func private @_QMarg_modPcheck_args(!fir.ref<i32> {fir.target}, !fir.ref<i3
// CHECK-SAME: !fir.ref<i32> {llvm.nocapture},
// CHECK-SAME: !fir.boxchar<1>,
// CHECK-SAME: !fir.ref<complex<f32>> {llvm.nocapture})
// Test !fir.box arguments:
// CHECK-LABEL: func.func private @test_box(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {llvm.nocapture}) {
func.func private @test_box(%arg0: !fir.box<i32>) {
return
}
// CHECK-LABEL: func.func private @test_box_target(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.target, llvm.nocapture}) {
func.func private @test_box_target(%arg0: !fir.box<i32> {fir.target}) {
return
}
// CHECK-LABEL: func.func private @test_box_volatile(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.volatile, llvm.nocapture}) {
func.func private @test_box_volatile(%arg0: !fir.box<i32> {fir.volatile}) {
return
}
// CHECK-LABEL: func.func private @test_box_asynchronous(
// CHECK-SAME: %[[ARG0:.*]]: !fir.box<i32> {fir.asynchronous, llvm.nocapture}) {
func.func private @test_box_asynchronous(%arg0: !fir.box<i32> {fir.asynchronous}) {
return
}