Reapply [IR] Explicitly specify target feature for module asm (#204548) (#207677)

Reapply with a use-after-free fix. The MC subtarget used for inline
assembly has to stay alive until finalization, not only during the
emitInlineAsm() call.

-----

Support specifying additional properties on module-level inline
assembly. In particular, the target features and target CPU can now be
specified as follows:

    module asm(target_features: "+foo", target_cpu: "bar")
        "asm line 1"
        "asm line 2"

There may be multiple module inline assembly blocks with different
properties.

This is intended to fix the long standing issue where in LTO scenarios
we don't know what target features to use for parsing the module-level
inline assembly. Now they can be faithfully preserved, even when merging
inline assembly from different modules with different features.

If target_features and target_cpu are empty, we fall back to the old
behavior (which, in the backend, would be to use the default subtarget
of the TargetMachine).

Fixes https://github.com/llvm/llvm-project/issues/61991.
Fixes https://github.com/llvm/llvm-project/issues/67698.
This commit is contained in:
Nikita Popov authored and GitHub committed 2026-07-06 11:57:38 +02:00
1 parent 4ffcfdfac1
commit fcfc9167b6
61 files changed
+573 -180

No files matched your search

+1 -5
View File
@@ -6610,10 +6610,6 @@ void CGObjCMac::FinishModule() {
if ((!LazySymbols.empty() || !DefinedSymbols.empty()) &&
CGM.getTriple().isOSBinFormatMachO()) {
SmallString<256> Asm;
Asm += CGM.getModule().getModuleInlineAsm();
if (!Asm.empty() && Asm.back() != '\n')
Asm += '\n';
llvm::raw_svector_ostream OS(Asm);
for (const auto *Sym : DefinedSymbols)
OS << "\t.objc_class_name_" << Sym->getName() << "=0\n"
@@ -6624,7 +6620,7 @@ void CGObjCMac::FinishModule() {
OS << "\t.objc_category_name_" << Category << "=0\n"
<< "\t.globl .objc_category_name_" << Category << "\n";
CGM.getModule().setModuleInlineAsm(OS.str());
CGM.getModule().appendModuleInlineAsm(OS.str());
}
}
+7 -1
View File
@@ -8057,7 +8057,13 @@ void CodeGenModule::EmitTopLevelDecl(Decl *D) {
if (LangOpts.SYCLIsDevice)
break;
auto *AD = cast<FileScopeAsmDecl>(D);
getModule().appendModuleInlineAsm(AD->getAsmString());
const TargetOptions &TargetOpts = getTarget().getTargetOpts();
llvm::Module::GlobalAsmProperties Props;
Props.TargetFeatures = llvm::join(TargetOpts.Features, ",");
Props.TargetCPU = TargetOpts.CPU;
getModule().appendModuleInlineAsm(
llvm::Module::GlobalAsmFragment(AD->getAsmString(), Props));
break;
}
+11 -6
View File
@@ -1,13 +1,18 @@
// UNSUPPORTED: target={{.*}}-zos{{.*}}
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s
// RUN: %clang_cc1 %s -triple=riscv64 -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,RISCV64
// RUN: %clang_cc1 %s -triple=riscv64 -target-feature +d -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,RISCV64-D
// RUN: %clang_cc1 %s -emit-llvm -o - | FileCheck %s --check-prefixes=CHECK,DEFAULT
// CHECK: module asm "foo1"
// RISCV64: module asm(target_features: "+64bit,+i")
// RISCV64-D: module asm(target_features: "+64bit,+d,+f,+i,+zicsr")
// DEFAULT: module asm
// CHECK-NEXT: "foo1"
__asm__ ("foo1");
// CHECK: module asm "foo2"
// CHECK-NEXT: "foo2"
__asm__ ("foo2");
// CHECK: module asm "foo3"
// CHECK-NEXT: "foo3"
__asm__ ("foo3");
// CHECK: module asm "foo4"
// CHECK-NEXT: "foo4"
__asm__ ("foo4");
// CHECK: module asm "foo5"
// CHECK-NEXT: "foo5"
__asm__ ("foo5");
+4 -3
View File
@@ -2,9 +2,10 @@
// PR10415:
//
// CHECK: module asm "foo1"
// CHECK-NEXT: module asm "foo2"
// CHECK-NEXT: module asm "foo3"
// CHECK: module asm(target_features: "{{.*}}")
// CHECK-NEXT: "foo1"
// CHECK-NEXT: "foo2"
// CHECK-NEXT: "foo3"
__asm__ ("foo1");
__asm__ ("foo2");
__asm__ ("foo3");
+2 -1
View File
@@ -6,4 +6,5 @@ asm(".incbin \"foo.h\"");
// RUN: cd %t
// RUN: %clang -c -emit-llvm %t/tu.c -o %t/tu.ll
// RUN: llvm-dis %t/tu.ll -o - | FileCheck %s
// CHECK: module asm ".incbin \22foo.h\22"
// CHECK: module asm
// CHECK-NEXT: ".incbin \22foo.h\22"
+6 -5
View File
@@ -26,13 +26,14 @@ typedef unsigned int (*ufn_t)(void);
typedef unsigned int (* __cfi_salt ufn_salt_t)(void);
/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], {{[0-9]+}} /* [[#%d,LOW_SODIUM_HASH:]] */"
// CHECK: module asm ".weak __kcfi_typeid_[[F4_SALT:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4_SALT]], {{[0-9]+}} /* [[#%d,ASM_SALTY_HASH:]] */"
// CHECK: module asm
// CHECK-NEXT: ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK-NEXT: ".set __kcfi_typeid_[[F4]], {{[0-9]+}} /* [[#%d,LOW_SODIUM_HASH:]] */"
// CHECK-NEXT: ".weak __kcfi_typeid_[[F4_SALT:[a-zA-Z0-9_]+]]"
// CHECK-NEXT: ".set __kcfi_typeid_[[F4_SALT]], {{[0-9]+}} /* [[#%d,ASM_SALTY_HASH:]] */"
/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_f6"
// CHECK-NOT: ".weak __kcfi_typeid_f6"
int f1(void);
int f1_salt(void) __cfi_salt;
+4 -3
View File
@@ -6,10 +6,11 @@
#endif
/// Must emit __kcfi_typeid symbols for address-taken function declarations
// CHECK: module asm ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK: module asm ".set __kcfi_typeid_[[F4]], {{[0-9]+}} /* [[#%d,HASH:]] */"
// CHECK: module asm
// CHECK-NEXT: ".weak __kcfi_typeid_[[F4:[a-zA-Z0-9_]+]]"
// CHECK-NEXT: ".set __kcfi_typeid_[[F4]], {{[0-9]+}} /* [[#%d,HASH:]] */"
/// Must not __kcfi_typeid symbols for non-address-taken declarations
// CHECK-NOT: module asm ".weak __kcfi_typeid_{{f6|_Z2f6v}}"
// CHECK-NOT: ".weak __kcfi_typeid_{{f6|_Z2f6v}}"
// C: @ifunc1 = ifunc i32 (i32), ptr @resolver1
// C: @ifunc2 = ifunc i64 (i64), ptr @resolver2
+3 -2
View File
@@ -5,8 +5,9 @@
// This has to be at the top of the file as that's where file-scope
// asm ends up.
// CHECK-HOST: module asm "file scope asm is host only"
// CHECK-DEVICE-NOT: module asm "file scope asm is host only"
// CHECK-HOST: module asm
// CHECK-HOST-NEXT: "file scope asm is host only"
// CHECK-DEVICE-NOT: "file scope asm is host only"
__asm__("file scope asm is host only");
// CHECK-HOST: constantdata = internal global
+2 -1
View File
@@ -19,7 +19,8 @@ struct string_view {
namespace GH143242 {
constexpr string_view code2 = R"(nop; nop; nop; nop)";
asm((code2));
// CHECK: module asm "nop; nop; nop; nop"
// CHECK: module asm(target_features: "{{.*}}")
// CHECK-NEXT: "nop; nop; nop; nop"
}
int func() {return 0;};
+4 -3
View File
@@ -1,9 +1,10 @@
// RUN: %clang_cc1 -triple i386-apple-darwin9 -fobjc-runtime=macosx-fragile-10.5 -emit-llvm -o - %s | FileCheck %s
// PR7431
// CHECK: module asm "\09.lazy_reference .objc_class_name_A"
// CHECK: module asm "\09.objc_category_name_A_foo=0"
// CHECK: module asm "\09.globl .objc_category_name_A_foo"
// CHECK: module asm
// CHECK-NEXT: "\09.lazy_reference .objc_class_name_A"
// CHECK-NEXT: "\09.objc_category_name_A_foo=0"
// CHECK-NEXT: "\09.globl .objc_category_name_A_foo"
@interface A
@end
+4 -3
View File
@@ -3,9 +3,10 @@
// Check that the runtime name is emitted and used instead of the class
// identifier.
// CHECK: module asm {{.*}}objc_class_name_XYZ=0
// CHECK: module asm {{.*}}globl .objc_class_name_XYZ
// CHECK: module asm {{.*}}lazy_reference .objc_class_name_XYZ
// CHECK: module asm
// CHECK-NEXT: {{.*}}objc_class_name_XYZ=0
// CHECK-NEXT: {{.*}}globl .objc_class_name_XYZ
// CHECK-NEXT: {{.*}}lazy_reference .objc_class_name_XYZ
// CHECK: @[[OBJC_CLASS_NAME:.*]] = private unnamed_addr constant [4 x i8] c"XYZ{{.*}}, section "__TEXT,__cstring,cstring_literals",
// CHECK: = private global {{.*}} @[[OBJC_CLASS_NAME]], section "__OBJC,__cls_refs,literal_pointers,no_dead_strip"
+2 -1
View File
@@ -2,7 +2,8 @@
// RUN: %clang -target i386-unknown-unknown -emit-ast -o %t.ast %s
// RUN: %clang -target i386-unknown-unknown -emit-llvm -S -o - %t.ast | FileCheck %s
// CHECK: module asm "foo"
// CHECK: module asm(target_features: "{{.*}}")
// CHECK-NEXT: "foo"
__asm__("foo");
// CHECK: @g0 = dso_local global i32 0, align 4
+2 -1
View File
@@ -18,7 +18,8 @@ was implemented to workaround/support the initialization of iostreams
(implemented as a namespace scope static in the header - only to be provided
when that specific header is included in the program).
BOTH: module asm "narf"
BOTH: module asm
BOTH-NEXT: "narf"
FOO: $_Z2f1PKcz = comdat any
FOO: $_ZN13implicit_dtorD1Ev = comdat any
+21 -6
View File
@@ -3358,19 +3358,34 @@ Module-Level Inline Assembly
----------------------------
Modules may contain "module-level inline asm" blocks, which corresponds
to the GCC "file scope inline asm" blocks. These blocks are internally
concatenated by LLVM and treated as a single unit, but may be separated
in the ``.ll`` file if desired. The syntax is very simple:
to the GCC "file scope inline asm" blocks:
.. code-block:: llvm
module asm "inline asm code goes here"
module asm "more can go here"
module asm
"inline asm code goes here"
"more can go here"
The strings can contain any character by escaping non-printable
The sequence of string literals is internally concatenated using newlines as
separators. The strings can contain any character by escaping non-printable
characters. The escape sequence used is simply "\\xx" where "xx" is the
two digit hex code for the number.
Additionally, module-level inline assembly can specify an optional list of
properties:
.. code-block:: llvm
module asm(target_features: "+foo", target_cpu: "bar")
"inline asm code goes here"
"more can go here"
Currently, the only supported properties are ``target_features`` and
``target_cpu``, with the same meaning as the ``"target-features"`` and
``"target-cpu"`` function attributes.
Consecutive blocks with identical properties will be concatenated into one.
Note that the assembly string *must* be parseable by LLVM's integrated assembler
(unless it is disabled), even when emitting a ``.s`` file.
+4
View File
@@ -114,6 +114,10 @@ Makes programs 10x faster by doing Special New Thing.
* `alwaysinline` no longer bypasses inlining compatibility checks based on
target features. Inlining will only be performed if it is safe to do so.
* Module-level inline assembly now accepts optional `target_features` and
`target_cpu` properties. This resolves errors during LTO on some
architectures.
### Changes to LLVM infrastructure
* Removed ``Constant::isZeroValue``. It was functionally identical to
+2
View File
@@ -120,6 +120,8 @@ enum ModuleCodes {
// IFUNC: [ifunc value type, addrspace, resolver val#, linkage, visibility]
MODULE_CODE_IFUNC = 18,
MODULE_CODE_ASM_PROPERTY = 19, // [strchr x N]
};
/// PARAMATTR blocks have code for defining a parameter attribute set.
+13
View File
@@ -930,6 +930,19 @@ public:
const MCSubtargetInfo *EndInfo,
const MachineInstr *MI);
/// Emit necessary directives to allow use of instructions that are permitted
/// by target features enabled by STI, but are not permitted by target
/// features enabled by the global subtarget (TM.getSubTargetInfo()).
/// Returns whether anything was emitted.
virtual bool emitTargetFeaturePush(const MCSubtargetInfo &STI) {
return false;
}
/// Emit necessary directives to restore target feature state.
/// The \p DidPush argument is the result of the prior emitTargetFeaturePush()
/// call.
virtual void emitTargetFeaturePop(const MCSubtargetInfo &STI, bool DidPush) {}
/// This emits visibility information about symbol, if this is supported by
/// the target.
void emitVisibility(MCSymbol *Sym, unsigned Visibility,
+85 -11
View File
@@ -169,6 +169,45 @@ public:
: Behavior(B), Key(K), Val(V) {}
};
struct GlobalAsmProperties {
std::string TargetFeatures;
std::string TargetCPU;
/// Set a property using a string name.
/// Returns whether the property name was valid.
LLVM_ABI bool set(StringRef Name, std::string Value);
/// Get a list of set properties as pairs of key and value.
LLVM_ABI SmallVector<std::pair<StringRef, StringRef>> getAsStrings() const;
bool operator==(const GlobalAsmProperties &Other) const {
return TargetFeatures == Other.TargetFeatures &&
TargetCPU == Other.TargetCPU;
}
bool operator!=(const GlobalAsmProperties &Other) const {
return !(*this == Other);
}
};
struct GlobalAsmFragment {
std::string Asm;
GlobalAsmProperties Props;
GlobalAsmFragment(StringRef Asm) : GlobalAsmFragment(Asm.str()) {}
GlobalAsmFragment(std::string AsmArg, GlobalAsmProperties Props = {})
: Asm(std::move(AsmArg)), Props(std::move(Props)) {
if (!Asm.empty() && Asm.back() != '\n')
Asm += '\n';
}
bool empty() const { return Asm.empty(); }
bool hasSameProperties(const GlobalAsmFragment &Other) const {
return Props == Other.Props;
}
};
/// @}
/// @name Member Variables
/// @{
@@ -180,7 +219,8 @@ private:
AliasListType AliasList; ///< The Aliases in the module
IFuncListType IFuncList; ///< The IFuncs in the module
NamedMDListType NamedMDList; ///< The named metadata in the module
std::string GlobalScopeAsm; ///< Inline Asm at global scope.
/// Inline Asm at the global scope.
SmallVector<GlobalAsmFragment, 0> GlobalScopeAsm;
std::unique_ptr<ValueSymbolTable> ValSymTab; ///< Symbol table for values
ComdatSymTabType ComdatSymTab; ///< Symbol table for COMDATs
std::unique_ptr<MemoryBuffer>
@@ -287,8 +327,17 @@ public:
LLVMContext &getContext() const { return Context; }
/// Get any module-scope inline assembly blocks.
/// @returns a string containing the module-scope inline assembly blocks.
const std::string &getModuleInlineAsm() const { return GlobalScopeAsm; }
ArrayRef<GlobalAsmFragment> getModuleInlineAsm() const {
return GlobalScopeAsm;
}
/// Get any module-scope inline assembly blocks.
MutableArrayRef<GlobalAsmFragment> getModuleInlineAsm() {
return GlobalScopeAsm;
}
/// Return whether there is any module-scope inline assembly.
bool hasModuleInlineAsm() const { return !GlobalScopeAsm.empty(); }
/// Get a RandomNumberGenerator salted for use with this module. The
/// RNG can be seeded via -rng-seed=<uint64> and is salted with the
@@ -325,20 +374,45 @@ public:
/// Set the target triple.
void setTargetTriple(Triple T) { TargetTriple = std::move(T); }
void removeModuleInlineAsm() { GlobalScopeAsm.clear(); }
/// Set the module-scope inline assembly blocks.
/// A trailing newline is added if the input doesn't have one.
void setModuleInlineAsm(StringRef Asm) {
GlobalScopeAsm = std::string(Asm);
if (!GlobalScopeAsm.empty() && GlobalScopeAsm.back() != '\n')
GlobalScopeAsm += '\n';
void setModuleInlineAsm(GlobalAsmFragment Fragment) {
GlobalScopeAsm.clear();
appendModuleInlineAsm(std::move(Fragment));
}
void setModuleInlineAsm(ArrayRef<GlobalAsmFragment> Fragments) {
GlobalScopeAsm.clear();
append_range(GlobalScopeAsm, Fragments);
}
/// Append to the module-scope inline assembly blocks.
/// A trailing newline is added if the input doesn't have one.
void appendModuleInlineAsm(StringRef Asm) {
GlobalScopeAsm += Asm;
if (!GlobalScopeAsm.empty() && GlobalScopeAsm.back() != '\n')
GlobalScopeAsm += '\n';
void appendModuleInlineAsm(GlobalAsmFragment Fragment) {
if (Fragment.empty())
return;
if (!GlobalScopeAsm.empty() &&
GlobalScopeAsm.back().hasSameProperties(Fragment)) {
GlobalScopeAsm.back().Asm += Fragment.Asm;
} else {
GlobalScopeAsm.emplace_back(std::move(Fragment));
}
}
/// Prepend to the module-scope inline assembly blocks.
void prependModuleInlineAsm(GlobalAsmFragment Fragment) {
if (Fragment.empty())
return;
if (!GlobalScopeAsm.empty() &&
GlobalScopeAsm.front().hasSameProperties(Fragment)) {
GlobalScopeAsm.front().Asm.insert(0, Fragment.Asm);
} else {
GlobalScopeAsm.insert(GlobalScopeAsm.begin(), std::move(Fragment));
}
}
/// @}
+10
View File
@@ -13,6 +13,7 @@
#ifndef LLVM_TARGET_TARGETMACHINE_H
#define LLVM_TARGET_TARGETMACHINE_H
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/PassManager.h"
@@ -114,6 +115,9 @@ protected: // Can only create subclasses.
std::unique_ptr<const MCInstrInfo> MII;
std::unique_ptr<const MCSubtargetInfo> STI;
/// MC subtarget keyed by target features and target CPU.
StringMap<std::unique_ptr<const MCSubtargetInfo>> MCSubtargetMap;
unsigned RequireStructuredCFG : 1;
unsigned O0WantsFastISel : 1;
@@ -238,6 +242,12 @@ public:
const MCInstrInfo *getMCInstrInfo() const { return MII.get(); }
const MCSubtargetInfo &getMCSubtargetInfo() const { return *STI; }
/// Get the MCSubtargetInfo for the given target CPU and target features.
/// For use in contexts where a feature-specific MC subtarget is needed,
/// but no MachineFunctionis available, such as for module-level inline
/// assembly.
const MCSubtargetInfo &getMCSubtargetInfo(StringRef CPU, StringRef FS);
/// Return the ExceptionHandling to use, considering TargetOptions and the
/// Triple's default.
ExceptionHandling getExceptionModel() const {
+36 -3
View File
@@ -641,16 +641,49 @@ bool LLParser::parseTopLevelEntities() {
/// toplevelentity
/// ::= 'module' 'asm' STRINGCONSTANT
/// ::= 'module' 'asm' '(' 'property_name1:' STRINGCONSTANT ','
/// 'property_name2:' STRINGCONSTANT ')'
/// STRINGCONSTANT
bool LLParser::parseModuleAsm() {
assert(Lex.getKind() == lltok::kw_module);
Lex.Lex();
std::string AsmStr;
if (parseToken(lltok::kw_asm, "expected 'module asm'") ||
parseStringConstant(AsmStr))
if (parseToken(lltok::kw_asm, "expected 'module asm'"))
return true;
M->appendModuleInlineAsm(AsmStr);
Module::GlobalAsmProperties Props;
if (EatIfPresent(lltok::lparen)) {
while (true) {
std::string Key, Value;
SMLoc Loc = Lex.getLoc();
if (Lex.getKind() != lltok::LabelStr)
return error(Loc, "expected property name followed by ':'");
Key = Lex.getStrVal();
Lex.Lex();
if (parseStringConstant(Value))
return true;
if (!Props.set(Key, Value))
return error(Loc, "unknown property name");
if (EatIfPresent(lltok::rparen))
break;
if (parseToken(lltok::comma, "expected ',' or ')'"))
return true;
}
}
do {
std::string AsmStrPart;
if (parseStringConstant(AsmStrPart))
return true;
AsmStr += AsmStrPart + "\n";
} while (Lex.getKind() == lltok::StringConstant);
M->appendModuleInlineAsm({AsmStr, Props});
return false;
}
+16 -1
View File
@@ -4600,6 +4600,9 @@ Error BitcodeReader::parseModule(uint64_t ResumeBit,
// Initialize to the current module's layout string in case none is specified.
std::string TentativeDataLayoutStr = TheModule->getDataLayoutStr();
// Apply to the following module asm.
Module::GlobalAsmProperties Props;
auto ResolveDataLayout = [&]() -> Error {
if (ResolvedDataLayout)
return Error::success();
@@ -4808,11 +4811,23 @@ Error BitcodeReader::parseModule(uint64_t ResumeBit,
return error("Invalid data layout record");
break;
}
case bitc::MODULE_CODE_ASM_PROPERTY: {
std::string Str;
if (convertToString(Record, 0, Str))
return error("Invalid module asm record");
size_t SepPos = Str.find('\0');
if (SepPos == std::string::npos)
return error("Invalid module asm record");
if (!Props.set(StringRef(Str.data(), SepPos), Str.substr(SepPos + 1)))
return error("Unknown module asm property");
break;
}
case bitc::MODULE_CODE_ASM: { // ASM: [strchr x N]
std::string S;
if (convertToString(Record, 0, S))
return error("Invalid asm record");
TheModule->setModuleInlineAsm(S);
TheModule->appendModuleInlineAsm(Module::GlobalAsmFragment(S, Props));
Props = {};
break;
}
case bitc::MODULE_CODE_DEPLIB: { // DEPLIB: [strchr x N]
+13 -3
View File
@@ -1551,9 +1551,19 @@ void ModuleBitcodeWriter::writeModuleInfo() {
const std::string &DL = M.getDataLayoutStr();
if (!DL.empty())
writeStringRecord(Stream, bitc::MODULE_CODE_DATALAYOUT, DL, 0 /*TODO*/);
if (!M.getModuleInlineAsm().empty())
writeStringRecord(Stream, bitc::MODULE_CODE_ASM, M.getModuleInlineAsm(),
0 /*TODO*/);
for (const Module::GlobalAsmFragment &Frag : M.getModuleInlineAsm()) {
SmallVector<std::pair<StringRef, StringRef>> Props =
Frag.Props.getAsStrings();
for (auto [Key, Value] : Props) {
SmallVector<unsigned, 64> Record;
Record.append(Key.begin(), Key.end());
Record.push_back(0);
Record.append(Value.begin(), Value.end());
Stream.EmitRecord(bitc::MODULE_CODE_ASM_PROPERTY, Record);
}
writeStringRecord(Stream, bitc::MODULE_CODE_ASM, Frag.Asm, 0 /*TODO*/);
}
// Emit information about sections and GC, computing how many there are. Also
// compute the maximum alignment value.
+11 -6
View File
@@ -110,6 +110,7 @@
#include "llvm/MC/MCTargetOptions.h"
#include "llvm/MC/MCValue.h"
#include "llvm/MC/SectionKind.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Object/ELFTypes.h"
#include "llvm/Pass.h"
#include "llvm/Remarks/RemarkStreamer.h"
@@ -127,7 +128,6 @@
#include "llvm/Target/TargetLoweringObjectFile.h"
#include "llvm/Target/TargetMachine.h"
#include "llvm/Target/TargetOptions.h"
#include "llvm/TargetParser/Triple.h"
#include <algorithm>
#include <cassert>
#include <cinttypes>
@@ -610,13 +610,18 @@ bool AsmPrinter::doInitialization(Module &M) {
BeginGCAssembly(M);
// Emit module-level inline asm if it exists.
if (!M.getModuleInlineAsm().empty()) {
if (M.hasModuleInlineAsm()) {
OutStreamer->AddComment("Start of file scope inline assembly");
OutStreamer->addBlankLine();
emitInlineAsm(
M.getModuleInlineAsm() + "\n", TM.getMCSubtargetInfo(),
TM.Options.MCOptions, nullptr,
InlineAsm::AsmDialect(TM.getMCAsmInfo().getAssemblerDialect()));
for (const Module::GlobalAsmFragment &Frag : M.getModuleInlineAsm()) {
const MCSubtargetInfo &AsmSTI = TM.getMCSubtargetInfo(
Frag.Props.TargetCPU, Frag.Props.TargetFeatures);
bool DidPush = emitTargetFeaturePush(AsmSTI);
emitInlineAsm(
Frag.Asm, AsmSTI, TM.Options.MCOptions, nullptr,
InlineAsm::AsmDialect(TM.getMCAsmInfo().getAssemblerDialect()));
emitTargetFeaturePop(AsmSTI, DidPush);
}
OutStreamer->AddComment("End of file scope inline assembly");
OutStreamer->addBlankLine();
}
+29 -12
View File
@@ -3126,21 +3126,38 @@ void AssemblyWriter::printModule(const Module *M) {
if (!M->getTargetTriple().empty())
Out << "target triple = \"" << M->getTargetTriple().str() << "\"\n";
if (!M->getModuleInlineAsm().empty()) {
if (M->hasModuleInlineAsm()) {
Out << '\n';
// Split the string into lines, to make it easier to read the .ll file.
StringRef Asm = M->getModuleInlineAsm();
do {
StringRef Front;
std::tie(Front, Asm) = Asm.split('\n');
for (const Module::GlobalAsmFragment &Frag : M->getModuleInlineAsm()) {
Out << "module asm";
SmallVector<std::pair<StringRef, StringRef>> Props =
Frag.Props.getAsStrings();
if (!Props.empty()) {
ListSeparator LS;
Out << "(";
for (auto [Key, Value] : Props) {
Out << LS;
Out << Key << ": \"";
printEscapedString(Value, Out);
Out << "\"";
}
Out << ")";
}
Out << "\n";
// Split the string into lines, to make it easier to read the .ll file.
StringRef Asm = Frag.Asm;
do {
StringRef Front;
std::tie(Front, Asm) = Asm.split('\n');
// We found a newline, print the portion of the asm string from the
// last newline up to this newline.
Out << "module asm \"";
printEscapedString(Front, Out);
Out << "\"\n";
} while (!Asm.empty());
// We found a newline, print the portion of the asm string from the
// last newline up to this newline.
Out << " \"";
printEscapedString(Front, Out);
Out << "\"\n";
} while (!Asm.empty());
}
}
printTypeIdentities();
+12 -1
View File
@@ -510,7 +510,18 @@ void LLVMAppendModuleInlineAsm(LLVMModuleRef M, const char *Asm, size_t Len) {
}
const char *LLVMGetModuleInlineAsm(LLVMModuleRef M, size_t *Len) {
auto &Str = unwrap(M)->getModuleInlineAsm();
Module *Mod = unwrap(M);
ArrayRef<Module::GlobalAsmFragment> Frags = Mod->getModuleInlineAsm();
if (Frags.empty()) {
*Len = 0;
return nullptr;
}
if (Frags.size() != 1)
reportFatalUsageError("LLVMGetModuleInlineAsm is not supported if there is "
"more than one module inline assembly fragment");
auto &Str = Frags.begin()->Asm;
*Len = Str.length();
return Str.c_str();
}
+20
View File
@@ -977,3 +977,23 @@ ControlFlowGuardMode Module::getControlFlowGuardMode() const {
return static_cast<ControlFlowGuardMode>(CI->getZExtValue());
return ControlFlowGuardMode::Disabled;
}
bool Module::GlobalAsmProperties::set(StringRef Name, std::string Value) {
if (Name == "target_features")
TargetFeatures = std::move(Value);
else if (Name == "target_cpu")
TargetCPU = std::move(Value);
else
return false;
return true;
}
SmallVector<std::pair<StringRef, StringRef>>
Module::GlobalAsmProperties::getAsStrings() const {
SmallVector<std::pair<StringRef, StringRef>> Props;
if (!TargetFeatures.empty())
Props.emplace_back("target_features", TargetFeatures);
if (!TargetCPU.empty())
Props.emplace_back("target_cpu", TargetCPU);
return Props;
}
+2 -2
View File
@@ -1112,7 +1112,7 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
// Prepend ".lto_discard <sym>, <sym>*" directive to each module inline asm
// block.
if (!M.getModuleInlineAsm().empty()) {
if (M.hasModuleInlineAsm()) {
std::string NewIA = ".lto_discard";
if (!NonPrevailingAsmSymbols.empty()) {
// Don't dicard a symbol if there is a live .symver for it.
@@ -1124,7 +1124,7 @@ LTO::addRegularLTO(InputFile &Input, ArrayRef<SymbolResolution> InputRes,
NewIA += " " + llvm::join(NonPrevailingAsmSymbols, ", ");
}
NewIA += "\n";
M.setModuleInlineAsm(NewIA + M.getModuleInlineAsm());
M.prependModuleInlineAsm(NewIA);
}
assert(MsymI == MsymE);
+6 -3
View File
@@ -1562,8 +1562,11 @@ Error IRLinker::run() {
if (!IsPerformingImport && !SrcM->getModuleInlineAsm().empty()) {
// Append the module inline asm string.
DstM.appendModuleInlineAsm(adjustInlineAsm(SrcM->getModuleInlineAsm(),
SrcTriple));
for (const Module::GlobalAsmFragment &Frag : SrcM->getModuleInlineAsm()) {
Module::GlobalAsmFragment NewFrag(Frag);
NewFrag.Asm = adjustInlineAsm(NewFrag.Asm, SrcTriple);
DstM.appendModuleInlineAsm(std::move(NewFrag));
}
} else if (IsPerformingImport) {
// Import any symver directives for symbols in DstM.
ModuleSymbolTable::CollectAsmSymvers(*SrcM,
@@ -1573,7 +1576,7 @@ Error IRLinker::run() {
S += Name;
S += ", ";
S += Alias;
DstM.appendModuleInlineAsm(S);
DstM.appendModuleInlineAsm(std::string(S));
}
});
}
+38 -36
View File
@@ -72,8 +72,7 @@ initializeRecordStreamer(const Module &M,
// caused errors in the first run, suppress the second run.
if (M.getContext().getDiagHandlerPtr()->HasErrors)
return;
StringRef InlineAsm = M.getModuleInlineAsm();
if (InlineAsm.empty())
if (!M.hasModuleInlineAsm())
return;
std::string Err;
@@ -90,52 +89,55 @@ initializeRecordStreamer(const Module &M,
if (!MAI)
return;
std::unique_ptr<MCSubtargetInfo> STI(T->createMCSubtargetInfo(TT, "", ""));
if (!STI)
return;
std::unique_ptr<MCInstrInfo> MCII(T->createMCInstrInfo());
if (!MCII)
return;
std::unique_ptr<MemoryBuffer> Buffer(
MemoryBuffer::getMemBuffer(InlineAsm, "<inline asm>"));
SourceMgr SrcMgr;
SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
for (const Module::GlobalAsmFragment &Frag : M.getModuleInlineAsm()) {
std::unique_ptr<MCSubtargetInfo> STI(T->createMCSubtargetInfo(
TT, Frag.Props.TargetCPU, Frag.Props.TargetFeatures));
if (!STI)
return;
MCContext MCCtx(TT, *MAI, *MRI, *STI, &SrcMgr);
std::unique_ptr<MCObjectFileInfo> MOFI(
T->createMCObjectFileInfo(MCCtx, /*PIC=*/false));
MCCtx.setObjectFileInfo(MOFI.get());
RecordStreamer Streamer(MCCtx, M);
T->createNullTargetStreamer(Streamer);
std::unique_ptr<MemoryBuffer> Buffer(
MemoryBuffer::getMemBuffer(Frag.Asm, "<inline asm>"));
SourceMgr SrcMgr;
SrcMgr.AddNewSourceBuffer(std::move(Buffer), SMLoc());
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, MCCtx, Streamer, *MAI));
MCContext MCCtx(TT, *MAI, *MRI, *STI, &SrcMgr);
std::unique_ptr<MCObjectFileInfo> MOFI(
T->createMCObjectFileInfo(MCCtx, /*PIC=*/false));
MCCtx.setObjectFileInfo(MOFI.get());
RecordStreamer Streamer(MCCtx, M);
T->createNullTargetStreamer(Streamer);
std::unique_ptr<MCTargetAsmParser> TAP(
T->createMCAsmParser(*STI, *Parser, *MCII));
if (!TAP)
return;
std::unique_ptr<MCAsmParser> Parser(
createMCAsmParser(SrcMgr, MCCtx, Streamer, *MAI));
MCCtx.setDiagnosticHandler([&](const SMDiagnostic &SMD, bool IsInlineAsm,
const SourceMgr &SrcMgr,
std::vector<const MDNode *> &LocInfos) {
M.getContext().diagnose(
DiagnosticInfoSrcMgr(SMD, M.getName(), IsInlineAsm, /*LocCookie=*/0));
});
std::unique_ptr<MCTargetAsmParser> TAP(
T->createMCAsmParser(*STI, *Parser, *MCII));
if (!TAP)
return;
// Module-level inline asm is assumed to use At&t syntax (see
// AsmPrinter::doInitialization()).
Parser->setAssemblerDialect(InlineAsm::AD_ATT);
MCCtx.setDiagnosticHandler([&](const SMDiagnostic &SMD, bool IsInlineAsm,
const SourceMgr &SrcMgr,
std::vector<const MDNode *> &LocInfos) {
M.getContext().diagnose(
DiagnosticInfoSrcMgr(SMD, M.getName(), IsInlineAsm, /*LocCookie=*/0));
});
Parser->setSymbolScanningMode(true);
// Module-level inline asm is assumed to use At&t syntax (see
// AsmPrinter::doInitialization()).
Parser->setAssemblerDialect(InlineAsm::AD_ATT);
Parser->setTargetParser(*TAP);
if (Parser->Run(false))
return;
Parser->setSymbolScanningMode(true);
Init(Streamer);
Parser->setTargetParser(*TAP);
if (Parser->Run(false))
return;
Init(Streamer);
}
}
void ModuleSymbolTable::CollectAsmSymbols(
+14 -9
View File
@@ -113,7 +113,8 @@ public:
void emitEndOfAsmFile(Module &M) override;
void emitFunctionEntryLabel() override;
bool emitDirectiveOptionArch();
bool emitTargetFeaturePush(const MCSubtargetInfo &STI) override;
void emitTargetFeaturePop(const MCSubtargetInfo &STI, bool DidPush) override;
void emitNoteGnuProperty(const Module &M);
@@ -523,19 +524,19 @@ bool RISCVAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
return false;
}
bool RISCVAsmPrinter::emitDirectiveOptionArch() {
bool RISCVAsmPrinter::emitTargetFeaturePush(const MCSubtargetInfo &STI) {
RISCVTargetStreamer &RTS = getTargetStreamer();
SmallVector<RISCVOptionArchArg> NeedEmitStdOptionArgs;
const MCSubtargetInfo &MCSTI = TM.getMCSubtargetInfo();
for (const auto &Feature : MCSTI.getAllProcessorFeatures()) {
if (STI->hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
if (STI.hasFeature(Feature.Value) == MCSTI.hasFeature(Feature.Value))
continue;
if (!llvm::RISCVISAInfo::isSupportedExtensionFeature(Feature.key()))
continue;
auto Delta = STI->hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus
: RISCVOptionArchArgType::Minus;
auto Delta = STI.hasFeature(Feature.Value) ? RISCVOptionArchArgType::Plus
: RISCVOptionArchArgType::Minus;
StringRef ExtName = Feature.key();
ExtName.consume_front("experimental-");
NeedEmitStdOptionArgs.emplace_back(Delta, ExtName.str());
@@ -549,11 +550,16 @@ bool RISCVAsmPrinter::emitDirectiveOptionArch() {
return false;
}
void RISCVAsmPrinter::emitTargetFeaturePop(const MCSubtargetInfo &STI,
bool DidPush) {
if (DidPush)
getTargetStreamer().emitDirectiveOptionPop();
}
bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
STI = &MF.getSubtarget<RISCVSubtarget>();
RISCVTargetStreamer &RTS = getTargetStreamer();
bool EmittedOptionArch = emitDirectiveOptionArch();
bool EmittedOptionArch = emitTargetFeaturePush(*STI);
SetupMachineFunction(MF);
emitFunctionBody();
@@ -561,8 +567,7 @@ bool RISCVAsmPrinter::runOnMachineFunction(MachineFunction &MF) {
// Emit the XRay table
emitXRayTable();
if (EmittedOptionArch)
RTS.emitDirectiveOptionPop();
emitTargetFeaturePop(*STI, EmittedOptionArch);
return false;
}
+1 -1
View File
@@ -955,7 +955,7 @@ bool SPIRVAsmPrinter::doInitialization(Module &M) {
if (!M.getModuleInlineAsm().empty()) {
M.getContext().emitError(
"SPIR-V does not support module-level inline assembly");
M.setModuleInlineAsm("");
M.removeModuleInlineAsm();
}
// Register the NSDI handler before calling the base class so that
+14
View File
@@ -23,6 +23,7 @@
#include "llvm/MC/MCRegisterInfo.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/TargetRegistry.h"
#include "llvm/Support/CodeGen.h"
#include "llvm/Target/TargetLoweringObjectFile.h"
using namespace llvm;
@@ -311,3 +312,16 @@ std::pair<int, int> TargetMachine::parseBinutilsVersion(StringRef Version) {
Version.consumeInteger(10, Ret.second);
return Ret;
}
const MCSubtargetInfo &TargetMachine::getMCSubtargetInfo(StringRef CPU,
StringRef FS) {
if (CPU.empty() && FS.empty())
return *STI;
SmallString<128> Key = CPU;
Key += '/';
Key += FS;
auto &Entry = MCSubtargetMap[Key];
if (!Entry)
Entry.reset(getTarget().createMCSubtargetInfo(getTargetTriple(), CPU, FS));
return *Entry;
}
+1 -1
View File
@@ -58,7 +58,7 @@ ExtractGVPass::ExtractGVPass(std::vector<GlobalValue *> &GVs, bool deleteS,
PreservedAnalyses ExtractGVPass::run(Module &M, ModuleAnalysisManager &) {
// Visit the global inline asm.
if (!deleteStuff)
M.setModuleInlineAsm("");
M.removeModuleInlineAsm();
// For simplicity, just give all GlobalValues ExternalLinkage. A trickier
// implementation could figure out which GlobalValues are actually
@@ -388,7 +388,7 @@ void splitAndWriteThinLTOBitcode(
return false;
}));
StripDebugInfo(*MergedM);
MergedM->setModuleInlineAsm("");
MergedM->removeModuleInlineAsm();
// Clone any llvm.*used globals to ensure the included values are
// not deleted.
@@ -1283,18 +1283,20 @@ void DataFlowSanitizer::addGlobalNameSuffix(GlobalValue *GV) {
// corrupting asm which happens to contain the symbol name as a substring.
// Note that the substitution for .symver assumes that the versioned symbol
// also has an instrumented name.
std::string Asm = GV->getParent()->getModuleInlineAsm();
std::string SearchStr = ".symver " + GVName + ",";
size_t Pos = Asm.find(SearchStr);
if (Pos != std::string::npos) {
Asm.replace(Pos, SearchStr.size(), ".symver " + GVName + Suffix + ",");
Pos = Asm.find('@');
for (Module::GlobalAsmFragment &Frag :
GV->getParent()->getModuleInlineAsm()) {
std::string SearchStr = ".symver " + GVName + ",";
size_t Pos = Frag.Asm.find(SearchStr);
if (Pos != std::string::npos) {
Frag.Asm.replace(Pos, SearchStr.size(),
".symver " + GVName + Suffix + ",");
Pos = Frag.Asm.find('@');
if (Pos == std::string::npos)
report_fatal_error(Twine("unsupported .symver: ", Asm));
if (Pos == std::string::npos)
report_fatal_error(Twine("unsupported .symver: ", Frag.Asm));
Asm.replace(Pos, 1, Suffix + "@");
GV->getParent()->setModuleInlineAsm(Asm);
Frag.Asm.replace(Pos, 1, Suffix + "@");
}
}
}
+1 -1
View File
@@ -304,7 +304,7 @@ void llvm::SplitModule(
return isInPartition(GV, I, N);
}));
if (I != 0)
MPart->setModuleInlineAsm("");
MPart->removeModuleInlineAsm();
ModuleCallback(std::move(MPart));
}
}
+25
View File
@@ -0,0 +1,25 @@
; RUN: split-file %s %t
; RUN: not llvm-as -disable-output < %t/invalid_prop.ll 2>&1 | FileCheck %t/invalid_prop.ll
; RUN: not llvm-as -disable-output < %t/missing_value1.ll 2>&1 | FileCheck %t/missing_value1.ll
; RUN: not llvm-as -disable-output < %t/missing_value2.ll 2>&1 | FileCheck %t/missing_value2.ll
; RUN: not llvm-as -disable-output < %t/missing_paren.ll 2>&1 | FileCheck %t/missing_paren.ll
;--- invalid_prop.ll
; CHECK: unknown property name
module asm(foo: "bar")
"asm"
;--- missing_value1.ll
; CHECK: expected property name followed by ':'
module asm(target_features)
"asm"
;--- missing_value2.ll
; CHECK: expected string constant
module asm(target_features:)
"asm"
;--- missing_paren.ll
; CHECK: expected ',' or ')'
module asm(target_features: "bar"
"asm"
+2 -1
View File
@@ -14,7 +14,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -14,7 +14,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -13,7 +13,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -13,7 +13,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -13,7 +13,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -13,7 +13,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -13,7 +13,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -16,7 +16,8 @@ target triple = "x86_64-apple-macosx10.10.0"
;; Module-level assembly
module asm "beep boop"
; CHECK: module asm "beep boop"
; CHECK: module asm
; CHECK-NEXT: "beep boop"
;; Comdats
$comdat.any = comdat any
+2 -1
View File
@@ -9,7 +9,8 @@
target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v16:16:16-v24:32:32-v32:32:32-v48:64:64-v64:64:64-v96:128:128-v128:128:128-v192:256:256-v256:256:256-v512:512:512-v1024:1024:1024-a0:0:64-f80:32:32-n8:16:32-S32"
; Module-Level Inline Assembly Test
; CHECK: module asm "some assembly"
; CHECK: module asm
; CHECK-NEXT: "some assembly"
module asm "some assembly"
; Named Types Test
+29
View File
@@ -0,0 +1,29 @@
; RUN: llvm-as < %s | llvm-dis | FileCheck %s
; CHECK: module asm
; CHECK: "asm line 0"
; CHECK: module asm(target_features: "+foo", target_cpu: "foo_cpu")
; CHECK: "asm line 1"
; CHECK: "asm line 2"
; CHECK: module asm(target_features: "+bar")
; CHECK: "asm line 3"
; CHECK: module asm(target_cpu: "bar_cpu")
; CHECK: "asm line 4"
; CHECK: module asm
; CHECK: "asm line 5"
module asm
"asm line 0"
module asm(target_features: "+foo", target_cpu: "foo_cpu")
"asm line 1"
"asm line 2"
module asm(target_features: "+bar")
"asm line 3"
module asm(target_cpu: "bar_cpu")
"asm line 4"
module asm
"asm line 5"
@@ -0,0 +1,17 @@
; RUN: llc -mtriple=riscv64-unknown-linux-gnu < %s | FileCheck %s --check-prefixes=CHECK,EXTRA-FEATURES
; RUN: llc -mtriple=riscv64-unknown-linux-gnu -mattr=+d < %s | FileCheck %s --check-prefixes=CHECK,SAME-FEATURES
; This should work fine, because the module asm specifies the necessary
; target features
; SAME-FEATURES-NOT: .option arch
; EXTRA-FEATURES: .option push
; EXTRA-FEATURES: .option arch, +d
; CHECK: fld ft0, 0(sp)
; EXTRA-FEATURES: .option pop
module asm(target_features: "+d")
".globl func"
"func:"
"fld f0, 0(sp)"
"ret"
@@ -2,7 +2,8 @@
target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"
; CHECK: module asm ".symver f1.dfsan,f.dfsan@@version1"
; CHECK: module asm
; CHECK-NEXT: ".symver f1.dfsan,f.dfsan@@version1"
module asm ".symver f1,f@@version1"
; CHECK: @f2.dfsan = alias {{.*}} @f1.dfsan
+18
View File
@@ -0,0 +1,18 @@
; RUN: llvm-as %s -o %t.o
; RUN: llvm-lto2 run -save-temps -filetype=asm -o %t.s %t.o -r=%t.o,func,p
; RUN: llvm-nm %t.o | FileCheck %s --check-prefix NM
; RUN: llvm-nm %t.s.0.5.precodegen.bc | FileCheck %s --check-prefix NM
; RUN: FileCheck %s --input-file %t.s.0
; NM: T func
; CHECK: fld ft0, 0(sp)
target datalayout = "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128"
target triple = "riscv64-unknown-linux-gnu"
module asm(target_features: "+d")
".globl func"
"func:"
"fld f0, 0(sp)"
"ret"
+11 -9
View File
@@ -32,17 +32,19 @@
; RUN: -r %t4,foo@@VER1,px
; RUN: llvm-dis < %to3.0.0.preopt.bc | FileCheck %s --check-prefix=ASM3
; ASM1: module asm ".lto_discard foo"
; ASM1-NEXT: module asm ".weak foo"
; ASM1-NEXT: module asm ".equ foo,bar"
; ASM1: module asm
; ASM1-NEXT: ".lto_discard foo"
; ASM1-NEXT: ".weak foo"
; ASM1-NEXT: ".equ foo,bar"
; ASM2: module asm ".lto_discard foo"
; ASM2-NEXT: module asm ".weak foo"
; ASM2-NEXT: module asm ".equ foo,bar"
; ASM2-NEXT: module asm ".lto_discard"
; ASM2-NEXT: module asm " .global foo ; foo: leal 2(%rdi), %eax"
; ASM2: module asm
; ASM2-NEXT: ".lto_discard foo"
; ASM2-NEXT: ".weak foo"
; ASM2-NEXT: ".equ foo,bar"
; ASM2-NEXT: ".lto_discard"
; ASM2-NEXT: " .global foo ; foo: leal 2(%rdi), %eax"
; ASM3-NOT: module asm ".lto_discard foo"
; ASM3-NOT: ".lto_discard foo"
; SYM: T foo
+2
View File
@@ -0,0 +1,2 @@
module asm(target_features: "+bar")
"asm 2"
@@ -9,11 +9,12 @@ target triple = "armv7-linux-gnueabihf"
module asm "add r1, r2, r2"
; CHECK: module asm ".text"
; CHECK-NEXT: module asm ".balign 4"
; CHECK-NEXT: module asm ".arm"
; CHECK-NEXT: module asm "add r1, r2, r2"
; CHECK-NEXT: module asm ".text"
; CHECK-NEXT: module asm ".balign 2"
; CHECK-NEXT: module asm ".thumb"
; CHECK-NEXT: module asm "orn r1, r2, r2"
; CHECK: module asm
; CHECK-NEXT: ".text"
; CHECK-NEXT: ".balign 4"
; CHECK-NEXT: ".arm"
; CHECK-NEXT: "add r1, r2, r2"
; CHECK-NEXT: ".text"
; CHECK-NEXT: ".balign 2"
; CHECK-NEXT: ".thumb"
; CHECK-NEXT: "orn r1, r2, r2"
+9
View File
@@ -0,0 +1,9 @@
; RUN: llvm-link %s %p/Inputs/module-asm.ll -S | FileCheck %s
; CHECK: module asm(target_features: "+foo")
; CHECK-NEXT: "asm 1"
; CHECK: module asm(target_features: "+bar")
; CHECK-NEXT: "asm 2"
module asm(target_features: "+foo")
"asm 1"
+2 -1
View File
@@ -9,7 +9,8 @@
; RUN: llvm-dis %t1.bc.thinlto.imported.bc -o - | FileCheck --check-prefix=NOIMPORT %s
; When @bar gets imported, the symver must be imported too.
; IMPORT: module asm ".symver bar, bar@BAR_1.2.3"
; IMPORT: module asm
; IMPORT-NEXT: ".symver bar, bar@BAR_1.2.3"
; IMPORT: declare dso_local i32 @bar()
; When @bar isn't imported, the symver is also not imported.
@@ -1,6 +1,7 @@
; RUN: opt -S %s -passes=lowertypetests -lowertypetests-summary-action=export -lowertypetests-read-summary=%S/Inputs/exported-funcs.yaml | FileCheck %s
;
; CHECK: module asm ".symver external_addrtaken, alias1"
; CHECK: module asm
; CHECK-NEXT: ".symver external_addrtaken, alias1"
; CHECK-NOT: .symver external_addrtaken2
; CHECK-NOT: .symver not_exported
@@ -3,7 +3,8 @@
target triple = "x86_64-unknown-linux-gnu"
; CHECK: module asm ".lto_set_conditional a,a.[[HASH:[0-9a-f]+]]"
; CHECK: module asm
; CHECK-NEXT: ".lto_set_conditional a,a.[[HASH:[0-9a-f]+]]"
define void @b() {
%f = alloca ptr, align 8
@@ -7,6 +7,7 @@ target triple = "x86_64-unknown-linux-gnu"
@g = constant i32 0, !type !0
!0 = !{i32 0, !"typeid"}
; M0: module asm "ret"
; M0: module asm
; M0-NEXT: "ret"
; M1-NOT: module asm
module asm "ret"
@@ -23,5 +23,5 @@ void llvm::reduceModuleDataDeltaPass(Oracle &O, ReducerWorkItem &WorkItem) {
Program.setSourceFileName("");
// TODO: clear line by line rather than all at once
if (!Program.getModuleInlineAsm().empty() && !O.shouldKeep())
Program.setModuleInlineAsm("");
Program.removeModuleInlineAsm();
}
+7 -4
View File
@@ -1150,12 +1150,15 @@ void ModuleImport::convertTargetTriple() {
}
void ModuleImport::convertModuleLevelAsm() {
llvm::StringRef asmStr = llvmModule->getModuleInlineAsm();
llvm::SmallVector<mlir::Attribute> asmArrayAttr;
for (llvm::StringRef line : llvm::split(asmStr, '\n'))
if (!line.empty())
asmArrayAttr.push_back(builder.getStringAttr(line));
for (const llvm::Module::GlobalAsmFragment &Frag :
llvmModule->getModuleInlineAsm()) {
// TODO: Preserve module asm properties.
for (llvm::StringRef line : llvm::split(Frag.Asm, '\n'))
if (!line.empty())
asmArrayAttr.push_back(builder.getStringAttr(line));
}
mlirModule->setAttr(LLVM::LLVMDialect::getModuleLevelAsmAttrName(),
builder.getArrayAttr(asmArrayAttr));
+3 -2
View File
@@ -2,5 +2,6 @@
module attributes {llvm.module_asm = ["foo", "bar"]} {}
// CHECK: module asm "foo"
// CHECK: module asm "bar"
// CHECK: module asm
// CHECK-NEXT: "foo"
// CHECK-NEXT: "bar"