Index: include/llvm/IR/GlobalAlias.h =================================================================== --- include/llvm/IR/GlobalAlias.h +++ include/llvm/IR/GlobalAlias.h @@ -36,6 +36,16 @@ const Twine &Name, Constant *Aliasee, Module *Parent); public: + /// Returns true if given alias has ifunc type. + bool isIFunc() const { + return getGlobalValueSubClassData(); + } + + /// Set isIFunc property. + void setIFunc(bool IsIFunc) { + setGlobalValueSubClassData(IsIFunc); + } + // allocate space for exactly one operand void *operator new(size_t s) { return User::operator new(s, 1); @@ -77,6 +87,10 @@ /// void eraseFromParent() override; + /// Copy all additional attributes (those not needed to create a GlobalAlias) + /// from the Src to this one. + void copyAttributesFrom(const GlobalValue *Src) override; + /// These methods retrive and set alias target. void setAliasee(Constant *Aliasee); const Constant *getAliasee() const { Index: lib/AsmParser/LLLexer.cpp =================================================================== --- lib/AsmParser/LLLexer.cpp +++ lib/AsmParser/LLLexer.cpp @@ -609,6 +609,7 @@ KEYWORD(convergent); KEYWORD(dereferenceable); KEYWORD(dereferenceable_or_null); + KEYWORD(ifunc); KEYWORD(inlinehint); KEYWORD(inreg); KEYWORD(jumptable); Index: lib/AsmParser/LLParser.cpp =================================================================== --- lib/AsmParser/LLParser.cpp +++ lib/AsmParser/LLParser.cpp @@ -678,6 +678,12 @@ return Error(NameLoc, "symbol with local linkage must have default visibility"); + bool IFunc = false; + if (Lex.getKind() == lltok::kw_ifunc) { + IFunc = true; + Lex.Lex(); + } + Type *Ty; LocTy ExplicitTypeLoc = Lex.getLoc(); if (ParseType(Ty) || @@ -739,6 +745,7 @@ GA->setVisibility((GlobalValue::VisibilityTypes)Visibility); GA->setDLLStorageClass((GlobalValue::DLLStorageClassTypes)DLLStorageClass); GA->setUnnamedAddr(UnnamedAddr); + GA->setIFunc(IFunc); if (Name.empty()) NumberedVals.push_back(GA.get()); Index: lib/AsmParser/LLToken.h =================================================================== --- lib/AsmParser/LLToken.h +++ lib/AsmParser/LLToken.h @@ -115,6 +115,7 @@ kw_convergent, kw_dereferenceable, kw_dereferenceable_or_null, + kw_ifunc, kw_inlinehint, kw_inreg, kw_jumptable, Index: lib/Bitcode/Reader/BitcodeReader.cpp =================================================================== --- lib/Bitcode/Reader/BitcodeReader.cpp +++ lib/Bitcode/Reader/BitcodeReader.cpp @@ -3624,6 +3624,8 @@ NewGA->setThreadLocalMode(getDecodedThreadLocalMode(Record[OpNum++])); if (OpNum != Record.size()) NewGA->setUnnamedAddr(Record[OpNum++]); + if (OpNum != Record.size()) + NewGA->setIFunc(Record[OpNum++]); ValueList.push_back(NewGA); AliasInits.push_back(std::make_pair(NewGA, Val)); break; Index: lib/Bitcode/Writer/BitcodeWriter.cpp =================================================================== --- lib/Bitcode/Writer/BitcodeWriter.cpp +++ lib/Bitcode/Writer/BitcodeWriter.cpp @@ -771,6 +771,7 @@ Vals.push_back(getEncodedDLLStorageClass(A)); Vals.push_back(getEncodedThreadLocalMode(A)); Vals.push_back(A.hasUnnamedAddr()); + Vals.push_back(A.isIFunc()); unsigned AbbrevToUse = 0; Stream.EmitRecord(bitc::MODULE_CODE_ALIAS, Vals, AbbrevToUse); Vals.clear(); Index: lib/CodeGen/AsmPrinter/AsmPrinter.cpp =================================================================== --- lib/CodeGen/AsmPrinter/AsmPrinter.cpp +++ lib/CodeGen/AsmPrinter/AsmPrinter.cpp @@ -1189,8 +1189,11 @@ // Set the symbol type to function if the alias has a function type. // This affects codegen when the aliasee is not a function. - if (Alias.getType()->getPointerElementType()->isFunctionTy()) + if (Alias.getType()->getPointerElementType()->isFunctionTy()) { OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeFunction); + if (Alias.isIFunc()) + OutStreamer->EmitSymbolAttribute(Name, MCSA_ELF_TypeIndFunction); + } EmitVisibility(Name, Alias.getVisibility()); Index: lib/IR/AsmWriter.cpp =================================================================== --- lib/IR/AsmWriter.cpp +++ lib/IR/AsmWriter.cpp @@ -2458,6 +2458,9 @@ Out << "alias "; + if (GA->isIFunc()) + Out << "ifunc "; + TypePrinter.print(GA->getValueType(), Out); Out << ", "; Index: lib/IR/Globals.cpp =================================================================== --- lib/IR/Globals.cpp +++ lib/IR/Globals.cpp @@ -241,6 +241,8 @@ if (ParentModule) ParentModule->getAliasList().push_back(this); + + setIFunc(false); } GlobalAlias *GlobalAlias::create(Type *Ty, unsigned AddressSpace, @@ -289,3 +291,9 @@ "Alias and aliasee types should match!"); setOperand(0, Aliasee); } + +void GlobalAlias::copyAttributesFrom(const GlobalValue *Src) { + GlobalValue::copyAttributesFrom(Src); + if (const auto *GV = dyn_cast(Src)) + setIFunc(GV->isIFunc()); +} Index: test/Assembler/ifunc-alias.ll =================================================================== --- /dev/null +++ test/Assembler/ifunc-alias.ll @@ -0,0 +1,14 @@ +; RUN: llvm-as < %s | llvm-dis | FileCheck %s --check-prefix=CHECK-LLVM +; RUN: llvm-as < %s -o - | llc -filetype=asm | FileCheck %s --check-prefix=CHECK-ASM + +target triple = "x86_64-unknown-linux-gnu" + +@foo = linkonce alias ifunc i32 (i32), bitcast (i64 ()* @foo_ifunc to i32 (i32)*) +; CHECK-LLVM: @foo = linkonce alias ifunc i32 (i32), bitcast (i64 ()* @foo_ifunc to i32 (i32)*) +; CHECK-ASM: .type foo,@gnu_indirect_function + +define internal i64 @foo_ifunc() { +entry: + ret i64 0 +} +; CHECK-LLVM: define internal i64 @foo_ifunc()