diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMEnums.td @@ -546,6 +546,25 @@ let cppNamespace = "::mlir::LLVM"; } +//===----------------------------------------------------------------------===// +// Visibility +//===----------------------------------------------------------------------===// + +def VisibilityDefault + : LLVM_EnumAttrCase<"Default", "", "DefaultVisibility", 0>; +def VisibilityHidden + : LLVM_EnumAttrCase<"Hidden", "hidden", "HiddenVisibility", 1>; +def VisibilityProtected + : LLVM_EnumAttrCase<"Protected", "protected", "ProtectedVisibility", 2>; + +def Visibility : LLVM_EnumAttr< + "Visibility", + "::llvm::GlobalValue::VisibilityTypes", + "LLVM GlobalValue Visibility", + [VisibilityDefault, VisibilityHidden, VisibilityProtected]> { + let cppNamespace = "::mlir::LLVM"; +} + //===----------------------------------------------------------------------===// // ModRefInfo //===----------------------------------------------------------------------===// diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -1301,7 +1301,8 @@ OptionalAttr:$alignment, DefaultValuedAttr, "0">:$addr_space, OptionalAttr:$unnamed_addr, - OptionalAttr:$section + OptionalAttr:$section, + DefaultValuedAttr:$visibility_ ); let summary = "LLVM dialect global."; let description = [{ @@ -1546,7 +1547,8 @@ OptionalAttr:$arg_attrs, OptionalAttr:$res_attrs, OptionalAttr:$function_entry_count, - OptionalAttr:$memory + OptionalAttr:$memory, + DefaultValuedAttr:$visibility_ ); let regions = (region AnyRegion:$body); diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -1623,13 +1623,16 @@ void GlobalOp::print(OpAsmPrinter &p) { p << ' ' << stringifyLinkage(getLinkage()) << ' '; + StringRef visibility = stringifyVisibility(getVisibility_()); + if (!visibility.empty()) + p << visibility << ' '; + if (getThreadLocal_()) + p << "thread_local "; if (auto unnamedAddr = getUnnamedAddr()) { StringRef str = stringifyUnnamedAddr(*unnamedAddr); if (!str.empty()) p << str << ' '; } - if (getThreadLocal_()) - p << "thread_local "; if (getConstant()) p << "constant "; p.printSymbolName(getSymName()); @@ -1640,11 +1643,12 @@ // Note that the alignment attribute is printed using the // default syntax here, even though it is an inherent attribute // (as defined in https://mlir.llvm.org/docs/LangRef/#attributes) - p.printOptionalAttrDict( - (*this)->getAttrs(), - {SymbolTable::getSymbolAttrName(), getGlobalTypeAttrName(), - getConstantAttrName(), getValueAttrName(), getLinkageAttrName(), - getUnnamedAddrAttrName(), getThreadLocal_AttrName()}); + p.printOptionalAttrDict((*this)->getAttrs(), + {SymbolTable::getSymbolAttrName(), + getGlobalTypeAttrName(), getConstantAttrName(), + getValueAttrName(), getLinkageAttrName(), + getUnnamedAddrAttrName(), getThreadLocal_AttrName(), + getVisibility_AttrName()}); // Print the trailing type unless it's a string global. if (getValueOrNull().dyn_cast_or_null()) @@ -1684,6 +1688,7 @@ REGISTER_ENUM_TYPE(Linkage); REGISTER_ENUM_TYPE(UnnamedAddr); REGISTER_ENUM_TYPE(CConv); +REGISTER_ENUM_TYPE(Visibility); } // namespace /// Parse an enum from the keyword, or default to the provided default value. @@ -1717,9 +1722,11 @@ ctx, parseOptionalLLVMKeyword( parser, result, LLVM::Linkage::External))); - if (succeeded(parser.parseOptionalKeyword("thread_local"))) - result.addAttribute(getThreadLocal_AttrName(result.name), - parser.getBuilder().getUnitAttr()); + // Parse optional visibility, default to Default. + result.addAttribute(getVisibility_AttrName(result.name), + parser.getBuilder().getI64IntegerAttr( + parseOptionalLLVMKeyword( + parser, result, LLVM::Visibility::Default))); // Parse optional UnnamedAddr, default to None. result.addAttribute(getUnnamedAddrAttrName(result.name), @@ -1727,6 +1734,10 @@ parseOptionalLLVMKeyword( parser, result, LLVM::UnnamedAddr::None))); + if (succeeded(parser.parseOptionalKeyword("thread_local"))) + result.addAttribute(getThreadLocal_AttrName(result.name), + parser.getBuilder().getUnitAttr()); + if (succeeded(parser.parseOptionalKeyword("constant"))) result.addAttribute(getConstantAttrName(result.name), parser.getBuilder().getUnitAttr()); @@ -2047,6 +2058,12 @@ parseOptionalLLVMKeyword( parser, result, LLVM::Linkage::External))); + // Parse optional visibility, default to Default. + result.addAttribute(getVisibility_AttrName(result.name), + parser.getBuilder().getI64IntegerAttr( + parseOptionalLLVMKeyword( + parser, result, LLVM::Visibility::Default))); + // Default to C Calling Convention if no keyword is provided. result.addAttribute( getCConvAttrName(result.name), @@ -2097,6 +2114,9 @@ p << ' '; if (getLinkage() != LLVM::Linkage::External) p << stringifyLinkage(getLinkage()) << ' '; + StringRef visibility = stringifyVisibility(getVisibility_()); + if (!visibility.empty()) + p << visibility << ' '; if (getCConv() != LLVM::CConv::C) p << stringifyCConv(getCConv()) << ' '; @@ -2118,7 +2138,7 @@ function_interface_impl::printFunctionAttributes( p, *this, {getFunctionTypeAttrName(), getArgAttrsAttrName(), getResAttrsAttrName(), - getLinkageAttrName(), getCConvAttrName()}); + getLinkageAttrName(), getCConvAttrName(), getVisibility_AttrName()}); // Print the body if this is not an external function. Region &body = getBody(); diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -893,6 +893,8 @@ } if (globalVar->hasSection()) globalOp.setSection(globalVar->getSection()); + globalOp.setVisibility_( + convertVisibilityFromLLVM(globalVar->getVisibility())); return success(); } @@ -1611,6 +1613,8 @@ if (func->hasGC()) funcOp.setGarbageCollector(StringRef(func->getGC())); + funcOp.setVisibility_(convertVisibilityFromLLVM(func->getVisibility())); + // Handle Function attributes. processFunctionAttributes(func, funcOp); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -706,6 +706,8 @@ if (alignment.has_value()) var->setAlignment(llvm::MaybeAlign(alignment.value())); + var->setVisibility(convertVisibilityToLLVM(op.getVisibility_())); + globalsMapping.try_emplace(op, var); } @@ -975,6 +977,9 @@ if (failed(forwardPassthroughAttributes( function.getLoc(), function.getPassthrough(), llvmFunc))) return failure(); + + // Convert visibility attribute. + llvmFunc->setVisibility(convertVisibilityToLLVM(function.getVisibility_())); } return success(); diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir --- a/mlir/test/Dialect/LLVMIR/func.mlir +++ b/mlir/test/Dialect/LLVMIR/func.mlir @@ -194,6 +194,16 @@ llvm.func @memory_attr() attributes {memory = #llvm.memory_effects} { llvm.return } + + // CHECK-LABEL: llvm.func hidden @hidden + llvm.func hidden @hidden() { + llvm.return + } + + // CHECK-LABEL: llvm.func protected @protected + llvm.func protected @protected() { + llvm.return + } } // ----- diff --git a/mlir/test/Dialect/LLVMIR/global.mlir b/mlir/test/Dialect/LLVMIR/global.mlir --- a/mlir/test/Dialect/LLVMIR/global.mlir +++ b/mlir/test/Dialect/LLVMIR/global.mlir @@ -90,6 +90,16 @@ // CHECK: llvm.mlir.global internal constant @sectionvar("teststring") {addr_space = 0 : i32, section = ".mysection"} llvm.mlir.global internal constant @sectionvar("teststring") {section = ".mysection"}: !llvm.array<10 x i8> +// CHECK: llvm.mlir.global internal thread_local constant @thread_local(42 : i32) +llvm.mlir.global internal thread_local constant @thread_local(42 : i32) : i32 + +// Visibility types. +// CHECK: llvm.mlir.global internal hidden constant @hidden(42 : i32) +llvm.mlir.global internal hidden constant @hidden(42 : i32) : i32 + +// CHECK: llvm.mlir.global internal protected unnamed_addr @protected(42 : i32) +llvm.mlir.global internal protected unnamed_addr @protected(42 : i32) : i32 + // ----- // expected-error @+1 {{op requires attribute 'sym_name'}} diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll --- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll +++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll @@ -179,3 +179,17 @@ define void @passthrough_string_only() "no-enum-attr" { ret void } + +// ----- + +; CHECK-LABEL: llvm.func hidden @hidden() +define hidden void @hidden() { + ret void +} + +// ----- + +; CHECK-LABEL: llvm.func protected @protected() +define protected void @protected() { + ret void +} diff --git a/mlir/test/Target/LLVMIR/Import/global-variables.ll b/mlir/test/Target/LLVMIR/Import/global-variables.ll --- a/mlir/test/Target/LLVMIR/Import/global-variables.ll +++ b/mlir/test/Target/LLVMIR/Import/global-variables.ll @@ -196,3 +196,13 @@ define void @bar() { ret void } + +; // ----- + +; Visibility attribute. + +; CHECK: llvm.mlir.global external hidden constant @hidden("string") +@hidden = hidden constant [6 x i8] c"string" + +; CHECK: llvm.mlir.global external protected constant @protected(42 : i64) +@protected = protected constant i64 42 diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -110,6 +110,17 @@ // CHECK: @external = external global i32 llvm.mlir.global external @external() : i32 + +// +// Visibility attribute. +// + +// CHECK: @hidden = hidden constant [6 x i8] c"string" +llvm.mlir.global external hidden constant @hidden("string") + +// CHECK: @protected = protected constant i64 42 +llvm.mlir.global external protected constant @protected(42 : i64) : i64 + // // UnnamedAddr attribute. // @@ -484,6 +495,20 @@ llvm.return } +// +// Visibility attribute. +// + +// CHECK-LABEL: define hidden void @hidden_func() +llvm.func hidden @hidden_func() { + llvm.return +} + +// CHECK-LABEL: define protected void @protected_func() +llvm.func protected @protected_func() { + llvm.return +} + // // dso_local attribute. //