[CIR] Add tons of function infra, plus a handful of attributes (#179811)

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.
This commit is contained in:
Erich Keane 2026-02-06 06:37:48 -08:00 committed by GitHub
parent 48619c8ab2
commit 5283f46615
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
26 changed files with 1116 additions and 54 deletions

View File

@ -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();

View File

@ -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);
}
static 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());
}

View File

@ -283,6 +283,12 @@ public:
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

View File

@ -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"

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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"

View File

@ -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"

View File

@ -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"

View File

@ -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> %{{.*}})

View File

@ -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> %{{.*}})

View File

@ -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> %{{.*}})

View File

@ -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> {{.+}})

View File

@ -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> %{{.*}})

View File

@ -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,
@ -2008,6 +2013,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,

View File

@ -351,22 +351,25 @@ public:
// 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) {
if (auto str = dyn_cast<StringAttr>(a))
return ("no-builtin-" + str.getValue()).str();
return std::nullopt;
}
static std::optional<llvm::Attribute> convertNoBuiltin(llvm::LLVMContext &ctx,
mlir::Attribute a);
/// 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,
const Converter &conv) {
for (Attribute a : array) {
auto result = conv(a);
static std::optional<llvm::Attribute>
convertDefaultFuncAttr(llvm::LLVMContext &ctx,
mlir::NamedAttribute namedAttr);
/// 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 : attrs) {
std::optional<llvm::Attribute> result = conv(getLLVMContext(), elt);
if (result)
op->addFnAttr(llvm::Attribute::get(getLLVMContext(), *result));
op->addFnAttr(*result);
}
}

View File

@ -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,

View File

@ -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,16 +455,28 @@ 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())
call->addFnAttr(llvm::Attribute::get(moduleTranslation.getLLVMContext(),
"no-builtins"));
moduleTranslation.convertFunctionArrayAttr(
moduleTranslation.convertFunctionAttrCollection(
noBuiltins, call, ModuleTranslation::convertNoBuiltin);
}
moduleTranslation.convertFunctionAttrCollection(
callOp.getDefaultFuncAttrsAttr(), call,
ModuleTranslation::convertDefaultFuncAttr);
if (llvm::Attribute attr =
moduleTranslation.convertAllocsizeAttr(callOp.getAllocsizeAttr());
attr.isValid())

View File

@ -2688,6 +2688,7 @@ 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"),
@ -2699,12 +2700,16 @@ static constexpr std::array kExplicitLLVMFuncOpAttributes{
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"),
StringLiteral("denormal_fpenv"),
};
@ -2795,6 +2800,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))
@ -2810,6 +2821,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);
@ -3024,6 +3039,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());
@ -3037,6 +3058,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());

View File

@ -1713,6 +1713,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())
@ -1727,15 +1733,20 @@ 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())
llvmFunc->addFnAttr("no-builtins");
mod.convertFunctionArrayAttr(noBuiltins, llvmFunc,
ModuleTranslation::convertNoBuiltin);
mod.convertFunctionAttrCollection(noBuiltins, llvmFunc,
ModuleTranslation::convertNoBuiltin);
}
mod.convertFunctionAttrCollection(func.getDefaultFuncAttrsAttr(), llvmFunc,
ModuleTranslation::convertDefaultFuncAttr);
if (llvm::Attribute attr = mod.convertAllocsizeAttr(func.getAllocsizeAttr());
attr.isValid())
llvmFunc->addFnAttr(attr);
@ -1879,6 +1890,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) {

View File

@ -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
}
}
// -----

View File

@ -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:.*]]

View File

@ -488,5 +488,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)

View File

@ -840,6 +840,92 @@ 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
}
; // -----

View File

@ -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