aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CIR/CodeGen/CIRGenModule.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CIR/CodeGen/CIRGenModule.cpp')
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenModule.cpp217
1 files changed, 204 insertions, 13 deletions
diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
index b31b2b3..11c3bd4 100644
--- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp
@@ -21,6 +21,7 @@
#include "clang/AST/GlobalDecl.h"
#include "clang/Basic/SourceManager.h"
#include "clang/CIR/Dialect/IR/CIRDialect.h"
+#include "clang/CIR/Interfaces/CIROpInterfaces.h"
#include "clang/CIR/MissingFeatures.h"
#include "CIRGenFunctionInfo.h"
@@ -391,9 +392,7 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
if (d->getTLSKind())
errorNYI(d->getSourceRange(), "thread local global variable");
- assert(!cir::MissingFeatures::opGlobalDLLImportExport());
- assert(!cir::MissingFeatures::opGlobalPartition());
- assert(!cir::MissingFeatures::setDSOLocal());
+ setGVProperties(gv, d);
// If required by the ABI, treat declarations of static data members with
// inline initializers as definitions.
@@ -401,15 +400,20 @@ CIRGenModule::getOrCreateCIRGlobal(StringRef mangledName, mlir::Type ty,
errorNYI(d->getSourceRange(), "MS static data member inline definition");
assert(!cir::MissingFeatures::opGlobalSection());
- assert(!cir::MissingFeatures::opGlobalVisibility());
+ gv.setGlobalVisibilityAttr(getGlobalVisibilityAttrFromDecl(d));
// Handle XCore specific ABI requirements.
if (getTriple().getArch() == llvm::Triple::xcore)
errorNYI(d->getSourceRange(), "XCore specific ABI requirements");
- // We need to check for external const declarations with initializers here,
- // but the 'isPublic()' part of the check uses the CIRGlobalValueInterface.
- assert(!cir::MissingFeatures::opGlobalCIRGlobalValueInterface());
+ // Check if we a have a const declaration with an initializer, we may be
+ // able to emit it as available_externally to expose it's value to the
+ // optimizer.
+ if (getLangOpts().CPlusPlus && gv.isPublic() &&
+ d->getType().isConstQualified() && gv.isDeclaration() &&
+ !d->hasDefinition() && d->hasInit() && !d->hasAttr<DLLImportAttr>())
+ errorNYI(d->getSourceRange(),
+ "external const declaration with initializer");
}
return gv;
@@ -568,7 +572,9 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
// Set CIR linkage and DLL storage class.
gv.setLinkage(linkage);
-
+ // FIXME(cir): setLinkage should likely set MLIR's visibility automatically.
+ gv.setVisibility(getMLIRVisibilityFromCIRLinkage(linkage));
+ assert(!cir::MissingFeatures::opGlobalDLLImportExport());
if (linkage == cir::GlobalLinkageKind::CommonLinkage)
errorNYI(initExpr->getSourceRange(), "common linkage");
}
@@ -632,8 +638,13 @@ CIRGenModule::getConstantArrayFromStringLiteral(const StringLiteral *e) {
return mlir::Attribute();
}
+bool CIRGenModule::supportsCOMDAT() const {
+ return getTriple().supportsCOMDAT();
+}
+
static bool shouldBeInCOMDAT(CIRGenModule &cgm, const Decl &d) {
- assert(!cir::MissingFeatures::supportComdat());
+ if (!cgm.supportsCOMDAT())
+ return false;
if (d.hasAttr<SelectAnyAttr>())
return true;
@@ -836,8 +847,11 @@ static cir::GlobalOp generateStringLiteral(mlir::Location loc,
assert(!cir::MissingFeatures::opGlobalThreadLocal());
assert(!cir::MissingFeatures::opGlobalUnnamedAddr());
CIRGenModule::setInitializer(gv, c);
- assert(!cir::MissingFeatures::supportComdat());
- assert(!cir::MissingFeatures::opGlobalDSOLocal());
+ if (gv.isWeakForLinker()) {
+ assert(cgm.supportsCOMDAT() && "Only COFF uses weak string literals");
+ gv.setComdat(true);
+ }
+ cgm.setDSOLocal(static_cast<mlir::Operation *>(gv));
return gv;
}
@@ -894,7 +908,7 @@ cir::GlobalOp CIRGenModule::getGlobalForStringLiteral(const StringLiteral *s,
auto typedC = llvm::cast<mlir::TypedAttr>(c);
cir::GlobalOp gv =
generateStringLiteral(loc, typedC, *this, uniqueName, alignment);
- assert(!cir::MissingFeatures::opGlobalDSOLocal());
+ setDSOLocal(static_cast<mlir::Operation *>(gv));
assert(!cir::MissingFeatures::sanitizers());
@@ -1075,6 +1089,134 @@ void CIRGenModule::emitTentativeDefinition(const VarDecl *d) {
emitGlobalVarDefinition(d);
}
+static bool shouldAssumeDSOLocal(const CIRGenModule &cgm,
+ cir::CIRGlobalValueInterface gv) {
+ if (gv.hasLocalLinkage())
+ return true;
+
+ if (!gv.hasDefaultVisibility() && !gv.hasExternalWeakLinkage())
+ return true;
+
+ // DLLImport explicitly marks the GV as external.
+ // so it shouldn't be dso_local
+ // But we don't have the info set now
+ assert(!cir::MissingFeatures::opGlobalDLLImportExport());
+
+ const llvm::Triple &tt = cgm.getTriple();
+ const CodeGenOptions &cgOpts = cgm.getCodeGenOpts();
+ if (tt.isWindowsGNUEnvironment()) {
+ // In MinGW, variables without DLLImport can still be automatically
+ // imported from a DLL by the linker; don't mark variables that
+ // potentially could come from another DLL as DSO local.
+
+ // With EmulatedTLS, TLS variables can be autoimported from other DLLs
+ // (and this actually happens in the public interface of libstdc++), so
+ // such variables can't be marked as DSO local. (Native TLS variables
+ // can't be dllimported at all, though.)
+ cgm.errorNYI("shouldAssumeDSOLocal: MinGW");
+ }
+
+ // On COFF, don't mark 'extern_weak' symbols as DSO local. If these symbols
+ // remain unresolved in the link, they can be resolved to zero, which is
+ // outside the current DSO.
+ if (tt.isOSBinFormatCOFF() && gv.hasExternalWeakLinkage())
+ return false;
+
+ // Every other GV is local on COFF.
+ // Make an exception for windows OS in the triple: Some firmware builds use
+ // *-win32-macho triples. This (accidentally?) produced windows relocations
+ // without GOT tables in older clang versions; Keep this behaviour.
+ // FIXME: even thread local variables?
+ if (tt.isOSBinFormatCOFF() || (tt.isOSWindows() && tt.isOSBinFormatMachO()))
+ return true;
+
+ // Only handle COFF and ELF for now.
+ if (!tt.isOSBinFormatELF())
+ return false;
+
+ llvm::Reloc::Model rm = cgOpts.RelocationModel;
+ const LangOptions &lOpts = cgm.getLangOpts();
+ if (rm != llvm::Reloc::Static && !lOpts.PIE) {
+ // On ELF, if -fno-semantic-interposition is specified and the target
+ // supports local aliases, there will be neither CC1
+ // -fsemantic-interposition nor -fhalf-no-semantic-interposition. Set
+ // dso_local on the function if using a local alias is preferable (can avoid
+ // PLT indirection).
+ if (!(isa<cir::FuncOp>(gv) && gv.canBenefitFromLocalAlias()))
+ return false;
+ return !(lOpts.SemanticInterposition || lOpts.HalfNoSemanticInterposition);
+ }
+
+ // A definition cannot be preempted from an executable.
+ if (!gv.isDeclarationForLinker())
+ return true;
+
+ // Most PIC code sequences that assume that a symbol is local cannot produce a
+ // 0 if it turns out the symbol is undefined. While this is ABI and relocation
+ // depended, it seems worth it to handle it here.
+ if (rm == llvm::Reloc::PIC_ && gv.hasExternalWeakLinkage())
+ return false;
+
+ // PowerPC64 prefers TOC indirection to avoid copy relocations.
+ if (tt.isPPC64())
+ return false;
+
+ if (cgOpts.DirectAccessExternalData) {
+ // If -fdirect-access-external-data (default for -fno-pic), set dso_local
+ // for non-thread-local variables. If the symbol is not defined in the
+ // executable, a copy relocation will be needed at link time. dso_local is
+ // excluded for thread-local variables because they generally don't support
+ // copy relocations.
+ if (auto globalOp = dyn_cast<cir::GlobalOp>(gv.getOperation())) {
+ // Assume variables are not thread-local until that support is added.
+ assert(!cir::MissingFeatures::opGlobalThreadLocal());
+ return true;
+ }
+
+ // -fno-pic sets dso_local on a function declaration to allow direct
+ // accesses when taking its address (similar to a data symbol). If the
+ // function is not defined in the executable, a canonical PLT entry will be
+ // needed at link time. -fno-direct-access-external-data can avoid the
+ // canonical PLT entry. We don't generalize this condition to -fpie/-fpic as
+ // it could just cause trouble without providing perceptible benefits.
+ if (isa<cir::FuncOp>(gv) && !cgOpts.NoPLT && rm == llvm::Reloc::Static)
+ return true;
+ }
+
+ // If we can use copy relocations we can assume it is local.
+
+ // Otherwise don't assume it is local.
+
+ return false;
+}
+
+void CIRGenModule::setGlobalVisibility(mlir::Operation *gv,
+ const NamedDecl *d) const {
+ assert(!cir::MissingFeatures::opGlobalVisibility());
+}
+
+void CIRGenModule::setDSOLocal(cir::CIRGlobalValueInterface gv) const {
+ gv.setDSOLocal(shouldAssumeDSOLocal(*this, gv));
+}
+
+void CIRGenModule::setDSOLocal(mlir::Operation *op) const {
+ if (auto globalValue = dyn_cast<cir::CIRGlobalValueInterface>(op))
+ setDSOLocal(globalValue);
+}
+
+void CIRGenModule::setGVProperties(mlir::Operation *op,
+ const NamedDecl *d) const {
+ assert(!cir::MissingFeatures::opGlobalDLLImportExport());
+ setGVPropertiesAux(op, d);
+}
+
+void CIRGenModule::setGVPropertiesAux(mlir::Operation *op,
+ const NamedDecl *d) const {
+ setGlobalVisibility(op, d);
+ setDSOLocal(op);
+ assert(!cir::MissingFeatures::opGlobalPartition());
+}
+
cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,
bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,
@@ -1111,7 +1253,7 @@ cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
// Handle dropped DLL attributes.
if (d && !d->hasAttr<DLLImportAttr>() && !d->hasAttr<DLLExportAttr>()) {
assert(!cir::MissingFeatures::setDLLStorageClass());
- assert(!cir::MissingFeatures::setDSOLocal());
+ setDSOLocal(entry);
}
// If there are two attempts to define the same mangled name, issue an
@@ -1165,6 +1307,55 @@ CIRGenModule::createCIRFunction(mlir::Location loc, StringRef name,
return func;
}
+mlir::SymbolTable::Visibility
+CIRGenModule::getMLIRVisibilityFromCIRLinkage(cir::GlobalLinkageKind glk) {
+ switch (glk) {
+ case cir::GlobalLinkageKind::InternalLinkage:
+ case cir::GlobalLinkageKind::PrivateLinkage:
+ return mlir::SymbolTable::Visibility::Private;
+ case cir::GlobalLinkageKind::ExternalLinkage:
+ case cir::GlobalLinkageKind::ExternalWeakLinkage:
+ case cir::GlobalLinkageKind::LinkOnceODRLinkage:
+ case cir::GlobalLinkageKind::AvailableExternallyLinkage:
+ case cir::GlobalLinkageKind::CommonLinkage:
+ case cir::GlobalLinkageKind::WeakAnyLinkage:
+ case cir::GlobalLinkageKind::WeakODRLinkage:
+ return mlir::SymbolTable::Visibility::Public;
+ default: {
+ llvm::errs() << "visibility not implemented for '"
+ << stringifyGlobalLinkageKind(glk) << "'\n";
+ assert(0 && "not implemented");
+ }
+ }
+ llvm_unreachable("linkage should be handled above!");
+}
+
+cir::VisibilityKind CIRGenModule::getGlobalVisibilityKindFromClangVisibility(
+ clang::VisibilityAttr::VisibilityType visibility) {
+ switch (visibility) {
+ case clang::VisibilityAttr::VisibilityType::Default:
+ return cir::VisibilityKind::Default;
+ case clang::VisibilityAttr::VisibilityType::Hidden:
+ return cir::VisibilityKind::Hidden;
+ case clang::VisibilityAttr::VisibilityType::Protected:
+ return cir::VisibilityKind::Protected;
+ }
+ llvm_unreachable("unexpected visibility value");
+}
+
+cir::VisibilityAttr
+CIRGenModule::getGlobalVisibilityAttrFromDecl(const Decl *decl) {
+ const clang::VisibilityAttr *va = decl->getAttr<clang::VisibilityAttr>();
+ cir::VisibilityAttr cirVisibility =
+ cir::VisibilityAttr::get(&getMLIRContext());
+ if (va) {
+ cirVisibility = cir::VisibilityAttr::get(
+ &getMLIRContext(),
+ getGlobalVisibilityKindFromClangVisibility(va->getVisibility()));
+ }
+ return cirVisibility;
+}
+
mlir::Type CIRGenModule::convertType(QualType type) {
return genTypes.convertType(type);
}