- Change syntax for FuncOp to be `func <visibility>? @name` instead of printing the
visibility in the attribute dictionary.
- Since printFunctionLikeOp() and parseFunctionLikeOp() are also used by other
operations, make the "inline visibility" an opt-in feature.
- Updated unit test to use and check the new syntax.
Differential Revision: https://reviews.llvm.org/D90859
table, but not outside of the visible IR, as long as each symbol table
parent also defines a non-private symbol.
-A few examples of what this looks like in the IR are shown below:
+For Functions, the visibility is printed after the operation name without a
+quote. A few examples of what this looks like in the IR are shown below:
```mlir
module @public_module {
// This function can be accessed by 'live.user', but cannot be referenced
// externally; all uses are known to reside within parent regions.
- func @nested_function() attributes { sym_visibility = "nested" }
+ func nested @nested_function()
// This function cannot be accessed outside of 'public_module'.
- func @private_function() attributes { sym_visibility = "private" }
+ func private @private_function()
}
// This function can only be accessed from within the top-level module.
-func @private_function() attributes { sym_visibility = "private" }
+func private @private_function()
// This function may be referenced externally.
func @public_function()
/// whether the function is variadic. If the builder returns a null type,
/// `result` will not contain the `type` attribute. The caller can then add a
/// type, report the error or delegate the reporting to the op's verifier.
+/// If `allowInlineVisibility` is true, then the parser will allow visibility
+/// to be specified after the operation name. If the visibility is not specified
+/// there or `allowInlineVisibility` is false, visibility will be allowed in the
+/// attribute dict.
ParseResult parseFunctionLikeOp(OpAsmParser &parser, OperationState &result,
bool allowVariadic,
- FuncTypeBuilder funcTypeBuilder);
+ FuncTypeBuilder funcTypeBuilder,
+ bool allowInlineVisibility = false);
/// Printer implementation for function-like operations. Accepts lists of
-/// argument and result types to use while printing.
+/// argument and result types to use while printing. If `printVisibilityInline`
+/// is true, visibility is printed "inline" after the operation name and elided
+/// from the attributes dict. Otherwise, it is printed in the attribute dict.
void printFunctionLikeOp(OpAsmPrinter &p, Operation *op,
ArrayRef<Type> argTypes, bool isVariadic,
- ArrayRef<Type> resultTypes);
+ ArrayRef<Type> resultTypes,
+ bool printVisibilityInline = false);
/// Prints the signature of the function-like operation `op`. Assumes `op` has
/// the FunctionLike trait and passed the verification.
/// Parse a keyword, if present, into 'keyword'.
virtual ParseResult parseOptionalKeyword(StringRef *keyword) = 0;
+ /// Parse a keyword, if present, and if one of the 'allowedValues',
+ /// into 'keyword'
+ virtual ParseResult
+ parseOptionalKeyword(StringRef *keyword,
+ ArrayRef<StringRef> allowedValues) = 0;
+
/// Parse a `(` token.
virtual ParseResult parseLParen() = 0;
};
} // end namespace OpTrait
+
+//===----------------------------------------------------------------------===//
+// Visibility parsing implementation.
+//===----------------------------------------------------------------------===//
+
+namespace impl {
+/// Parse an optional visibility attribute keyword (i.e., public, private, or
+/// nested) without quotes in a string attribute named 'attrName'.
+ParseResult parseOptionalVisibilityKeyword(OpAsmParser &parser,
+ NamedAttrList &attrs);
+} // end namespace impl
+
} // end namespace mlir
/// Include the generated symbol interfaces.
For example, consider the following input:
```mlir
- func @dead_private_function() attributes { sym_visibility = "private" }
- func @live_private_function() attributes { sym_visibility = "private" }
+ func private @dead_private_function()
+ func private @live_private_function()
// Note: The `public` isn't necessary here, as this is the default.
- func @public_function() attributes { sym_visibility = "public" } {
+ func public @public_function() {
"foo.return"() {uses = [@live_private_function]} : () -> ()
}
```
are no links to known-live operations. After running, we get the expected:
```mlir
- func @live_private_function() attributes { sym_visibility = "private" }
+ func private @live_private_function()
- func @public_function() attributes { sym_visibility = "public" } {
+ func public @public_function() {
"foo.return"() {uses = [@live_private_function]} : () -> ()
}
```
};
return impl::parseFunctionLikeOp(parser, result, /*allowVariadic=*/false,
- buildFuncType);
+ buildFuncType,
+ /*allowInlineVisibility=*/true);
}
void FuncOp::print(OpAsmPrinter &p) {
FunctionType fnType = getType();
impl::printFunctionLikeOp(p, *this, fnType.getInputs(), /*isVariadic=*/false,
- fnType.getResults());
+ fnType.getResults(),
+ /*printVisibilityInline=*/true);
}
LogicalResult FuncOp::verify() {
/// Parser implementation for function-like operations. Uses `funcTypeBuilder`
/// to construct the custom function type given lists of input and output types.
-ParseResult
-mlir::impl::parseFunctionLikeOp(OpAsmParser &parser, OperationState &result,
- bool allowVariadic,
- mlir::impl::FuncTypeBuilder funcTypeBuilder) {
+ParseResult mlir::impl::parseFunctionLikeOp(
+ OpAsmParser &parser, OperationState &result, bool allowVariadic,
+ mlir::impl::FuncTypeBuilder funcTypeBuilder, bool allowInlineVisibility) {
SmallVector<OpAsmParser::OperandType, 4> entryArgs;
SmallVector<NamedAttrList, 4> argAttrs;
SmallVector<NamedAttrList, 4> resultAttrs;
SmallVector<Type, 4> resultTypes;
auto &builder = parser.getBuilder();
+ // Parse visibility if inline visibility is allowed.
+ if (allowInlineVisibility)
+ impl::parseOptionalVisibilityKeyword(parser, result.attributes);
+
// Parse the name as a symbol.
StringAttr nameAttr;
- if (parser.parseSymbolName(nameAttr, ::mlir::SymbolTable::getSymbolAttrName(),
+ if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),
result.attributes))
return failure();
/// argument and result types to use while printing.
void mlir::impl::printFunctionLikeOp(OpAsmPrinter &p, Operation *op,
ArrayRef<Type> argTypes, bool isVariadic,
- ArrayRef<Type> resultTypes) {
+ ArrayRef<Type> resultTypes,
+ bool printVisibilityInline) {
// Print the operation and the function name.
auto funcName =
- op->getAttrOfType<StringAttr>(::mlir::SymbolTable::getSymbolAttrName())
+ op->getAttrOfType<StringAttr>(SymbolTable::getSymbolAttrName())
.getValue();
p << op->getName() << ' ';
+ StringRef elidedAttr;
+ if (printVisibilityInline) {
+ elidedAttr = SymbolTable::getVisibilityAttrName();
+ if (auto visibility = op->getAttrOfType<StringAttr>(elidedAttr))
+ p << visibility.getValue() << ' ';
+ }
p.printSymbolName(funcName);
printFunctionSignature(p, op, argTypes, isVariadic, resultTypes);
- printFunctionAttributes(p, op, argTypes.size(), resultTypes.size());
-
+ printFunctionAttributes(p, op, argTypes.size(), resultTypes.size(),
+ {elidedAttr});
// Print the body if this is not an external function.
Region &body = op->getRegion(0);
if (!body.empty())
//===----------------------------------------------------------------------===//
#include "mlir/IR/SymbolTable.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/OpImplementation.h"
#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallString.h"
}
//===----------------------------------------------------------------------===//
+// Visibility parsing implementation.
+//===----------------------------------------------------------------------===//
+
+ParseResult impl::parseOptionalVisibilityKeyword(OpAsmParser &parser,
+ NamedAttrList &attrs) {
+ StringRef visibility;
+ if (parser.parseOptionalKeyword(&visibility, {"public", "private", "nested"}))
+ return failure();
+
+ StringAttr visibilityAttr = parser.getBuilder().getStringAttr(visibility);
+ attrs.push_back(parser.getBuilder().getNamedAttr(
+ SymbolTable::getVisibilityAttrName(), visibilityAttr));
+ return success();
+}
+
+//===----------------------------------------------------------------------===//
// Symbol Interfaces
//===----------------------------------------------------------------------===//
return success();
}
+ /// Parse a keyword if it is one of the 'allowedKeywords'.
+ ParseResult
+ parseOptionalKeyword(StringRef *keyword,
+ ArrayRef<StringRef> allowedKeywords) override {
+ // Check that the current token is a keyword.
+ if (!isCurrentTokenAKeyword())
+ return failure();
+
+ StringRef currentKeyword = parser.getTokenSpelling();
+ if (llvm::is_contained(allowedKeywords, currentKeyword)) {
+ *keyword = currentKeyword;
+ parser.consumeToken();
+ return success();
+ }
+
+ return failure();
+ }
+
/// Parse an optional @-identifier and store it (without the '@' symbol) in a
/// string attribute named 'attrName'.
ParseResult parseOptionalSymbolName(StringAttr &result, StringRef attrName,
}
// Function outlined from the async.execute operation.
-// CHECK-LABEL: func @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>)
-// CHECK-SAME: -> !llvm.ptr<i8> attributes {sym_visibility = "private"}
+// CHECK-LABEL: func private @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>)
+// CHECK-SAME: -> !llvm.ptr<i8>
// Create token for return op, and mark a function as a coroutine.
// CHECK: %[[RET:.*]] = call @mlirAsyncRuntimeCreateToken()
}
// Function outlined from the inner async.execute operation.
-// CHECK-LABEL: func @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>, %arg2: index)
-// CHECK-SAME: -> !llvm.ptr<i8> attributes {sym_visibility = "private"}
+// CHECK-LABEL: func private @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>, %arg2: index)
+// CHECK-SAME: -> !llvm.ptr<i8>
// CHECK: %[[RET_0:.*]] = call @mlirAsyncRuntimeCreateToken()
// CHECK: %[[HDL_0:.*]] = llvm.call @llvm.coro.begin
// CHECK: call @mlirAsyncRuntimeExecute
// CHECK: call @mlirAsyncRuntimeEmplaceToken(%[[RET_0]])
// Function outlined from the outer async.execute operation.
-// CHECK-LABEL: func @async_execute_fn_0(%arg0: f32, %arg1: memref<1xf32>, %arg2: f32)
-// CHECK-SAME: -> !llvm.ptr<i8> attributes {sym_visibility = "private"}
+// CHECK-LABEL: func private @async_execute_fn_0(%arg0: f32, %arg1: memref<1xf32>, %arg2: f32)
+// CHECK-SAME: -> !llvm.ptr<i8>
// CHECK: %[[RET_1:.*]] = call @mlirAsyncRuntimeCreateToken()
// CHECK: %[[HDL_1:.*]] = llvm.call @llvm.coro.begin
}
// Function outlined from the first async.execute operation.
-// CHECK-LABEL: func @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>)
-// CHECK-SAME: -> !llvm.ptr<i8> attributes {sym_visibility = "private"}
+// CHECK-LABEL: func private @async_execute_fn(%arg0: f32, %arg1: memref<1xf32>)
+// CHECK-SAME: -> !llvm.ptr<i8>
// CHECK: %[[RET_0:.*]] = call @mlirAsyncRuntimeCreateToken()
// CHECK: %[[HDL_0:.*]] = llvm.call @llvm.coro.begin
// CHECK: call @mlirAsyncRuntimeExecute
// CHECK: call @mlirAsyncRuntimeEmplaceToken(%[[RET_0]])
// Function outlined from the second async.execute operation with dependency.
-// CHECK-LABEL: func @async_execute_fn_0(%arg0: !llvm.ptr<i8>, %arg1: f32, %arg2: memref<1xf32>)
-// CHECK-SAME: -> !llvm.ptr<i8> attributes {sym_visibility = "private"}
+// CHECK-LABEL: func private @async_execute_fn_0(%arg0: !llvm.ptr<i8>, %arg1: f32, %arg2: memref<1xf32>)
+// CHECK-SAME: -> !llvm.ptr<i8>
// CHECK: %[[RET_1:.*]] = call @mlirAsyncRuntimeCreateToken()
// CHECK: %[[HDL_1:.*]] = llvm.call @llvm.coro.begin
print(d);
}
-# CHECK-LABEL: func @multiply_transpose(
+# CHECK-LABEL: func private @multiply_transpose(
# CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64>
# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64>
# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64>
// Check the result of inlining+shape inference on an input module.
-func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64>
- attributes { sym_visibility = "private" } {
+func private @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> {
%0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64>
%1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64>
%2 = toy.mul %0, %1 : tensor<*xf64>
toy.return
}
-// CHECK-NOT: func @multiply_transpose
+// CHECK-NOT: func private @multiply_transpose
// CHECK-NOT: tensor<*xf64>
// CHECK-LABEL: func @main()
print(d);
}
-# CHECK-LABEL: func @multiply_transpose(
+# CHECK-LABEL: func private @multiply_transpose(
# CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64>
# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64>
# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64>
// Check the result of inlining+shape inference on an input module.
-func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64>
- attributes { sym_visibility = "private" } {
+func private @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> {
%0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64>
%1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64>
%2 = toy.mul %0, %1 : tensor<*xf64>
print(d);
}
-# CHECK-LABEL: func @multiply_transpose(
+# CHECK-LABEL: func private @multiply_transpose(
# CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64>
# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64>
# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64>
// Check the result of inlining+shape inference on an input module.
-func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64>
- attributes { sym_visibility = "private" } {
+func private @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> {
%0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64>
%1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64>
%2 = toy.mul %0, %1 : tensor<*xf64>
print(d);
}
-# CHECK-LABEL: func @multiply_transpose(
+# CHECK-LABEL: func private @multiply_transpose(
# CHECK-SAME: [[VAL_0:%.*]]: tensor<*xf64>, [[VAL_1:%.*]]: tensor<*xf64>) -> tensor<*xf64>
# CHECK: [[VAL_2:%.*]] = toy.transpose([[VAL_0]] : tensor<*xf64>) to tensor<*xf64>
# CHECK-NEXT: [[VAL_3:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64>
// Check the result of inlining+shape inference on an input module.
-func @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64>
- attributes { sym_visibility = "private" } {
+func private @multiply_transpose(%arg0: tensor<*xf64>, %arg1: tensor<*xf64>) -> tensor<*xf64> {
%0 = toy.transpose(%arg0 : tensor<*xf64>) to tensor<*xf64>
%1 = toy.transpose(%arg1 : tensor<*xf64>) to tensor<*xf64>
%2 = toy.mul %0, %1 : tensor<*xf64>
print(c);
}
-# CHECK-LABEL: func @multiply_transpose(
+# CHECK-LABEL: func private @multiply_transpose(
# CHECK-SAME: [[VAL_0:%.*]]: !toy.struct<tensor<*xf64>, tensor<*xf64>>) -> tensor<*xf64>
-# CHECK-SAME: attributes {sym_visibility = "private"}
# CHECK-NEXT: [[VAL_1:%.*]] = toy.struct_access [[VAL_0]][0] : !toy.struct<tensor<*xf64>, tensor<*xf64>> -> tensor<*xf64>
# CHECK-NEXT: [[VAL_2:%.*]] = toy.transpose([[VAL_1]] : tensor<*xf64>) to tensor<*xf64>
# CHECK-NEXT: [[VAL_3:%.*]] = toy.struct_access [[VAL_0]][1] : !toy.struct<tensor<*xf64>, tensor<*xf64>> -> tensor<*xf64>
return
}
+
+// CHECK-LABEL: func private @legacy_visibility_syntax
+func @legacy_visibility_syntax() attributes { sym_visibility = "private" }
+
// This file tests the callgraph dead code elimination performed by the inliner.
// Function is already dead.
-// CHECK-NOT: func @dead_function
-func @dead_function() attributes {sym_visibility = "private"} {
+// CHECK-NOT: func private @dead_function
+func private @dead_function() {
return
}
// Function becomes dead after inlining.
-// CHECK-NOT: func @dead_function_b
-func @dead_function_b() attributes {sym_visibility = "private"} {
+// CHECK-NOT: func private @dead_function_b
+func @dead_function_b() {
return
}
func @live_function_b() {
return
}
-// CHECK-NOT: func @dead_function_c
-func @dead_function_c() attributes {sym_visibility = "private"} {
+// CHECK-NOT: func private @dead_function_c
+func private @dead_function_c() {
call @live_function_b() : () -> ()
return
}
-// CHECK-NOT: func @dead_function_d
-func @dead_function_d() attributes {sym_visibility = "private"} {
+// CHECK-NOT: func private @dead_function_d
+func private @dead_function_d() {
call @dead_function_c() : () -> ()
call @dead_function_c() : () -> ()
return
}
// Function is referenced by non-callable top-level user.
-// CHECK: func @live_function_d
-func @live_function_d() attributes {sym_visibility = "private"} {
+// CHECK: func private @live_function_d
+func private @live_function_d() {
return
}
return
}
// CHECK-NOT: func @dead_function_e
-func @dead_function_e() -> () attributes {sym_visibility = "private"} {
+func private @dead_function_e() -> () {
"test.fold_to_call_op"() {callee=@dead_function_f} : () -> ()
return
}
-// CHECK-NOT: func @dead_function_f
-func @dead_function_f() attributes {sym_visibility = "private"} {
+// CHECK-NOT: func private @dead_function_f
+func private @dead_function_f() {
return
}
/// Check that a constant is properly propagated through the arguments and
/// results of a private function.
-// CHECK-LABEL: func @private(
-func @private(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+// CHECK-LABEL: func private @private(
+func private @private(%arg0 : i32) -> i32 {
// CHECK: %[[CST:.*]] = constant 1 : i32
// CHECK: return %[[CST]] : i32
/// Check that a constant is properly propagated through the arguments and
/// results of a visible nested function.
-// CHECK: func @nested(
-func @nested(%arg0 : i32) -> i32 attributes { sym_visibility = "nested" } {
+// CHECK: func nested @nested(
+func nested @nested(%arg0 : i32) -> i32 {
// CHECK: %[[CST:.*]] = constant 1 : i32
// CHECK: return %[[CST]] : i32
// NESTED-LABEL: module @nested_module
module @nested_module attributes { sym_visibility = "public" } {
- // NESTED: func @nested(
- func @nested(%arg0 : i32) -> (i32, i32) attributes { sym_visibility = "nested" } {
+ // NESTED: func nested @nested(
+ func nested @nested(%arg0 : i32) -> (i32, i32) {
// NESTED: %[[CST:.*]] = constant 1 : i32
// NESTED: return %[[CST]], %arg0 : i32, i32
/// Check that public functions do not track arguments.
// CHECK-LABEL: func @public(
-func @public(%arg0 : i32) -> (i32, i32) attributes { sym_visibility = "public" } {
+func @public(%arg0 : i32) -> (i32, i32) {
%1 = constant 1 : i32
return %1, %arg0 : i32, i32
}
/// Check that functions with non-call users don't have arguments tracked.
-func @callable(%arg0 : i32) -> (i32, i32) attributes { sym_visibility = "private" } {
+func private @callable(%arg0 : i32) -> (i32, i32) {
%1 = constant 1 : i32
return %1, %arg0 : i32, i32
}
/// Check that return values are overdefined in the presence of an unknown terminator.
-func @callable(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+func private @callable(%arg0 : i32) -> i32 {
"unknown.return"(%arg0) : (i32) -> ()
}
/// Check that return values are overdefined when the constant conflicts.
-func @callable(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+func private @callable(%arg0 : i32) -> i32 {
"unknown.return"(%arg0) : (i32) -> ()
}
/// Check that return values are overdefined when the constant conflicts with a
/// non-constant.
-func @callable(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+func private @callable(%arg0 : i32) -> i32 {
"unknown.return"(%arg0) : (i32) -> ()
}
/// Check a more complex interaction with calls and control flow.
-// CHECK-LABEL: func @complex_inner_if(
-func @complex_inner_if(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+// CHECK-LABEL: func private @complex_inner_if(
+func private @complex_inner_if(%arg0 : i32) -> i32 {
// CHECK-DAG: %[[TRUE:.*]] = constant true
// CHECK-DAG: %[[CST:.*]] = constant 1 : i32
// CHECK: cond_br %[[TRUE]], ^bb1
func @complex_cond() -> i1
-// CHECK-LABEL: func @complex_callee(
-func @complex_callee(%arg0 : i32) -> i32 attributes { sym_visibility = "private" } {
+// CHECK-LABEL: func private @complex_callee(
+func private @complex_callee(%arg0 : i32) -> i32 {
// CHECK: %[[CST:.*]] = constant 1 : i32
%loop_cond = call @complex_cond() : () -> i1
// CHECK-LABEL: module attributes {test.simple}
module attributes {test.simple} {
- // CHECK-NOT: func @dead_private_function
- func @dead_private_function() attributes { sym_visibility = "private" }
+ // CHECK-NOT: func private @dead_private_function
+ func private @dead_private_function()
- // CHECK-NOT: func @dead_nested_function
- func @dead_nested_function() attributes { sym_visibility = "nested" }
+ // CHECK-NOT: func nested @dead_nested_function
+ func nested @dead_nested_function()
- // CHECK: func @live_private_function
- func @live_private_function() attributes { sym_visibility = "private" }
+ // CHECK: func private @live_private_function
+ func private @live_private_function()
- // CHECK: func @live_nested_function
- func @live_nested_function() attributes { sym_visibility = "nested" }
+ // CHECK: func nested @live_nested_function
+ func nested @live_nested_function()
// CHECK: func @public_function
func @public_function() {
"foo.return"() {uses = [@live_private_function, @live_nested_function]} : () -> ()
}
- // CHECK: func @public_function_explicit
- func @public_function_explicit() attributes { sym_visibility = "public" }
+ // CHECK: func public @public_function_explicit
+ func public @public_function_explicit()
}
// -----
module attributes {test.nested} {
// CHECK: module @public_module
module @public_module {
- // CHECK-NOT: func @dead_nested_function
- func @dead_nested_function() attributes { sym_visibility = "nested" }
+ // CHECK-NOT: func nested @dead_nested_function
+ func nested @dead_nested_function()
- // CHECK: func @private_function
- func @private_function() attributes { sym_visibility = "private" }
+ // CHECK: func private @private_function
+ func private @private_function()
- // CHECK: func @nested_function
- func @nested_function() attributes { sym_visibility = "nested" } {
+ // CHECK: func nested @nested_function
+ func nested @nested_function() {
"foo.return"() {uses = [@private_function]} : () -> ()
}
}
module attributes {test.no_dce_non_hidden_parent} {
// NESTED: module @public_module
module @public_module {
- // NESTED: func @nested_function
- func @nested_function() attributes { sym_visibility = "nested" }
+ // NESTED: func nested @nested_function
+ func nested @nested_function()
}
// NESTED: module @nested_module
module @nested_module attributes { sym_visibility = "nested" } {
- // NESTED: func @nested_function
- func @nested_function() attributes { sym_visibility = "nested" }
+ // NESTED: func nested @nested_function
+ func nested @nested_function()
}
// Only private modules can be assumed to be hidden.
// NESTED: module @private_module
module @private_module attributes { sym_visibility = "private" } {
- // NESTED-NOT: func @nested_function
- func @nested_function() attributes { sym_visibility = "nested" }
+ // NESTED-NOT: func nested @nested_function
+ func nested @nested_function()
}
"live.user"() {uses = [@nested_module, @private_module]} : () -> ()
// -----
module {
- func @private_symbol() attributes { sym_visibility = "private" }
+ func private @private_symbol()
// expected-error@+1 {{contains potentially unknown symbol table}}
"foo.possibly_unknown_symbol_table"() ({
// CHECK-LABEL: func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
// CHECK-NOT: func @dead_nested_function
-func @dead_private_function() attributes { sym_visibility = "private" }
+func private @dead_private_function()
// CHECK-NOT: func @dead_nested_function
-func @dead_nested_function() attributes { sym_visibility = "nested" }
+func nested @dead_nested_function()
func @simple1(%arg0: i1, %arg1: memref<2xf32>, %arg2: memref<2xf32>) {
"test.crashOp" () : () -> ()