diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 257343f678388..fb2e7adb28198 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -2264,6 +2264,30 @@ void CodeGenModule::EmitDeferred() { CurDeclsToEmit.swap(DeferredDeclsToEmit); for (GlobalDecl &D : CurDeclsToEmit) { + const ValueDecl *VD = cast(D.getDecl()); + // If emitting for SYCL device, emit the deferred alias + // as well as what it aliases. + if (LangOpts.SYCLIsDevice) { + if (AliasAttr *Attr = VD->getAttr()) { + StringRef AliaseeName = Attr->getAliasee(); + auto DDI = DeferredDecls.find(AliaseeName); + // Emit what is aliased first. + if (DDI != DeferredDecls.end()) { + llvm::GlobalValue *AliaseeGV = dyn_cast( + GetAddrOfGlobal(DDI->second, ForDefinition)); + if (!AliaseeGV) + AliaseeGV = GetGlobalValue(getMangledName(DDI->second)); + assert(AliaseeGV); + EmitGlobalDefinition(DDI->second, AliaseeGV); + // Remove the entry just added to the DeferredDeclsToEmit + // since we have emitted it. + DeferredDeclsToEmit.pop_back(); + } + // Now emit the alias itself. + EmitAliasDefinition(D); + continue; + } + } // We should call GetAddrOfGlobal with IsForDefinition set to true in order // to get GlobalValue with exactly the type we need, not something that // might had been created for another decl with the same mangled name but @@ -2296,6 +2320,20 @@ void CodeGenModule::EmitDeferred() { // Otherwise, emit the definition and move on to the next one. EmitGlobalDefinition(D, GV); + if (LangOpts.SYCLIsDevice) { + // If there are any aliases deferred for this, emit those now. + for (auto It = DeferredAliases.begin(); It != DeferredAliases.end(); + /*no increment*/) { + const ValueDecl *Global = cast(It->second.getDecl()); + if (It->first == getMangledName(D)) { + EmitAliasDefinition(Global); + It = DeferredAliases.erase(It); + } else { + ++It; + } + } + } + // If we found out that we need to emit more decls, do that recursively. // This has the advantage that the decls are emitted in a DFS and related // ones are close together, which is convenient for testing. @@ -2619,9 +2657,19 @@ void CodeGenModule::EmitGlobal(GlobalDecl GD) { return; // If this is an alias definition (which otherwise looks like a declaration) - // emit it now. - if (Global->hasAttr()) - return EmitAliasDefinition(GD); + // handle it now. + if (AliasAttr *Attr = Global->getAttr()) { + // Emit the alias here if it is not SYCL device compilation. + if (!LangOpts.SYCLIsDevice) + return EmitAliasDefinition(GD); + // Defer for SYCL devices, until either the alias or what it aliases + // is used. + StringRef MangledName = getMangledName(GD); + DeferredDecls[MangledName] = GD; + StringRef AliaseeName = Attr->getAliasee(); + DeferredAliases[AliaseeName] = GD; + return; + } // IFunc like an alias whose value is resolved at runtime by calling resolver. if (Global->hasAttr()) @@ -4836,20 +4884,21 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { // if a deferred decl. llvm::Constant *Aliasee; llvm::GlobalValue::LinkageTypes LT; + unsigned AS; if (isa(DeclTy)) { Aliasee = GetOrCreateLLVMFunction(AA->getAliasee(), DeclTy, GD, /*ForVTable=*/false); LT = getFunctionLinkage(GD); + AS = Aliasee->getType()->getPointerAddressSpace(); } else { - Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), - llvm::PointerType::getUnqual(DeclTy), + AS = ArgInfoAddressSpace(GetGlobalVarAddressSpace(/*D=*/nullptr)); + Aliasee = GetOrCreateLLVMGlobal(AA->getAliasee(), DeclTy->getPointerTo(AS), /*D=*/nullptr); LT = getLLVMLinkageVarDefinition(cast(GD.getDecl()), D->getType().isConstQualified()); } // Create the new alias itself, but don't set a name yet. - unsigned AS = Aliasee->getType()->getPointerAddressSpace(); auto *GA = llvm::GlobalAlias::create(DeclTy, AS, LT, "", Aliasee, &getModule()); @@ -4870,8 +4919,8 @@ void CodeGenModule::EmitAliasDefinition(GlobalDecl GD) { // Remove it and replace uses of it with the alias. GA->takeName(Entry); - Entry->replaceAllUsesWith(llvm::ConstantExpr::getBitCast(GA, - Entry->getType())); + Entry->replaceAllUsesWith( + llvm::ConstantExpr::getBitCast(GA, Entry->getType())); Entry->eraseFromParent(); } else { GA->setName(MangledName); diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h index 2037571f38829..cac10a97e7106 100644 --- a/clang/lib/CodeGen/CodeGenModule.h +++ b/clang/lib/CodeGen/CodeGenModule.h @@ -345,6 +345,11 @@ class CodeGenModule : public CodeGenTypeCache { /// yet. std::map DeferredDecls; + /// This contains all the aliases that are deferred for emission until + /// they or what they alias are actually used. Note that the StringRef + /// associated in this map is that of the aliasee. + std::map DeferredAliases; + /// This is a list of deferred decls which we have seen that *are* actually /// referenced. These get code generated when the module is done. std::vector DeferredDeclsToEmit; diff --git a/clang/test/CodeGenSYCL/sycl-device-alias.cpp b/clang/test/CodeGenSYCL/sycl-device-alias.cpp new file mode 100644 index 0000000000000..3a124901b471d --- /dev/null +++ b/clang/test/CodeGenSYCL/sycl-device-alias.cpp @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -fsycl -fsycl-is-device -triple spir64-unknown-unknown-sycldevice -disable-llvm-passes -emit-llvm %s -o - | FileCheck %s +// Test that aliasing does not force an unused entity to be emitted + +// CHECK-NOT: define spir_func void @unused_func() +extern "C" void unused_func() {} +// CHECK-NOT: @unused_aliaser +extern "C" void unused_aliaser() __attribute__((alias("unused_func"))); +// CHECK-NOT: @unused_int +int unused_int = 3; +// CHECK-NOT: @alias_unused_int +extern int alias_unused_int __attribute__((alias("unused_int"))); + +// CHECK-DAG: define spir_func void @used_func() +extern "C" void used_func() {} +// CHECK-DAG: @aliaser = alias void (), void ()* @used_func +extern "C" void aliaser() __attribute__((alias("used_func"))); + +// CHECK-DAG: define spir_func void @func() +extern "C" void func() {} +// CHECK-DAG: @used_aliaser = alias void (), void ()* @func +extern "C" void used_aliaser() __attribute__((alias("func"))); + +// CHECK-DAG: @used_int = addrspace(1) constant i32 5, align 4 +extern "C" const int used_int = 5; +// CHECK-DAG: @alias_used_int = alias i32, i32 addrspace(1)* @used_int +extern "C" const int alias_used_int __attribute__((alias("used_int"))); +// CHECK-DAG: @vint = addrspace(1) constant i32 7, align 4 +extern "C" const int vint = 7; +// CHECK-DAG: @used_alias_used_int = alias i32, i32 addrspace(1)* @vint +extern "C" const int used_alias_used_int __attribute__((alias("vint"))); + +// CHECK-DAG: define spir_func void @{{.*}}bar{{.*}} +void bar(const int &i) {} + +// CHECK-DAG: define spir_func void @{{.*}}foo{{.*}} +void __attribute__((sycl_device)) foo() { + // CHECK-DAG: call spir_func void @{{.*}}bar{{.*}}@used_int + bar(used_int); + // CHECK-DAG: call spir_func void @{{.*}}bar{{.*}}@used_alias_used_int + bar(used_alias_used_int); + // CHECK-DAG: call spir_func void @used_func() + used_func(); + // CHECK-DAG: call spir_func void @used_aliaser() + used_aliaser(); +}