https://github.com/erichkeane updated https://github.com/llvm/llvm-project/pull/179811
>From 51f2bb6552c9829ebe5d4888d1503a11645da2ef Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Tue, 3 Feb 2026 09:41:44 -0800 Subject: [PATCH 1/3] [CIR] Add tons of function infra, plus a handful of attributes This patch puts together a lot more of the CIR infrastructure for function attributes, plus adds a bunch of 'TODO' messages for areas that have been skipped. Along the way, we also implement 8 attributes in some way: -Convergent gets a little more work, to make the `noconvergent` C attribute have an effect -optsize/minsize are implemented, sourced from the command line -nobuiltin is a call-only attribute that tells not to replace the individual call with a builtin. This is a touch confusing, since no-builtins is an attribute that means "don't replace anything in the body of this function with builtins (from this list)". The spelling confusion is existing, and it seems that changing the names away from LLVM would be confusing. -save_reg_params & zero_call_used_regs are boht pretty simple registers -temp-func-name just passes a string to LLVM, consistent with existing implementation. -default-func-attrs is a difficult one. It takes command line arguments and passes them as LLVM-IR attributes directly on functions/calls. In the dialect, we are capturing these in their own attribute to pass them on correctly. However, this is one we cannot recover from LLVM-IR for obvious reasons, so we instead choose to let the 'passthrough' mechanism work for those. --- .../clang/CIR/Dialect/IR/CIRDialect.td | 10 + clang/lib/CIR/CodeGen/CIRGenCall.cpp | 207 +++++++++++++++++- clang/lib/CIR/CodeGen/CIRGenModule.h | 6 + .../CodeGen/default-func-attrs-cmd-line.cpp | 29 +++ .../CIR/CodeGen/no-builtin-attr-automatic.cpp | 83 +++++++ .../CIR/CodeGen/offload-convergent-attr.cu | 45 ++++ clang/test/CIR/CodeGen/optsize-func-attr.cpp | 74 +++++++ .../CIR/CodeGen/save-reg-params-func-attr.cpp | 29 +++ .../test/CIR/CodeGen/trap-func-name-attr.cpp | 33 +++ .../CodeGen/zero-call-used-regs-func-attr.cpp | 102 +++++++++ .../CodeGenBuiltins/X86/avx512-reduceIntrin.c | 8 +- .../X86/avx512-reduceMinMaxIntrin.c | 8 +- .../CodeGenBuiltins/X86/avx512fp16-builtins.c | 8 +- .../X86/avx512vlbf16-builtins.c | 12 +- .../X86/avx512vlfp16-builtins.c | 16 +- mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td | 10 + .../mlir/Target/LLVMIR/ModuleTranslation.h | 30 ++- mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp | 20 +- .../LLVMIR/LLVMToLLVMIRTranslation.cpp | 21 ++ mlir/lib/Target/LLVMIR/ModuleImport.cpp | 29 +++ mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 11 + mlir/test/Dialect/LLVMIR/func.mlir | 24 ++ mlir/test/Dialect/LLVMIR/roundtrip.mlir | 21 ++ .../LLVMIR/Import/function-attributes.ll | 32 +++ .../test/Target/LLVMIR/Import/instructions.ll | 87 ++++++++ mlir/test/Target/LLVMIR/llvmir.mlir | 190 ++++++++++++++++ 26 files changed, 1101 insertions(+), 44 deletions(-) create mode 100644 clang/test/CIR/CodeGen/default-func-attrs-cmd-line.cpp create mode 100644 clang/test/CIR/CodeGen/no-builtin-attr-automatic.cpp create mode 100644 clang/test/CIR/CodeGen/offload-convergent-attr.cu create mode 100644 clang/test/CIR/CodeGen/optsize-func-attr.cpp create mode 100644 clang/test/CIR/CodeGen/save-reg-params-func-attr.cpp create mode 100644 clang/test/CIR/CodeGen/trap-func-name-attr.cpp create mode 100644 clang/test/CIR/CodeGen/zero-call-used-regs-func-attr.cpp diff --git a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td index c06807efbb83a..3e134d952b8b5 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIRDialect.td +++ b/clang/include/clang/CIR/Dialect/IR/CIRDialect.td @@ -54,6 +54,8 @@ def CIR_Dialect : Dialect { static llvm::StringRef getNoCallerSavedRegsAttrName() { return "no_caller_saved_registers"; } static llvm::StringRef getNoCallbackAttrName() { return "nocallback"; } static llvm::StringRef getAllocSizeAttrName() { return "allocsize"; } + static llvm::StringRef getOptimizeForSizeAttrName() { return "optsize"; } + static llvm::StringRef getMinSizeAttrName() { return "minsize"; } // Note: we have to name this with the underscore instead of the dash like // traditional LLVM-IR does, because the LLVM-IR-Dialect doesn't have a way // of forming names with a dash instead of underscore in its auto-generated @@ -61,7 +63,15 @@ def CIR_Dialect : Dialect { // of a [a-zA-Z0-9_] character regex(numbers only if not first), so there is // no way to get an underscore into this, even with escaping. static llvm::StringRef getModularFormatAttrName() { return "modular_format"; } + // NoBuiltins means "don't put builtins into my body", whereas "nobuiltin" + // means "I'm not a builtin, so don't replace me". This is a subtle + // difference, but one that reflects Classic Codegen. static llvm::StringRef getNoBuiltinsAttrName() { return "nobuiltins"; } + static llvm::StringRef getNoBuiltinAttrName() { return "nobuiltin"; } + static llvm::StringRef getTrapFuncNameAttrName() { return "trap_func_name"; } + static llvm::StringRef getZeroCallUsedRegsAttrName() { return "zero_call_used_regs"; } + static llvm::StringRef getSaveRegParamsAttrName() { return "save_reg_params"; } + static llvm::StringRef getDefaultFuncAttrsAttrName() { return "default_func_attrs"; } void registerAttributes(); void registerTypes(); diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index abc4dd9b3c160..2f52e5442ab67 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -145,6 +145,169 @@ static void addNoBuiltinAttributes(mlir::MLIRContext &ctx, mlir::ArrayAttr::get(&ctx, nbFuncs.getArrayRef())); } +/// Add denormal-fp-math and denormal-fp-math-f32 as appropriate for the +/// requested denormal behavior, accounting for the overriding behavior of the +/// -f32 case. +static void addDenormalModeAttrs(llvm::DenormalMode fpDenormalMode, + llvm::DenormalMode fp32DenormalMode, + mlir::NamedAttrList &attrs) { + // TODO(cir): Classic-codegen sets the denormal modes here. There are two + // values, both with a string, but it seems that perhaps we could combine + // these into a single attribute? It seems a little silly to have two so + // similar named attributes that do the same thing. +} + +/// Add default attributes to a function, which have merge semantics under +/// -mlink-builtin-bitcode and should not simply overwrite any existing +/// attributes in the linked library. +static void +addMergeableDefaultFunctionAttributes(const CodeGenOptions &CodeGenOpts, + mlir::NamedAttrList &attrs) { + addDenormalModeAttrs(CodeGenOpts.FPDenormalMode, CodeGenOpts.FP32DenormalMode, + attrs); +} + +llvm::StringLiteral +getZeroCallUsedRegsKindStr(llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind k) { + switch (k) { + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip: + llvm_unreachable("No string value, shouldn't be able to get here"); + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedGPRArg: + return "used-gpr-arg"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedGPR: + return "used-gpr"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::UsedArg: + return "used-arg"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Used: + return "used"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllGPRArg: + return "all-gpr-arg"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllGPR: + return "all-gpr"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::AllArg: + return "all-arg"; + case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::All: + return "all"; + } + + llvm_unreachable("Unknown kind?"); +} + +/// Add default attributes to a function, which have merge semantics under +/// -mlink-builtin-bitcode and should not simply overwrite any existing +/// attributes in the linked library. +static void addTrivialDefaultFunctionAttributes( + mlir::MLIRContext *mlirCtx, StringRef name, bool hasOptNoneAttr, + const CodeGenOptions &codeGenOpts, const LangOptions &langOpts, + bool attrOnCallSite, mlir::NamedAttrList &attrs) { + // TODO(cir): Handle optimize attribute flag here. + // OptimizeNoneAttr takes precedence over -Os or -Oz. No warning needed. + if (!hasOptNoneAttr) { + if (codeGenOpts.OptimizeSize) + attrs.set(cir::CIRDialect::getOptimizeForSizeAttrName(), + mlir::UnitAttr::get(mlirCtx)); + if (codeGenOpts.OptimizeSize == 2) + attrs.set(cir::CIRDialect::getMinSizeAttrName(), + mlir::UnitAttr::get(mlirCtx)); + } + + // TODO(cir): Classic codegen adds 'DisableRedZone', 'indirect-tls-seg-refs' + // and 'NoImplicitFloat' here. + + if (attrOnCallSite) { + // Add the 'nobuiltin' tag, which is different from 'no-builtins'. + if (!codeGenOpts.SimplifyLibCalls || langOpts.isNoBuiltinFunc(name)) + attrs.set(cir::CIRDialect::getNoBuiltinAttrName(), + mlir::UnitAttr::get(mlirCtx)); + + if (!codeGenOpts.TrapFuncName.empty()) + attrs.set(cir::CIRDialect::getTrapFuncNameAttrName(), + mlir::StringAttr::get(mlirCtx, codeGenOpts.TrapFuncName)); + } else { + // TODO(cir): Set frame pointer attribute here. + // TODO(cir): a number of other attribute 1-offs based on codegen/lang opts + // should be done here: less-recise-fpmad null-pointer-is-valid + // no-trapping-math + // various inf/nan/nsz/etc work here. + // + // TODO(cir): set stack-protector buffer size attribute (sorted oddly in + // classic compiler inside of the above region, but should be done on its + // own). + // TODO(cir): other attributes here: + // reciprocal estimates, prefer-vector-width, stackrealign, backchain, + // split-stack, speculative-load-hardening. + + if (codeGenOpts.getZeroCallUsedRegs() == + llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip) + attrs.erase(cir::CIRDialect::getZeroCallUsedRegsAttrName()); + else + attrs.set(cir::CIRDialect::getZeroCallUsedRegsAttrName(), + mlir::StringAttr::get(mlirCtx, + getZeroCallUsedRegsKindStr( + codeGenOpts.getZeroCallUsedRegs()))); + } + + if (langOpts.assumeFunctionsAreConvergent()) { + // Conservatively, mark all functions and calls in CUDA and OpenCL as + // convergent (meaning, they may call an intrinsically convergent op, such + // as __syncthreads() / barrier(), and so can't have certain optimizations + // applied around them). LLVM will remove this attribute where it safely + // can. + attrs.set(cir::CIRDialect::getConvergentAttrName(), + mlir::UnitAttr::get(mlirCtx)); + } + + // TODO(cir): Classic codegen adds 'nounwind' here in a bunch of offload + // targets. + + if (codeGenOpts.SaveRegParams && !attrOnCallSite) + attrs.set(cir::CIRDialect::getSaveRegParamsAttrName(), + mlir::UnitAttr::get(mlirCtx)); + + // These come in the form of an optional equality sign, so make sure we pass + // these on correctly. These will eventually just be passed through to + // LLVM-IR, but we want to put them all in 1 array to simplify the + // LLVM-MLIR dialect. + SmallVector<mlir::NamedAttribute> defaultFuncAttrs; + llvm::transform( + codeGenOpts.DefaultFunctionAttrs, std::back_inserter(defaultFuncAttrs), + [mlirCtx](llvm::StringRef arg) { + auto [var, value] = arg.split('='); + auto valueAttr = + value.empty() + ? cast<mlir::Attribute>(mlir::UnitAttr::get(mlirCtx)) + : cast<mlir::Attribute>(mlir::StringAttr::get(mlirCtx, value)); + return mlir::NamedAttribute(var, valueAttr); + }); + + if (!defaultFuncAttrs.empty()) + attrs.set(cir::CIRDialect::getDefaultFuncAttrsAttrName(), + mlir::DictionaryAttr::get(mlirCtx, defaultFuncAttrs)); + + // TODO(cir): Do branch protection attributes here. +} + +/// This function matches the behavior of 'getDefaultFunctionAttributes' from +/// classic codegen, despite the similarity of its name to +/// 'addDefaultFunctionDefinitionAttributes', which is a caller of this +/// function. +void CIRGenModule::addDefaultFunctionAttributes(StringRef name, + bool hasOptNoneAttr, + bool attrOnCallSite, + mlir::NamedAttrList &attrs) { + + addTrivialDefaultFunctionAttributes(&getMLIRContext(), name, hasOptNoneAttr, + codeGenOpts, langOpts, attrOnCallSite, + attrs); + + if (!attrOnCallSite) { + // TODO(cir): Classic codegen adds pointer-auth attributes here, by calling + // into TargetCodeGenInfo. At the moment, we've not looked into this as it + // is somewhat less used. + addMergeableDefaultFunctionAttributes(codeGenOpts, attrs); + } +} + /// Construct the CIR attribute list of a function or call. void CIRGenModule::constructAttributeList(llvm::StringRef name, const CIRGenFunctionInfo &info, @@ -244,9 +407,6 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name, // TODO(cir): Implement 'BPFFastCall' attribute here. This requires C, and // the BPF target. - // TODO(cir): Detecting 'OptimizeNone' is done here in classic codegen, when - // we figure out when to do that, we should do it here. - if (auto *allocSizeAttr = targetDecl->getAttr<AllocSizeAttr>()) { unsigned size = allocSizeAttr->getElemSizeParam().getLLVMIndex(); @@ -283,11 +443,44 @@ void CIRGenModule::constructAttributeList(llvm::StringRef name, addNoBuiltinAttributes(getMLIRContext(), attrs, getLangOpts(), nba); - // TODO(cir): We should set default function attrs here. + bool hasOptNoneAttr = targetDecl && targetDecl->hasAttr<OptimizeNoneAttr>(); + addDefaultFunctionAttributes(name, hasOptNoneAttr, attrOnCallSite, attrs); + if (targetDecl) { + // TODO(cir): There is another region of `if (targetDecl)` that handles + // removing some attributes that are necessary modifications of the + // default-function attrs. Including: + // NoSpeculativeLoadHardening + // SpeculativeLoadHardening + // NoSplitStack + // Non-lazy-bind + // 'sample-profile-suffix-elision-policy'. + + if (targetDecl->hasAttr<ZeroCallUsedRegsAttr>()) { + // A function "__attribute__((...))" overrides the command-line flag. + auto kind = + targetDecl->getAttr<ZeroCallUsedRegsAttr>()->getZeroCallUsedRegs(); + attrs.set( + cir::CIRDialect::getZeroCallUsedRegsAttrName(), + mlir::StringAttr::get( + &getMLIRContext(), + ZeroCallUsedRegsAttr::ConvertZeroCallUsedRegsKindToStr(kind))); + } + + if (targetDecl->hasAttr<NoConvergentAttr>()) + attrs.erase(cir::CIRDialect::getConvergentAttrName()); + } + + // TODO(cir): A bunch of non-call-site function IR attributes from + // declaration-specific information, including tail calls, + // cmse_nonsecure_entry, additional/automatic 'returns-twice' functions, + // CPU-features/overrides, and hotpatch support. + + // TODO(cir): Add loader-replaceable attribute here. + + // TODO(cir): Ret attrs. + // + // TODO(cir): Arg attrs. - // TODO(cir): There is another region of `if (targetDecl)` that handles - // removing some attributes that are necessary modifications of the - // default-function attrs. We should do that here. assert(!cir::MissingFeatures::opCallAttrs()); } diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.h b/clang/lib/CIR/CodeGen/CIRGenModule.h index 88b66129a8348..4444092b58466 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.h +++ b/clang/lib/CIR/CodeGen/CIRGenModule.h @@ -283,6 +283,12 @@ class CIRGenModule : public CIRGenTypeCache { cir::CallingConv &callingConv, cir::SideEffect &sideEffect, bool attrOnCallSite, bool isThunk); + /// Helper function for constructAttributeList/others. Builds a set of + /// function attributes to add to a function based on language opts, codegen + /// opts, and some small properties. + void addDefaultFunctionAttributes(StringRef name, bool hasOptNoneAttr, + bool attrOnCallSite, + mlir::NamedAttrList &attrs); /// Will return a global variable of the given type. If a variable with a /// different type already exists then a new variable with the right type diff --git a/clang/test/CIR/CodeGen/default-func-attrs-cmd-line.cpp b/clang/test/CIR/CodeGen/default-func-attrs-cmd-line.cpp new file mode 100644 index 0000000000000..df1e9fa7d9b18 --- /dev/null +++ b/clang/test/CIR/CodeGen/default-func-attrs-cmd-line.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -default-function-attr "key-2=1" -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -default-function-attr "key-2=1" -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -default-function-attr "key=value" -default-function-attr "just_key" -default-function-attr "key-2=1" -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +extern "C" { +// CIR: cir.func{{.*}}@func() attributes { +// CIR-SAME: default_func_attrs = {just_key, key = "value", "key-2" = "1"} +// LLVM: define{{.*}}@func() #[[FUNC_ATTRS:.*]] { +void func() {} + +void caller() { + func(); + // CIR: cir.call @func() + // CIR-SAME: default_func_attrs = {just_key, key = "value", "key-2" = "1"} + // LLVM: call void{{.*}}@func() #[[FUNC_CALL_ATTRS:.*]] +} +} + +// LLVM: attributes #[[FUNC_ATTRS]] = +// LLVM-SAME: "just_key" +// LLVM-SAME: "key"="value" +// LLVM-SAME: "key-2"="1" +// LLVM: attributes #[[FUNC_CALL_ATTRS]] = +// LLVM-SAME: "just_key" +// LLVM-SAME: "key"="value" +// LLVM-SAME: "key-2"="1" diff --git a/clang/test/CIR/CodeGen/no-builtin-attr-automatic.cpp b/clang/test/CIR/CodeGen/no-builtin-attr-automatic.cpp new file mode 100644 index 0000000000000..7cdda57b515cf --- /dev/null +++ b/clang/test/CIR/CodeGen/no-builtin-attr-automatic.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-STD +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-STD +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-STD +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -fno-builtin -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefixes=CIR,CIR-NB +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -fno-builtin -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-NB +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fno-builtin-memset -fno-builtin -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefixes=LLVM,LLVM-NB + +extern "C" { +__attribute__((hot)) +__attribute__((no_builtin)) +void no_builtin() {} +// CIR: cir.func{{.*}}@no_builtin() +// CIR-SAME: nobuiltins = [] +// LLVM: define{{.*}}@no_builtin() #[[NO_BUILTIN_ATTRS:.*]] { + +__attribute__((cold)) +__attribute__((no_builtin("memcpy"))) +void no_memcpy() {} +// CIR: cir.func{{.*}}@no_memcpy() +// CIR-STD-SAME: nobuiltins = ["memset", "memcpy"] +// CIR-NB-SAME: nobuiltins = [] +// LLVM: define{{.*}}@no_memcpy() #[[NO_MEMCPY_ATTRS:.*]] { + +__attribute__((noduplicate)) +void memset() {} +// CIR: cir.func{{.*}}@memset() +// CIR-STD-SAME: nobuiltins = ["memset"] +// CIR-NB-SAME: nobuiltins = [] +// LLVM: define{{.*}}@memset() #[[MEMSET_ATTRS:.*]] { + +void caller() { + no_builtin(); + // CIR: cir.call @no_builtin() + // CIR-NB-SAME: nobuiltin + // CIR-SAME: nobuiltins = [] + // LLVM: call void @no_builtin() #[[NO_BUILTIN_CALL_ATTRS:.*]] + no_memcpy(); + // CIR: cir.call @no_memcpy() + // CIR-STD-SAME: nobuiltins = ["memset", "memcpy"] + // CIR-NB-SAME: nobuiltin + // CIR-NB-SAME: nobuiltins = [] + // LLVM: call void @no_memcpy() #[[NO_MEMCPY_CALL_ATTRS:.*]] + memset(); + // CIR: cir.call @memset() + // CIR-STD-SAME: nobuiltins = ["memset"] + // CIR-NB-SAME: nobuiltin + // CIR-NB-SAME: nobuiltins = [] + // LLVM: call void @memset() #[[MEMSET_CALL_ATTRS:.*]] +} +} + +// LLVM: attributes #[[NO_BUILTIN_ATTRS]] +// LLVM-SAME: no-builtins +// LLVM: attributes #[[NO_MEMCPY_ATTRS]] +// LLVM-STD-SAME: no-builtin-memcpy +// LLVM-STD-SAME: no-builtin-memset +// LLVM-NB-SAME: no-builtins +// LLVM: attributes #[[MEMSET_ATTRS]] +// LLVM-STD-SAME: no-builtin-memset +// LLVM-NB-SAME: no-builtins +// LLVM: attributes #[[NO_BUILTIN_CALL_ATTRS]] +// LLVM-NB-SAME: nobuiltin +// LLVM-SAME: no-builtins +// LLVM: attributes #[[NO_MEMCPY_CALL_ATTRS]] +// LLVM-STD-SAME: no-builtin-memcpy +// LLVM-STD-SAME: no-builtin-memset +// LLVM-NB-SAME: nobuiltin +// LLVM-NB-SAME: no-builtins +// LLVM: attributes #[[MEMSET_CALL_ATTRS]] +// LLVM-STD-SAME: no-builtin-memset +// LLVM-NB-SAME: nobuiltin +// LLVM-NB-SAME: no-builtins diff --git a/clang/test/CIR/CodeGen/offload-convergent-attr.cu b/clang/test/CIR/CodeGen/offload-convergent-attr.cu new file mode 100644 index 0000000000000..1112ca3614326 --- /dev/null +++ b/clang/test/CIR/CodeGen/offload-convergent-attr.cu @@ -0,0 +1,45 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcuda-is-device -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcuda-is-device -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fcuda-is-device -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +extern "C" { +__attribute__((device)) +void normal() {} +// CIR: cir.func{{.*}}@normal() +// CIR-SAME: convergent +// LLVM: define {{.*}}@normal(){{.*}} #[[NORMAL_ATTR:.*]] { + +__attribute__((hot)) +__attribute__((device)) +__attribute__((noconvergent)) +void no_conv() {} +// CIR: cir.func{{.*}}@no_conv() +// CIR-NOT: convergent +// LLVM: define {{.*}}@no_conv(){{.*}} #[[NO_CONV_ATTR:.*]] { + +// CIR: cir.func{{.*}}@caller +__attribute__((device)) +void caller() { + normal(); + // CIR: cir.call{{.*}}@normal() + // CIR-SAME: convergent + // LLVM: call void{{.*}}@normal() #[[NORMAL_CALL_ATTR:.*]] + no_conv(); + // CIR: cir.call{{.*}}@no_conv() + // CIR-NOT: convergent + // CIR: cir.return + // LLVM: call void{{.*}}@no_conv() #[[NO_CONV_CALL_ATTR:.*]] +} +} + +// LLVM: attributes #[[NORMAL_ATTR]] +// LLVM-SAME: convergent +// LLVM: attributes #[[NO_CONV_ATTR]] +// LLVM-NOT: convergent +// LLVM: attributes #[[NORMAL_CALL_ATTR]] +// LLVM-SAME: convergent +// LLVM: attributes #[[NO_CONV_CALL_ATTR]] +// LLVM-NOT: convergent diff --git a/clang/test/CIR/CodeGen/optsize-func-attr.cpp b/clang/test/CIR/CodeGen/optsize-func-attr.cpp new file mode 100644 index 0000000000000..28441b8558584 --- /dev/null +++ b/clang/test/CIR/CodeGen/optsize-func-attr.cpp @@ -0,0 +1,74 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Os -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Os -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,BOTH +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Os -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG,BOTH +// +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Oz -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIROZ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Oz -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,BOTH,BOTHOZ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -disable-llvm-passes -Oz -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG,OGCGOZ,BOTH,BOTHOZ + +extern "C" { + __attribute__((hot)) + void normal(){} + // CIR: cir.func{{.*}}@normal() + // CIROZ-SAME: minsize + // CIR-SAME: optsize + // BOTH: define{{.*}}@normal(){{.*}} #[[NORMAL_ATTR:.*]] { + + __attribute__((cold)) + __attribute__((optnone)) + void optnone(){} + // CIR: cir.func{{.*}}@optnone() + // CIR-NOT: optsize + // CIR-NOT: minsize + // BOTH: define{{.*}}@optnone(){{.*}} #[[OPTNONE_ATTR:.*]] { + + // CIR: cir.func{{.*}}@caller() + void caller() { + normal(); + // CIR: cir.call{{.*}}@normal() + // CIROZ-SAME: minsize + // CIR-SAME: optsize + // LLVM: call void @normal() #[[NORMAL_ATTR]] + // OGCG: call void @normal() #[[NORMAL_CALL_ATTR:.*]] + optnone(); + // CIR: cir.call{{.*}}@optnone() + // CIR-NOT: optsize + // CIR-NOT: minsize + // LLVM: call void @optnone() #[[OPTNONE_ATTR]] + // OGCG: call void @optnone() #[[OPTNONE_CALL_ATTR:.*]] + + // CIR: cir.return + } +} + +// BOTH: attributes #[[NORMAL_ATTR]] +// BOTHOZ-SAME: minsize +// BOTH-SAME: optsize +// +// BOTH: attributes #[[OPTNONE_ATTR]] +// BOTH-NOT: optsize +// BOTH-NOT: minsize +// +// attributes for caller, to block the 'NOT'. +// BOTH: attributes +// +// CIR doesn't have sufficiently different 'attributes' implemented for the +// caller and the callee to be different when doing -O settings (as 'optnone' +// is the only difference). So the below call attributes are only necessary +// for classic codegen. +// OGCG: attributes #[[NORMAL_CALL_ATTR]] +// OGCGOZ-SAME: minsize +// OGCG-SAME: optsize +// +// OGCG: attributes #[[OPTNONE_CALL_ATTR]] +// OGCG-NOT: optsize +// OGCG-NOT: minsize +// +// to block the 'NOT'. +// BOTH: llvm.module.flags diff --git a/clang/test/CIR/CodeGen/save-reg-params-func-attr.cpp b/clang/test/CIR/CodeGen/save-reg-params-func-attr.cpp new file mode 100644 index 0000000000000..61bf1bdf31287 --- /dev/null +++ b/clang/test/CIR/CodeGen/save-reg-params-func-attr.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -msave-reg-params -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -msave-reg-params -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -msave-reg-params -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +extern "C" { + + __attribute__((hot)) + void func(){} + // CIR: cir.func{{.*}}@func() + // CIR-SAME: save_reg_params + // LLVM: define{{.*}}@func() #[[FUNC_ATTRS:.*]] { + + void caller() { + func(); + // CIR: cir.call{{.*}}@func() + // CIR-NOT: save_reg_params + // CIR: cir.return + // LLVM: call void{{.*}}@func() #[[CALL_ATTRS:.*]] + + } +} + +// LLVM: attributes #[[FUNC_ATTRS]] +// LLVM-SAME: "save-reg-params" +// LLVM: attributes #[[CALL_ATTRS]] +// LLVM-NOT: "save-reg-params" diff --git a/clang/test/CIR/CodeGen/trap-func-name-attr.cpp b/clang/test/CIR/CodeGen/trap-func-name-attr.cpp new file mode 100644 index 0000000000000..38afc6b3b11d4 --- /dev/null +++ b/clang/test/CIR/CodeGen/trap-func-name-attr.cpp @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -ftrap-function=trap_func -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -ftrap-function=trap_func -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -ftrap-function=trap_func -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM + +extern "C" { + void normal() {} + // CIR: cir.func{{.*}}@normal() + // CIR-NOT: trap_func_name + // LLVM: define{{.*}}@normal() #[[FUNC_ATTR:.*]] { + void trap_func(){} + // CIR: cir.func{{.*}}@trap_func() + // CIR-NOT: trap_func_name + // LLVM: define{{.*}}@trap_func() #[[FUNC_ATTR]] { + + void caller() { + normal(); + // CIR: cir.call{{.*}}normal() + // CIR-SAME: trap_func_name = "trap_func" + // LLVM: call void{{.*}} @normal() #[[CALL_ATTR:.*]] + trap_func(); + // CIR: cir.call{{.*}}trap_func() + // CIR-SAME: trap_func_name = "trap_func" + // LLVM: call void{{.*}} @trap_func() #[[CALL_ATTR]] + } +} + +// LLVM: attributes #[[FUNC_ATTR]] +// LLVM-NOT: trap-func-name +// LLVM: attributes #[[CALL_ATTR]] +// LLVM-SAME: "trap-func-name"="trap_func" diff --git a/clang/test/CIR/CodeGen/zero-call-used-regs-func-attr.cpp b/clang/test/CIR/CodeGen/zero-call-used-regs-func-attr.cpp new file mode 100644 index 0000000000000..b5953fd63d581 --- /dev/null +++ b/clang/test/CIR/CodeGen/zero-call-used-regs-func-attr.cpp @@ -0,0 +1,102 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIR_NONE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_NONE +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_NONE + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=skip -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIR_SKIP +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=skip -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_SKIP +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=skip -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_SKIP + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=all-gpr -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR,CIR_ALLGPR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=all-gpr -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_ALLGPR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fzero-call-used-regs=all-gpr -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s -check-prefix=LLVM,LLVM_ALLGPR + +extern "C" { + __attribute__((hot)) + void normal(){} + // CIR: cir.func{{.*}}@normal() + // CIR_NONE-NOT: zero-call-used-regs + // CIR_SKIP-NOT: zero-call-used-regs + // CIR_ALLGPR-SAME: zero_call_used_regs = "all-gpr" + // LLVM: define{{.*}}@normal() #[[NORM_ATTR:.*]] { + + __attribute__((cold)) + __attribute__((zero_call_used_regs("skip"))) + void skip() { } + // CIR: cir.func{{.*}}@skip() + // CIR-SAME: zero_call_used_regs = "skip" + // LLVM: define{{.*}}@skip() #[[SKIP_ATTR:.*]] { + + __attribute__((zero_call_used_regs("all"))) + void all() { } + // CIR: cir.func{{.*}}@all() + // CIR-SAME: zero_call_used_regs = "all" + // LLVM: define{{.*}}@all() #[[ALL_ATTR:.*]] { + + __attribute__((zero_call_used_regs("used"))) + void used() { } + // CIR: cir.func{{.*}}@used() + // CIR-SAME: zero_call_used_regs = "used" + // LLVM: define{{.*}}@used() #[[USED_ATTR:.*]] { + + __attribute__((zero_call_used_regs("used-gpr-arg"))) + void used_gpr_arg() { } + // CIR: cir.func{{.*}}@used_gpr_arg() + // CIR-SAME: zero_call_used_regs = "used-gpr-arg" + // LLVM: define{{.*}}@used_gpr_arg() #[[USED_GPR_ATTR:.*]] { + + void caller() { + normal(); + // CIR: cir.call{{.*}}@normal() + // CIR-NOT: zero-call-used-regs + // LLVM: call void{{.*}}@normal() #[[NORM_CALL_ATTR:.*]] + skip(); + // CIR: cir.call{{.*}}@skip() + // CIR-SAME: zero_call_used_regs = "skip" + // LLVM: call void{{.*}}@skip() #[[SKIP_CALL_ATTR:.*]] + all(); + // CIR: cir.call{{.*}}@all() + // CIR-SAME: zero_call_used_regs = "all" + // LLVM: call void{{.*}}@all() #[[ALL_CALL_ATTR:.*]] + used(); + // CIR: cir.call{{.*}}@used() + // CIR-SAME: zero_call_used_regs = "used" + // LLVM: call void{{.*}}@used() #[[USED_CALL_ATTR:.*]] + used_gpr_arg(); + // CIR: cir.call{{.*}}@used_gpr_arg() + // CIR-SAME: zero_call_used_regs = "used-gpr-arg" + // LLVM: call void{{.*}}@used_gpr_arg() #[[USED_GPR_CALL_ATTR:.*]] + } +} + +// LLVM: attributes #[[NORM_ATTR]] +// LLVM_NONE-NOT: zero-call-used-regs +// LLVM_SKIP-NOT: zero-call-used-regs +// LLVM_ALLGPR-SAME: "zero-call-used-regs"="all-gpr" +// LLVM: attributes #[[SKIP_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="skip" +// LLVM: attributes #[[ALL_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="all" +// LLVM: attributes #[[USED_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="used" +// LLVM: attributes #[[USED_GPR_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="used-gpr-arg" +// +// LLVM: attributes #[[NORM_CALL_ATTR]] +// LLVM-NOT: zero-call-used-regs +// LLVM: attributes #[[SKIP_CALL_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="skip" +// LLVM: attributes #[[ALL_CALL_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="all" +// LLVM: attributes #[[USED_CALL_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="used" +// LLVM: attributes #[[USED_GPR_CALL_ATTR]] +// LLVM-SAME: "zero-call-used-regs"="used-gpr-arg" diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c index d2e15e3889a2d..c720dc031c3d1 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceIntrin.c @@ -10,7 +10,7 @@ double test_mm512_reduce_add_pd(__m512d __W, double ExtraAddOp){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : (!cir.double, !cir.vector<8 x !cir.double>) -> !cir.double // CIR-LABEL: test_mm512_reduce_add_pd - // CIR: cir.call @_mm512_reduce_add_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double + // CIR: cir.call @_mm512_reduce_add_pd(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double // LLVM-LABEL: test_mm512_reduce_add_pd // LLVM: call double @llvm.vector.reduce.fadd.v8f64(double -0.000000e+00, <8 x double> %{{.*}}) @@ -27,7 +27,7 @@ double test_mm512_reduce_mul_pd(__m512d __W, double ExtraMulOp){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : (!cir.double, !cir.vector<8 x !cir.double>) -> !cir.double // CIR-LABEL: test_mm512_reduce_mul_pd - // CIR: cir.call @_mm512_reduce_mul_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double + // CIR: cir.call @_mm512_reduce_mul_pd(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double // LLVM-LABEL: test_mm512_reduce_mul_pd // LLVM: call double @llvm.vector.reduce.fmul.v8f64(double 1.000000e+00, <8 x double> %{{.*}}) @@ -45,7 +45,7 @@ float test_mm512_reduce_add_ps(__m512 __W){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : (!cir.float, !cir.vector<16 x !cir.float>) -> !cir.float // CIR-LABEL: test_mm512_reduce_add_ps - // CIR: cir.call @_mm512_reduce_add_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float + // CIR: cir.call @_mm512_reduce_add_ps(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float // LLVM-LABEL: test_mm512_reduce_add_ps // LLVM: call float @llvm.vector.reduce.fadd.v16f32(float -0.000000e+00, <16 x float> %{{.*}}) @@ -60,7 +60,7 @@ float test_mm512_reduce_mul_ps(__m512 __W){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : (!cir.float, !cir.vector<16 x !cir.float>) -> !cir.float // CIR-LABEL: test_mm512_reduce_mul_ps - // CIR: cir.call @_mm512_reduce_mul_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float + // CIR: cir.call @_mm512_reduce_mul_ps(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float // LLVM-LABEL: test_mm512_reduce_mul_ps // LLVM: call float @llvm.vector.reduce.fmul.v16f32(float 1.000000e+00, <16 x float> %{{.*}}) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c index c724942a7a7f2..f61b55b6b27f8 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512-reduceMinMaxIntrin.c @@ -9,7 +9,7 @@ double test_mm512_reduce_max_pd(__m512d __W, double ExtraAddOp){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] : (!cir.vector<8 x !cir.double>) -> !cir.double // CIR-LABEL: test_mm512_reduce_max_pd - // CIR: cir.call @_mm512_reduce_max_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double + // CIR: cir.call @_mm512_reduce_max_pd(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double // LLVM-LABEL: test_mm512_reduce_max_pd // LLVM: call double @llvm.vector.reduce.fmax.v8f64(<8 x double> %{{.*}}) @@ -26,7 +26,7 @@ double test_mm512_reduce_min_pd(__m512d __W, double ExtraMulOp){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : (!cir.vector<8 x !cir.double>) -> !cir.double // CIR-LABEL: test_mm512_reduce_min_pd - // CIR: cir.call @_mm512_reduce_min_pd(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double + // CIR: cir.call @_mm512_reduce_min_pd(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.double>) -> !cir.double // LLVM-LABEL: test_mm512_reduce_min_pd // LLVM: call double @llvm.vector.reduce.fmin.v8f64(<8 x double> %{{.*}}) @@ -43,7 +43,7 @@ float test_mm512_reduce_max_ps(__m512 __W){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] : (!cir.vector<16 x !cir.float>) -> !cir.float // CIR-LABEL: test_mm512_reduce_max_ps - // CIR: cir.call @_mm512_reduce_max_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float + // CIR: cir.call @_mm512_reduce_max_ps(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float // LLVM-LABEL: test_mm512_reduce_max_ps // LLVM: call float @llvm.vector.reduce.fmax.v16f32(<16 x float> %{{.*}}) @@ -58,7 +58,7 @@ float test_mm512_reduce_min_ps(__m512 __W){ // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : (!cir.vector<16 x !cir.float>) -> !cir.float // CIR-LABEL: test_mm512_reduce_min_ps - // CIR: cir.call @_mm512_reduce_min_ps(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float + // CIR: cir.call @_mm512_reduce_min_ps(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.float>) -> !cir.float // LLVM-LABEL: test_mm512_reduce_min_ps // LLVM: call float @llvm.vector.reduce.fmin.v16f32(<16 x float> %{{.*}}) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c index 399dfee75d81c..cd6b87d65c90e 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512fp16-builtins.c @@ -70,7 +70,7 @@ _Float16 test_mm512_reduce_add_ph(__m512h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<32 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm512_reduce_add_ph - // CIR: cir.call @_mm512_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm512_reduce_add_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm512_reduce_add_ph // LLVM: call half @llvm.vector.reduce.fadd.v32f16(half 0xH8000, <32 x half> %{{.*}}) @@ -85,7 +85,7 @@ _Float16 test_mm512_reduce_mul_ph(__m512h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<32 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm512_reduce_mul_ph - // CIR: cir.call @_mm512_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm512_reduce_mul_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm512_reduce_mul_ph // LLVM: call half @llvm.vector.reduce.fmul.v32f16(half 0xH3C00, <32 x half> %{{.*}}) @@ -100,7 +100,7 @@ _Float16 test_mm512_reduce_max_ph(__m512h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] (!cir.vector<32 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm512_reduce_max_ph - // CIR: cir.call @_mm512_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm512_reduce_max_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm512_reduce_max_ph // LLVM: call half @llvm.vector.reduce.fmax.v32f16(<32 x half> %{{.*}}) @@ -115,7 +115,7 @@ _Float16 test_mm512_reduce_min_ph(__m512h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] (!cir.vector<32 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm512_reduce_min_ph - // CIR: cir.call @_mm512_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm512_reduce_min_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<32 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm512_reduce_min_ph // LLVM: call half @llvm.vector.reduce.fmin.v32f16(<32 x half> %{{.*}}) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c index 1c8d68c1ab69e..f85488aead8fb 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlbf16-builtins.c @@ -9,7 +9,7 @@ __m256bh test_mm512_mask_cvtneps_pbh(__m256bh src, __mmask16 k, __m512 a) { // CIR-LABEL: test_mm512_mask_cvtneps_pbh - // CIR: cir.call @_mm512_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.bf16>, !u16i, !cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16> + // CIR: cir.call @_mm512_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.bf16>, !u16i, !cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16> // LLVM-LABEL: @test_mm512_mask_cvtneps_pbh // LLVM: call <16 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.512 @@ -21,7 +21,7 @@ __m256bh test_mm512_mask_cvtneps_pbh(__m256bh src, __mmask16 k, __m512 a) { __m256bh test_mm512_maskz_cvtneps_pbh(__mmask16 k, __m512 a) { // CIR-LABEL: test_mm512_maskz_cvtneps_pbh - // CIR: cir.call @_mm512_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!u16i, !cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16> + // CIR: cir.call @_mm512_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!u16i, !cir.vector<16 x !cir.float>) -> !cir.vector<16 x !cir.bf16> // LLVM-LABEL: @test_mm512_maskz_cvtneps_pbh // LLVM: call <16 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.512(<16 x float> {{.+}}) @@ -34,7 +34,7 @@ __m256bh test_mm512_maskz_cvtneps_pbh(__mmask16 k, __m512 a) { __m128bh test_mm256_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m256 a) { // CIR-LABEL: test_mm256_mask_cvtneps_pbh - // CIR: cir.call @_mm256_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16> + // CIR: cir.call @_mm256_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16> // LLVM-LABEL: @test_mm256_mask_cvtneps_pbh // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.256(<8 x float> {{.+}}) @@ -46,7 +46,7 @@ __m128bh test_mm256_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m256 a) { __m128bh test_mm256_maskz_cvtneps_pbh(__mmask8 k, __m256 a) { // CIR-LABEL: test_mm256_maskz_cvtneps_pbh - // CIR: cir.call @_mm256_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!u8i, !cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16> + // CIR: cir.call @_mm256_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!u8i, !cir.vector<8 x !cir.float>) -> !cir.vector<8 x !cir.bf16> // LLVM-LABEL: @test_mm256_maskz_cvtneps_pbh // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.cvtneps2bf16.256(<8 x float> {{.+}}) @@ -58,7 +58,7 @@ __m128bh test_mm256_maskz_cvtneps_pbh(__mmask8 k, __m256 a) { __m128bh test_mm_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m128 a) { // CIR-LABEL: test_mm_mask_cvtneps_pbh - // CIR: cir.call @_mm_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16>{{.+}} + // CIR: cir.call @_mm_mask_cvtneps_pbh({{.+}}, {{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.bf16>, !u8i, !cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16>{{.+}} // LLVM-LABEL: @test_mm_mask_cvtneps_pbh // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.mask.cvtneps2bf16.128(<4 x float> {{.+}}, <8 x bfloat> {{.+}}, <4 x i1> {{.+}}) @@ -70,7 +70,7 @@ __m128bh test_mm_mask_cvtneps_pbh(__m128bh src, __mmask8 k, __m128 a) { __m128bh test_mm_maskz_cvtneps_pbh(__mmask8 k, __m128 a) { // CIR-LABEL: test_mm_maskz_cvtneps_pbh - // CIR: cir.call @_mm_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltins = [{{.*}}]} : (!u8i, !cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16> + // CIR: cir.call @_mm_maskz_cvtneps_pbh({{.+}}, {{.+}}) {nobuiltin, nobuiltins = [{{.*}}]} : (!u8i, !cir.vector<4 x !cir.float>) -> !cir.vector<8 x !cir.bf16> // LLVM-LABEL: @test_mm_maskz_cvtneps_pbh // LLVM: call <8 x bfloat> @llvm.x86.avx512bf16.mask.cvtneps2bf16.128(<4 x float> {{.+}}, <8 x bfloat> {{.+}}, <4 x i1> {{.+}}) diff --git a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c index d3eaa8c66d273..a9b5c74ba9afe 100644 --- a/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c +++ b/clang/test/CIR/CodeGenBuiltins/X86/avx512vlfp16-builtins.c @@ -12,7 +12,7 @@ _Float16 test_mm256_reduce_add_ph(__m256h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<16 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm256_reduce_add_ph - // CIR: cir.call @_mm256_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm256_reduce_add_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm256_reduce_add_ph // LLVM: call half @llvm.vector.reduce.fadd.v16f16(half 0xH8000, <16 x half> %{{.*}}) @@ -27,7 +27,7 @@ _Float16 test_mm256_reduce_mul_ph(__m256h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<16 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm256_reduce_mul_ph - // CIR: cir.call @_mm256_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm256_reduce_mul_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm256_reduce_mul_ph // LLVM: call half @llvm.vector.reduce.fmul.v16f16(half 0xH3C00, <16 x half> %{{.*}}) @@ -42,7 +42,7 @@ _Float16 test_mm256_reduce_max_ph(__m256h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] (!cir.vector<16 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm256_reduce_max_ph - // CIR: cir.call @_mm256_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm256_reduce_max_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm256_reduce_max_ph // LLVM: call half @llvm.vector.reduce.fmax.v16f16(<16 x half> %{{.*}}) @@ -57,7 +57,7 @@ _Float16 test_mm256_reduce_min_ph(__m256h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : (!cir.vector<16 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm256_reduce_min_ph - // CIR: cir.call @_mm256_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm256_reduce_min_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<16 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm256_reduce_min_ph // LLVM: call half @llvm.vector.reduce.fmin.v16f16(<16 x half> %{{.*}}) @@ -72,7 +72,7 @@ _Float16 test_mm_reduce_add_ph(__m128h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fadd" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<8 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm_reduce_add_ph - // CIR: cir.call @_mm_reduce_add_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm_reduce_add_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm_reduce_add_ph // LLVM: call half @llvm.vector.reduce.fadd.v8f16(half 0xH8000, <8 x half> %{{.*}}) @@ -87,7 +87,7 @@ _Float16 test_mm_reduce_mul_ph(__m128h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmul" %[[R:.*]], %[[V:.*]] : (!cir.f16, !cir.vector<8 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm_reduce_mul_ph - // CIR: cir.call @_mm_reduce_mul_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm_reduce_mul_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm_reduce_mul_ph // LLVM: call half @llvm.vector.reduce.fmul.v8f16(half 0xH3C00, <8 x half> %{{.*}}) @@ -102,7 +102,7 @@ _Float16 test_mm_reduce_max_ph(__m128h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmax" %[[V:.*]] (!cir.vector<8 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm_reduce_max_ph - // CIR: cir.call @_mm_reduce_max_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm_reduce_max_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm_reduce_max_ph // LLVM: call half @llvm.vector.reduce.fmax.v8f16(<8 x half> %{{.*}}) @@ -117,7 +117,7 @@ _Float16 test_mm_reduce_min_ph(__m128h __W) { // CIR: cir.call_llvm_intrinsic "vector.reduce.fmin" %[[V:.*]] : (!cir.vector<8 x !cir.f16>) -> !cir.f16 // CIR-LABEL: test_mm_reduce_min_ph - // CIR: cir.call @_mm_reduce_min_ph(%[[VEC:.*]]) {nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 + // CIR: cir.call @_mm_reduce_min_ph(%[[VEC:.*]]) {nobuiltin, nobuiltins = [{{.*}}]} : (!cir.vector<8 x !cir.f16>) -> !cir.f16 // LLVM-LABEL: test_mm_reduce_min_ph // LLVM: call half @llvm.vector.reduce.fmin.v8f16(<8 x half> %{{.*}}) diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index a03a933eed370..75e0767c9d5a9 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -801,6 +801,11 @@ def LLVM_CallOp OptionalAttr<StrAttr>:$modular_format, OptionalAttr<ArrayAttr>:$nobuiltins, OptionalAttr<DenseI32ArrayAttr>:$allocsize, + UnitAttr:$optsize, UnitAttr:$minsize, + UnitAttr:$nobuiltin, UnitAttr:$save_reg_params, + OptionalAttr<StrAttr>:$zero_call_used_regs, + OptionalAttr<StrAttr>:$trap_func_name, + OptionalAttr<DictionaryAttr>:$default_func_attrs, VariadicOfVariadic<LLVM_Type, "op_bundle_sizes">:$op_bundle_operands, DenseI32ArrayAttr:$op_bundle_sizes, OptionalAttr<ArrayAttr>:$op_bundle_tags, @@ -2009,6 +2014,11 @@ def LLVM_LLVMFuncOp : LLVM_Op<"func", [ OptionalAttr<StrAttr>:$modular_format, OptionalAttr<ArrayAttr>:$nobuiltins, OptionalAttr<DenseI32ArrayAttr>:$allocsize, + OptionalAttr<UnitAttr>:$optsize, + OptionalAttr<UnitAttr>:$minsize, + OptionalAttr<UnitAttr>:$save_reg_params, + OptionalAttr<StrAttr>:$zero_call_used_regs, + OptionalAttr<DictionaryAttr>:$default_func_attrs, OptionalAttr<LLVM_VecTypeHintAttr>:$vec_type_hint, OptionalAttr<DenseI32ArrayAttr>:$work_group_size_hint, OptionalAttr<DenseI32ArrayAttr>:$reqd_work_group_size, diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 349c0f8810a47..a6278e3afcd94 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -351,22 +351,38 @@ class ModuleTranslation { // A helper callback that takes an attribute, and if it is a StringAttr, // properly converts it to the 'no-builtin-VALUE' form. - static std::optional<std::string> convertNoBuiltin(mlir::Attribute a) { + static std::optional<llvm::Attribute> convertNoBuiltin(llvm::LLVMContext &ctx, + mlir::Attribute a) { if (auto str = dyn_cast<StringAttr>(a)) - return ("no-builtin-" + str.getValue()).str(); + return llvm::Attribute::get(ctx, ("no-builtin-" + str.getValue()).str()); + return std::nullopt; + } + + static std::optional<llvm::Attribute> + convertDefaultFuncAttr(llvm::LLVMContext &ctx, + mlir::NamedAttribute namedAttr) { + StringAttr name = namedAttr.getName(); + Attribute value = namedAttr.getValue(); + + if (auto strVal = dyn_cast<StringAttr>(value)) + return llvm::Attribute::get(ctx, name.getValue(), strVal.getValue()); + if (mlir::isa<UnitAttr>(value)) + return llvm::Attribute::get(ctx, name.getValue()); return std::nullopt; } /// A template that takes an ArrayAttr, converts it via a user provided /// callback, then adds each element to as function attributes to the provided /// operation. - template <typename Operation, typename Converter> - void convertFunctionArrayAttr(ArrayAttr array, Operation *op, + template <typename ArrayTy, typename Operation, typename Converter> + void convertFunctionArrayAttr(ArrayTy arrayAttr, Operation *op, const Converter &conv) { - for (Attribute a : array) { - auto result = conv(a); + if (!arrayAttr) + return; + for (auto elt : arrayAttr) { + auto result = conv(getLLVMContext(), elt); if (result) - op->addFnAttr(llvm::Attribute::get(getLLVMContext(), *result)); + op->addFnAttr(*result); } } diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index d4573060eca25..4c67720654f83 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -999,7 +999,10 @@ void CallOp::build(OpBuilder &builder, OperationState &state, TypeRange results, /*cold=*/nullptr, /*noduplicate=*/nullptr, /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr, /*nobuiltins=*/nullptr, - /*alloc_size=*/nullptr, + /*allocsize=*/nullptr, /*optsize=*/nullptr, /*minsize=*/nullptr, + /*nobuiltin=*/nullptr, /*save_reg_params=*/nullptr, + /*zero_call_used_regs=*/nullptr, /*trap_func_name=*/nullptr, + /*default_func_attrs=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, @@ -1035,7 +1038,10 @@ void CallOp::build(OpBuilder &builder, OperationState &state, /*cold=*/nullptr, /*noduplicate=*/nullptr, /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr, /*nobuiltins=*/nullptr, - /*alloc_size=*/nullptr, + /*allocsize=*/nullptr, /*optsize=*/nullptr, /*minsize=*/nullptr, + /*nobuiltin=*/nullptr, /*save_reg_params=*/nullptr, + /*zero_call_used_regs=*/nullptr, /*trap_func_name=*/nullptr, + /*default_func_attrs=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, @@ -1057,7 +1063,10 @@ void CallOp::build(OpBuilder &builder, OperationState &state, /*cold=*/nullptr, /*noduplicate=*/nullptr, /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr, /*nobuiltins=*/nullptr, - /*alloc_size=*/nullptr, + /*allocsize=*/nullptr, /*optsize=*/nullptr, /*minsize=*/nullptr, + /*nobuiltin=*/nullptr, /*save_reg_params=*/nullptr, + /*zero_call_used_regs=*/nullptr, /*trap_func_name=*/nullptr, + /*default_func_attrs=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, @@ -1079,7 +1088,10 @@ void CallOp::build(OpBuilder &builder, OperationState &state, LLVMFuncOp func, /*cold=*/nullptr, /*noduplicate=*/nullptr, /*no_caller_saved_registers=*/nullptr, /*nocallback=*/nullptr, /*modular_format=*/nullptr, /*nobuiltins=*/nullptr, - /*alloc_size=*/nullptr, + /*allocsize=*/nullptr, /*optsize=*/nullptr, /*minsize=*/nullptr, + /*nobuiltin=*/nullptr, /*save_reg_params=*/nullptr, + /*zero_call_used_regs=*/nullptr, /*trap_func_name=*/nullptr, + /*default_func_attrs=*/nullptr, /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*access_groups=*/nullptr, /*alias_scopes=*/nullptr, /*arg_attrs=*/nullptr, /*res_attrs=*/nullptr, diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp index 93a8e00d40e35..401a939b52371 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -423,6 +423,15 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, call->addFnAttr(llvm::Attribute::WillReturn); if (callOp.getNoreturnAttr()) call->addFnAttr(llvm::Attribute::NoReturn); + if (callOp.getOptsizeAttr()) + call->addFnAttr(llvm::Attribute::OptimizeForSize); + if (callOp.getMinsizeAttr()) + call->addFnAttr(llvm::Attribute::MinSize); + if (callOp.getSaveRegParamsAttr()) + call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(), + "save-reg-params")); + if (callOp.getNobuiltinAttr()) + call->addFnAttr(llvm::Attribute::NoBuiltin); if (callOp.getReturnsTwiceAttr()) call->addFnAttr(llvm::Attribute::ReturnsTwice); if (callOp.getColdAttr()) @@ -446,6 +455,14 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(), "modular-format", modFormat.getValue())); + if (StringAttr zcsr = callOp.getZeroCallUsedRegsAttr()) + call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(), + "zero-call-used-regs", + zcsr.getValue())); + if (StringAttr trapFunc = callOp.getTrapFuncNameAttr()) + call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(), + "trap-func-name", + trapFunc.getValue())); if (ArrayAttr noBuiltins = callOp.getNobuiltinsAttr()) { if (noBuiltins.empty()) @@ -456,6 +473,10 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, noBuiltins, call, ModuleTranslation::convertNoBuiltin); } + moduleTranslation.convertFunctionArrayAttr( + callOp.getDefaultFuncAttrsAttr(), call, + ModuleTranslation::convertDefaultFuncAttr); + if (llvm::Attribute attr = moduleTranslation.convertAllocsizeAttr(callOp.getAllocsizeAttr()); attr.isValid()) diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 2c1613c890923..09b12942638d9 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -2673,23 +2673,29 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{ StringLiteral("instrument-function-exit"), StringLiteral("modular-format"), StringLiteral("memory"), + StringLiteral("minsize"), StringLiteral("no_caller_saved_registers"), StringLiteral("no-infs-fp-math"), StringLiteral("no-nans-fp-math"), StringLiteral("no-signed-zeros-fp-math"), StringLiteral("no-builtins"), + StringLiteral("nobuiltin"), StringLiteral("nocallback"), StringLiteral("noduplicate"), StringLiteral("noinline"), StringLiteral("noreturn"), StringLiteral("nounwind"), StringLiteral("optnone"), + StringLiteral("optsize"), StringLiteral("returns_twice"), + StringLiteral("save-reg-params"), StringLiteral("target-features"), + StringLiteral("trap-func-name"), StringLiteral("tune-cpu"), StringLiteral("uwtable"), StringLiteral("vscale_range"), StringLiteral("willreturn"), + StringLiteral("zero-call-used-regs"), }; // List of LLVM IR attributes that are handled by prefix to map onto an MLIR @@ -2778,6 +2784,12 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func, funcOp.setWillReturn(true); if (func->hasFnAttribute(llvm::Attribute::NoReturn)) funcOp.setNoreturn(true); + if (func->hasFnAttribute(llvm::Attribute::OptimizeForSize)) + funcOp.setOptsize(true); + if (func->hasFnAttribute("save-reg-params")) + funcOp.setSaveRegParams(true); + if (func->hasFnAttribute(llvm::Attribute::MinSize)) + funcOp.setMinsize(true); if (func->hasFnAttribute(llvm::Attribute::ReturnsTwice)) funcOp.setReturnsTwice(true); if (func->hasFnAttribute(llvm::Attribute::Cold)) @@ -2793,6 +2805,10 @@ void ModuleImport::processFunctionAttributes(llvm::Function *func, if (llvm::Attribute attr = func->getFnAttribute("modular-format"); attr.isStringAttribute()) funcOp.setModularFormat(StringAttr::get(context, attr.getValueAsString())); + if (llvm::Attribute attr = func->getFnAttribute("zero-call-used-regs"); + attr.isStringAttribute()) + funcOp.setZeroCallUsedRegsAttr( + StringAttr::get(context, attr.getValueAsString())); if (func->hasFnAttribute("aarch64_pstate_sm_enabled")) funcOp.setArmStreaming(true); @@ -3017,6 +3033,12 @@ LogicalResult ModuleImport::convertCallAttributes(llvm::CallInst *inst, op.setNoUnwind(callAttrs.getFnAttr(llvm::Attribute::NoUnwind).isValid()); op.setWillReturn(callAttrs.getFnAttr(llvm::Attribute::WillReturn).isValid()); op.setNoreturn(callAttrs.getFnAttr(llvm::Attribute::NoReturn).isValid()); + op.setOptsize( + callAttrs.getFnAttr(llvm::Attribute::OptimizeForSize).isValid()); + op.setSaveRegParams(callAttrs.getFnAttr("save-reg-params").isValid()); + op.setNobuiltin(callAttrs.getFnAttr(llvm::Attribute::NoBuiltin).isValid()); + op.setMinsize(callAttrs.getFnAttr(llvm::Attribute::MinSize).isValid()); + op.setReturnsTwice( callAttrs.getFnAttr(llvm::Attribute::ReturnsTwice).isValid()); op.setHot(callAttrs.getFnAttr(llvm::Attribute::Hot).isValid()); @@ -3030,6 +3052,13 @@ LogicalResult ModuleImport::convertCallAttributes(llvm::CallInst *inst, if (llvm::Attribute attr = callAttrs.getFnAttr("modular-format"); attr.isStringAttribute()) op.setModularFormat(StringAttr::get(context, attr.getValueAsString())); + if (llvm::Attribute attr = callAttrs.getFnAttr("zero-call-used-regs"); + attr.isStringAttribute()) + op.setZeroCallUsedRegsAttr( + StringAttr::get(context, attr.getValueAsString())); + if (llvm::Attribute attr = callAttrs.getFnAttr("trap-func-name"); + attr.isStringAttribute()) + op.setTrapFuncNameAttr(StringAttr::get(context, attr.getValueAsString())); op.setNoInline(callAttrs.getFnAttr(llvm::Attribute::NoInline).isValid()); op.setAlwaysInline( callAttrs.getFnAttr(llvm::Attribute::AlwaysInline).isValid()); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index 6ee9b0cc1cee7..351198a320e9b 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1700,6 +1700,12 @@ static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func, llvmFunc->addFnAttr(llvm::Attribute::WillReturn); if (func.getNoreturnAttr()) llvmFunc->addFnAttr(llvm::Attribute::NoReturn); + if (func.getOptsizeAttr()) + llvmFunc->addFnAttr(llvm::Attribute::OptimizeForSize); + if (func.getMinsizeAttr()) + llvmFunc->addFnAttr(llvm::Attribute::MinSize); + if (func.getSaveRegParamsAttr()) + llvmFunc->addFnAttr("save-reg-params"); if (func.getNoCallerSavedRegistersAttr()) llvmFunc->addFnAttr("no_caller_saved_registers"); if (func.getNocallbackAttr()) @@ -1714,6 +1720,8 @@ static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func, if (UWTableKindAttr uwTableKindAttr = func.getUwtableKindAttr()) llvmFunc->setUWTableKind( convertUWTableKindToLLVM(uwTableKindAttr.getUwtableKind())); + if (StringAttr zcsr = func.getZeroCallUsedRegsAttr()) + llvmFunc->addFnAttr("zero-call-used-regs", zcsr.getValue()); if (ArrayAttr noBuiltins = func.getNobuiltinsAttr()) { if (noBuiltins.empty()) @@ -1723,6 +1731,9 @@ static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func, ModuleTranslation::convertNoBuiltin); } + mod.convertFunctionArrayAttr(func.getDefaultFuncAttrsAttr(), llvmFunc, + ModuleTranslation::convertDefaultFuncAttr); + if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr()); attr.isValid()) llvmFunc->addFnAttr(attr); diff --git a/mlir/test/Dialect/LLVMIR/func.mlir b/mlir/test/Dialect/LLVMIR/func.mlir index 8dc7f1ddab11c..8af1e52485425 100644 --- a/mlir/test/Dialect/LLVMIR/func.mlir +++ b/mlir/test/Dialect/LLVMIR/func.mlir @@ -396,6 +396,30 @@ module { llvm.return } + llvm.func @minsize_optsize() attributes { minsize, optsize } { + // CHECK: @minsize_optsize + // CHECK-SAME: attributes {minsize, optsize} + llvm.return + } + + llvm.func @save_reg_params() attributes { save_reg_params } { + // CHECK: @save_reg_params + // CHECK-SAME: attributes {save_reg_params} + llvm.return + } + + llvm.func @zero_call_used_regs() attributes { zero_call_used_regs="used-gpr-arg"} { + // CHECK: @zero_call_used_regs + // CHECK-SAME: attributes {zero_call_used_regs = "used-gpr-arg"} + llvm.return + } + + llvm.func @default_func_attrs() attributes {default_func_attrs={key="value",justKey}} { + // CHECK: @default_func_attrs + // CHECK-SAME: attributes {default_func_attrs = {justKey, key = "value"}} + llvm.return + } + } // ----- diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir index a39a4e9e18a56..c680d0d98ac5f 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -161,6 +161,27 @@ func.func @ops(%arg0: i32, %arg1: f32, // CHECK: llvm.call @baz() {allocsize = array<i32: 3, 5>} : () -> () llvm.call @baz() {allocsize = array<i32: 3, 5>} : () -> () +// CHECK: llvm.call @baz() {minsize} : () -> () + llvm.call @baz() {minsize} : () -> () + +// CHECK: llvm.call @baz() {optsize} : () -> () + llvm.call @baz() {optsize} : () -> () + +// CHECK: llvm.call @baz() {nobuiltin} : () -> () + llvm.call @baz() {nobuiltin} : () -> () + +// CHECK: llvm.call @baz() {save_reg_params} : () -> () + llvm.call @baz() {save_reg_params} : () -> () + +// CHECK: llvm.call @baz() {zero_call_used_regs = "all"} : () -> () + llvm.call @baz() {zero_call_used_regs="all"} : () -> () + +// CHECK: llvm.call @baz() {zero_call_used_regs = "thing"} : () -> () + llvm.call @baz() {zero_call_used_regs="thing"} : () -> () + +// CHECK: llvm.call @baz() {default_func_attrs = {justKey, key = "value"}} : () -> () + llvm.call @baz() {default_func_attrs={justKey, key = "value"}} : () -> () + // Terminator operations and their successors. // // CHECK: llvm.br ^[[BB1:.*]] diff --git a/mlir/test/Target/LLVMIR/Import/function-attributes.ll b/mlir/test/Target/LLVMIR/Import/function-attributes.ll index 6348511935e0c..7785a6f0f86c8 100644 --- a/mlir/test/Target/LLVMIR/Import/function-attributes.ll +++ b/mlir/test/Target/LLVMIR/Import/function-attributes.ll @@ -483,5 +483,37 @@ declare void @alloc_size_2(i32, i32) allocsize(0, 1) // ----- +; CHECK-LABEL: @minsize +; CHECK-SAME: attributes {minsize} +declare void @minsize() minsize + +// ----- + +; CHECK-LABEL: @optsize +; CHECK-SAME: attributes {optsize} +declare void @optsize() optsize + +// ----- + +; CHECK-LABEL: @save_reg_params +; CHECK-SAME: attributes {save_reg_params} +declare void @save_reg_params() "save-reg-params" + +// ----- + +; CHECK-LABEL: @zero_call_used_regs +; CHECK-SAME: attributes {zero_call_used_regs = "skip"} +declare void @zero_call_used_regs() "zero-call-used-regs"="skip" + +// ----- + +; Note: the 'default-func-attrs' aren't recoverable due to the way they lower +; to LLVM-IR, so they are handled on import as passthrough attributes. +; CHECK-LABEL: @default_func_attrs +; CHECK-SAME: attributes {passthrough = {{\[}}["key", "value"], "keyOnly"]} +declare void @default_func_attrs() "key"="value" "keyOnly" + +// ----- + ; expected-warning @unknown {{'preallocated' attribute is invalid on current operation, skipping it}} declare void @test() preallocated(i32) diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll index a72227f01716c..521f130341730 100644 --- a/mlir/test/Target/LLVMIR/Import/instructions.ll +++ b/mlir/test/Target/LLVMIR/Import/instructions.ll @@ -840,6 +840,93 @@ define void @call_alloc_size_2() { call void @f(i32 0, i32 0) allocsize(1, 0) ret void } +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_minsize +define void @call_minsize() { +; CHECK: llvm.call @f() {minsize} + call void @f() minsize + ret void +} + +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_optsize +define void @call_optsize() { +; CHECK: llvm.call @f() {optsize} + call void @f() optsize + ret void +} + +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_save_reg_params +define void @call_save_reg_params() { +; CHECK: llvm.call @f() {save_reg_params} + call void @f() "save-reg-params" + ret void +} + +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_zero_call_used_regs +define void @call_zero_call_used_regs() { +; CHECK: llvm.call @f() {zero_call_used_regs = "used"} + call void @f() "zero-call-used-regs"="used" + ret void +} + +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_trap_func_name +define void @call_trap_func_name() { +; CHECK: llvm.call @f() {trap_func_name = "something"} + call void @f() "trap-func-name"="something" + ret void +} + +; // ----- + +; CHECK: llvm.func @f() +declare void @f() + +; Note: the 'default-func-attrs' aren't recoverable due to the way they lower +; to LLVM-IR, and 'call' operations don't have passthrough, so these would be +; lost in translation. +; CHECK-LABEL: @call_default_func_attrs +define void @call_default_func_attrs() { +; CHECK: llvm.call @f() : () -> () + call void @f() "key"="value" "key" + ret void +} + +; // ----- + + +; CHECK: llvm.func @f() +declare void @f() + +; CHECK-LABEL: @call_nobuiltin +define void @call_nobuiltin() { +; CHECK: llvm.call @f() {nobuiltin} + call void @f() nobuiltin + ret void +} ; // ----- diff --git a/mlir/test/Target/LLVMIR/llvmir.mlir b/mlir/test/Target/LLVMIR/llvmir.mlir index f88cbda459e80..4fb5285584a89 100644 --- a/mlir/test/Target/LLVMIR/llvmir.mlir +++ b/mlir/test/Target/LLVMIR/llvmir.mlir @@ -2823,6 +2823,196 @@ llvm.func @allocsize_call_2() { // ----- +// CHECK-LABEL: @minsize +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @minsize() attributes { minsize } { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: minsize + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @minsize_call +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @minsize_call() { + llvm.call @f() {minsize} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: minsize + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @optsize +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @optsize() attributes { optsize } { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: optsize + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @optsize_call +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @optsize_call() { + llvm.call @f() {optsize} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: optsize + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @save_reg_params +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @save_reg_params() attributes { save_reg_params } { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "save-reg-params" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @save_reg_params_call +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @save_reg_params_call() { + llvm.call @f() {save_reg_params} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "save-reg-params" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @zero_call_used_regs_1 +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @zero_call_used_regs_1() attributes { zero_call_used_regs = "skip"} { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "zero-call-used-regs"="skip" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @zero_call_used_regs_2 +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @zero_call_used_regs_2() attributes { zero_call_used_regs = "all"} { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "zero-call-used-regs"="all" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @zero_call_used_regs_call_1 +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @zero_call_used_regs_call_1() { + llvm.call @f() {zero_call_used_regs="used_gpr_all"} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "zero-call-used-regs"="used_gpr_all" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @zero_call_used_regs_call_2 +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @zero_call_used_regs_call_2() { + llvm.call @f() {zero_call_used_regs="used"} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "zero-call-used-regs"="used" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @trap_func_name_call +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @trap_func_name_call() { + llvm.call @f() {trap_func_name="whatever"} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "trap-func-name"="whatever" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @default_func_attrs +// CHECK-SAME: #[[ATTRS:[0-9]+]] +llvm.func @default_func_attrs() attributes {default_func_attrs={key="value", justKey}} { + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "justKey" +// CHECK-SAME: "key"="value" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @default_func_attrs +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @default_func_attrs_call() { + llvm.call @f() {default_func_attrs={key="value", justKey}} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: "justKey" +// CHECK-SAME: "key"="value" + +// ----- + +llvm.func @f() + +// CHECK-LABEL: @nobuiltin_call +// CHECK: call void @f() #[[ATTRS:[0-9]+]] +llvm.func @nobuiltin_call() { + llvm.call @f() {nobuiltin} : () -> () + llvm.return +} + +// CHECK: #[[ATTRS]] +// CHECK-SAME: nobuiltin + +// ----- + llvm.func @f() // CHECK-LABEL: @convergent_call >From 12cdf31f1bf71e5965daa36f0a7c1433680be7b3 Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Thu, 5 Feb 2026 06:36:53 -0800 Subject: [PATCH 2/3] MLIR Review comments --- .../mlir/Target/LLVMIR/ModuleTranslation.h | 19 +++--------------- mlir/lib/Target/LLVMIR/ModuleImport.cpp | 1 - mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 20 +++++++++++++++++++ .../test/Target/LLVMIR/Import/instructions.ll | 1 - 4 files changed, 23 insertions(+), 18 deletions(-) diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index a6278e3afcd94..71a47adb2716b 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -352,24 +352,11 @@ class ModuleTranslation { // A helper callback that takes an attribute, and if it is a StringAttr, // properly converts it to the 'no-builtin-VALUE' form. static std::optional<llvm::Attribute> convertNoBuiltin(llvm::LLVMContext &ctx, - mlir::Attribute a) { - if (auto str = dyn_cast<StringAttr>(a)) - return llvm::Attribute::get(ctx, ("no-builtin-" + str.getValue()).str()); - return std::nullopt; - } + mlir::Attribute a); static std::optional<llvm::Attribute> convertDefaultFuncAttr(llvm::LLVMContext &ctx, - mlir::NamedAttribute namedAttr) { - StringAttr name = namedAttr.getName(); - Attribute value = namedAttr.getValue(); - - if (auto strVal = dyn_cast<StringAttr>(value)) - return llvm::Attribute::get(ctx, name.getValue(), strVal.getValue()); - if (mlir::isa<UnitAttr>(value)) - return llvm::Attribute::get(ctx, name.getValue()); - return std::nullopt; - } + mlir::NamedAttribute namedAttr); /// A template that takes an ArrayAttr, converts it via a user provided /// callback, then adds each element to as function attributes to the provided @@ -380,7 +367,7 @@ class ModuleTranslation { if (!arrayAttr) return; for (auto elt : arrayAttr) { - auto result = conv(getLLVMContext(), elt); + std::optional<llvm::Attribute> result = conv(getLLVMContext(), elt); if (result) op->addFnAttr(*result); } diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 09b12942638d9..e4a1ea8aa33ed 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -2679,7 +2679,6 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{ StringLiteral("no-nans-fp-math"), StringLiteral("no-signed-zeros-fp-math"), StringLiteral("no-builtins"), - StringLiteral("nobuiltin"), StringLiteral("nocallback"), StringLiteral("noduplicate"), StringLiteral("noinline"), diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index 351198a320e9b..ead80d24eceeb 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1874,6 +1874,26 @@ LogicalResult ModuleTranslation::convertArgAndResultAttrs( return success(); } +std::optional<llvm::Attribute> +ModuleTranslation::convertNoBuiltin(llvm::LLVMContext &ctx, mlir::Attribute a) { + if (auto str = dyn_cast<StringAttr>(a)) + return llvm::Attribute::get(ctx, ("no-builtin-" + str.getValue()).str()); + return std::nullopt; +} + +std::optional<llvm::Attribute> +ModuleTranslation::convertDefaultFuncAttr(llvm::LLVMContext &ctx, + mlir::NamedAttribute namedAttr) { + StringAttr name = namedAttr.getName(); + Attribute value = namedAttr.getValue(); + + if (auto strVal = dyn_cast<StringAttr>(value)) + return llvm::Attribute::get(ctx, name.getValue(), strVal.getValue()); + if (mlir::isa<UnitAttr>(value)) + return llvm::Attribute::get(ctx, name.getValue()); + return std::nullopt; +} + FailureOr<llvm::AttrBuilder> ModuleTranslation::convertParameterAttrs(Location loc, DictionaryAttr paramAttrs) { diff --git a/mlir/test/Target/LLVMIR/Import/instructions.ll b/mlir/test/Target/LLVMIR/Import/instructions.ll index 521f130341730..22a274049ecf4 100644 --- a/mlir/test/Target/LLVMIR/Import/instructions.ll +++ b/mlir/test/Target/LLVMIR/Import/instructions.ll @@ -917,7 +917,6 @@ define void @call_default_func_attrs() { ; // ----- - ; CHECK: llvm.func @f() declare void @f() >From 65977f104e14b154b6f850211e2c90ade42418ad Mon Sep 17 00:00:00 2001 From: erichkeane <[email protected]> Date: Thu, 5 Feb 2026 11:34:13 -0800 Subject: [PATCH 3/3] More review feedback addressed --- clang/lib/CIR/CodeGen/CIRGenCall.cpp | 6 +++--- .../mlir/Target/LLVMIR/ModuleTranslation.h | 16 ++++++++-------- .../Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp | 4 ++-- mlir/lib/Target/LLVMIR/ModuleTranslation.cpp | 8 ++++---- 4 files changed, 17 insertions(+), 17 deletions(-) diff --git a/clang/lib/CIR/CodeGen/CIRGenCall.cpp b/clang/lib/CIR/CodeGen/CIRGenCall.cpp index 2f52e5442ab67..cfbba27e12b93 100644 --- a/clang/lib/CIR/CodeGen/CIRGenCall.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenCall.cpp @@ -161,13 +161,13 @@ static void addDenormalModeAttrs(llvm::DenormalMode fpDenormalMode, /// -mlink-builtin-bitcode and should not simply overwrite any existing /// attributes in the linked library. static void -addMergeableDefaultFunctionAttributes(const CodeGenOptions &CodeGenOpts, +addMergeableDefaultFunctionAttributes(const CodeGenOptions &codeGenOpts, mlir::NamedAttrList &attrs) { - addDenormalModeAttrs(CodeGenOpts.FPDenormalMode, CodeGenOpts.FP32DenormalMode, + addDenormalModeAttrs(codeGenOpts.FPDenormalMode, codeGenOpts.FP32DenormalMode, attrs); } -llvm::StringLiteral +static llvm::StringLiteral getZeroCallUsedRegsKindStr(llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind k) { switch (k) { case llvm::ZeroCallUsedRegs::ZeroCallUsedRegsKind::Skip: diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index 71a47adb2716b..c67bb57985bd0 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -358,15 +358,15 @@ class ModuleTranslation { convertDefaultFuncAttr(llvm::LLVMContext &ctx, mlir::NamedAttribute namedAttr); - /// A template that takes an ArrayAttr, converts it via a user provided - /// callback, then adds each element to as function attributes to the provided - /// operation. - template <typename ArrayTy, typename Operation, typename Converter> - void convertFunctionArrayAttr(ArrayTy arrayAttr, Operation *op, - const Converter &conv) { - if (!arrayAttr) + /// A template that takes a collection-like attribute, and converts it via a + /// user provided callback, then adds each element as function attributes to + /// the provided operation. + template <typename AttrsTy, typename Operation, typename Converter> + void convertFunctionAttrCollection(AttrsTy attrs, Operation *op, + const Converter &conv) { + if (!attrs) return; - for (auto elt : arrayAttr) { + for (auto elt : attrs) { std::optional<llvm::Attribute> result = conv(getLLVMContext(), elt); if (result) op->addFnAttr(*result); diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp index 401a939b52371..36cbcd370364f 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -469,11 +469,11 @@ convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(), "no-builtins")); - moduleTranslation.convertFunctionArrayAttr( + moduleTranslation.convertFunctionAttrCollection( noBuiltins, call, ModuleTranslation::convertNoBuiltin); } - moduleTranslation.convertFunctionArrayAttr( + moduleTranslation.convertFunctionAttrCollection( callOp.getDefaultFuncAttrsAttr(), call, ModuleTranslation::convertDefaultFuncAttr); diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index ead80d24eceeb..37b0b8f3d5077 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1727,12 +1727,12 @@ static void convertFunctionAttributes(ModuleTranslation &mod, LLVMFuncOp func, if (noBuiltins.empty()) llvmFunc->addFnAttr("no-builtins"); - mod.convertFunctionArrayAttr(noBuiltins, llvmFunc, - ModuleTranslation::convertNoBuiltin); + mod.convertFunctionAttrCollection(noBuiltins, llvmFunc, + ModuleTranslation::convertNoBuiltin); } - mod.convertFunctionArrayAttr(func.getDefaultFuncAttrsAttr(), llvmFunc, - ModuleTranslation::convertDefaultFuncAttr); + mod.convertFunctionAttrCollection(func.getDefaultFuncAttrsAttr(), llvmFunc, + ModuleTranslation::convertDefaultFuncAttr); if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr()); attr.isValid()) _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
