diff --git a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td index eed3b2cdb91ea..121cf53393f15 100644 --- a/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td +++ b/mlir/include/mlir/Dialect/LLVMIR/LLVMOps.td @@ -2107,18 +2107,14 @@ def LLVM_CallIntrinsicOp VariadicOfVariadic:$op_bundle_operands, DenseI32ArrayAttr:$op_bundle_sizes, - OptionalAttr:$op_bundle_tags); + OptionalAttr:$op_bundle_tags, + OptionalAttr:$arg_attrs, + OptionalAttr:$res_attrs); let results = (outs Optional:$results); let llvmBuilder = [{ return convertCallLLVMIntrinsicOp(op, builder, moduleTranslation); }]; - let assemblyFormat = [{ - $intrin `(` $args `)` - ( custom($op_bundle_operands, type($op_bundle_operands), - $op_bundle_tags)^ )? - `:` functional-type($args, $results) - attr-dict - }]; + let hasCustomAssemblyFormat = 1; let builders = [ OpBuilder<(ins "StringAttr":$intrin, "ValueRange":$args)>, diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h index 6c673295d8dcc..c0af924e0aecd 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleImport.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleImport.h @@ -272,6 +272,11 @@ class ModuleImport { SmallVectorImpl &valuesOut, SmallVectorImpl &attrsOut); + /// Converts the parameter and result attributes in `argsAttr` and `resAttr` + /// and add them to the `callOp`. + void convertParameterAttributes(llvm::CallBase *call, ArrayAttr &argsAttr, + ArrayAttr &resAttr, OpBuilder &builder); + private: /// Clears the accumulated state before processing a new region. void clearRegionState() { @@ -350,7 +355,8 @@ class ModuleImport { DictionaryAttr convertParameterAttribute(llvm::AttributeSet llvmParamAttrs, OpBuilder &builder); /// Converts the parameter and result attributes attached to `call` and adds - /// them to the `callOp`. + /// them to the `callOp`. Implemented in terms of the the public definition of + /// convertParameterAttributes. void convertParameterAttributes(llvm::CallBase *call, CallOpInterface callOp, OpBuilder &builder); /// Converts the attributes attached to `inst` and adds them to the `op`. diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h index eb59ef8c62266..4e984baa65f16 100644 --- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h +++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h @@ -237,7 +237,7 @@ class ModuleTranslation { /// Translates parameter attributes of a call and adds them to the returned /// AttrBuilder. Returns failure if any of the translations failed. - FailureOr convertParameterAttrs(CallOpInterface callOp, + FailureOr convertParameterAttrs(mlir::Location loc, DictionaryAttr paramAttrs); /// Gets the named metadata in the LLVM IR module being constructed, creating diff --git a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp index fb9236fcc640d..d37f9f97fffe3 100644 --- a/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp +++ b/mlir/lib/Dialect/LLVMIR/IR/LLVMDialect.cpp @@ -3547,7 +3547,8 @@ void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, mlir::StringAttr intrin, mlir::ValueRange args) { build(builder, state, /*resultTypes=*/TypeRange{}, intrin, args, FastmathFlagsAttr{}, - /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}); + /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{}, + /*res_attrs=*/{}); } void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, @@ -3555,14 +3556,16 @@ void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, mlir::LLVM::FastmathFlagsAttr fastMathFlags) { build(builder, state, /*resultTypes=*/TypeRange{}, intrin, args, fastMathFlags, - /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}); + /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{}, + /*res_attrs=*/{}); } void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, mlir::Type resultType, mlir::StringAttr intrin, mlir::ValueRange args) { build(builder, state, {resultType}, intrin, args, FastmathFlagsAttr{}, - /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}); + /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{}, + /*res_attrs=*/{}); } void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, @@ -3570,7 +3573,101 @@ void CallIntrinsicOp::build(OpBuilder &builder, OperationState &state, mlir::StringAttr intrin, mlir::ValueRange args, mlir::LLVM::FastmathFlagsAttr fastMathFlags) { build(builder, state, resultTypes, intrin, args, fastMathFlags, - /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}); + /*op_bundle_operands=*/{}, /*op_bundle_tags=*/{}, /*arg_attrs=*/{}, + /*res_attrs=*/{}); +} + +ParseResult CallIntrinsicOp::parse(OpAsmParser &parser, + OperationState &result) { + StringAttr intrinAttr; + SmallVector operands; + SmallVector> opBundleOperands; + SmallVector> opBundleOperandTypes; + ArrayAttr opBundleTags; + + // Parse intrinsic name. + if (parser.parseCustomAttributeWithFallback( + intrinAttr, parser.getBuilder().getType())) + return failure(); + result.addAttribute(CallIntrinsicOp::getIntrinAttrName(result.name), + intrinAttr); + + if (parser.parseLParen()) + return failure(); + + // Parse the function arguments. + if (parser.parseOperandList(operands)) + return mlir::failure(); + + if (parser.parseRParen()) + return mlir::failure(); + + // Handle bundles. + SMLoc opBundlesLoc = parser.getCurrentLocation(); + if (std::optional result = parseOpBundles( + parser, opBundleOperands, opBundleOperandTypes, opBundleTags); + result && failed(*result)) + return failure(); + if (opBundleTags && !opBundleTags.empty()) + result.addAttribute( + CallIntrinsicOp::getOpBundleTagsAttrName(result.name).getValue(), + opBundleTags); + + if (parser.parseOptionalAttrDict(result.attributes)) + return mlir::failure(); + + SmallVector argAttrs; + SmallVector resultAttrs; + if (parseCallTypeAndResolveOperands(parser, result, /*isDirect=*/true, + operands, argAttrs, resultAttrs)) + return failure(); + call_interface_impl::addArgAndResultAttrs( + parser.getBuilder(), result, argAttrs, resultAttrs, + getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name)); + + if (resolveOpBundleOperands(parser, opBundlesLoc, result, opBundleOperands, + opBundleOperandTypes, + getOpBundleSizesAttrName(result.name))) + return failure(); + + int32_t numOpBundleOperands = 0; + for (const auto &operands : opBundleOperands) + numOpBundleOperands += operands.size(); + + result.addAttribute( + CallIntrinsicOp::getOperandSegmentSizeAttr(), + parser.getBuilder().getDenseI32ArrayAttr( + {static_cast(operands.size()), numOpBundleOperands})); + + return mlir::success(); +} + +void CallIntrinsicOp::print(OpAsmPrinter &p) { + p << ' '; + p.printAttributeWithoutType(getIntrinAttr()); + + OperandRange args = getArgs(); + p << "(" << args << ")"; + + // Operand bundles. + if (!getOpBundleOperands().empty()) { + p << ' '; + printOpBundles(p, *this, getOpBundleOperands(), + getOpBundleOperands().getTypes(), getOpBundleTagsAttr()); + } + + p.printOptionalAttrDict(processFMFAttr((*this)->getAttrs()), + {getOperandSegmentSizesAttrName(), + getOpBundleSizesAttrName(), getIntrinAttrName(), + getOpBundleTagsAttrName(), getArgAttrsAttrName(), + getResAttrsAttrName()}); + + p << " : "; + + // Reconstruct the MLIR function type from operand and result types. + call_interface_impl::printFunctionSignature( + p, args.getTypes(), getArgAttrsAttr(), + /*isVariadic=*/false, getResultTypes(), getResAttrsAttr()); } //===----------------------------------------------------------------------===// diff --git a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp index 4f89ee703ebb9..25599efe64322 100644 --- a/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.cpp @@ -135,6 +135,46 @@ convertOperandBundles(OperandRangeRange bundleOperands, return convertOperandBundles(bundleOperands, *bundleTags, moduleTranslation); } +static LogicalResult +convertParameterAndResultAttrs(mlir::Location loc, ArrayAttr argAttrsArray, + ArrayAttr resAttrsArray, llvm::CallBase *call, + LLVM::ModuleTranslation &moduleTranslation) { + if (argAttrsArray) { + for (auto [argIdx, argAttrsAttr] : llvm::enumerate(argAttrsArray)) { + if (auto argAttrs = cast(argAttrsAttr); + !argAttrs.empty()) { + FailureOr attrBuilder = + moduleTranslation.convertParameterAttrs(loc, argAttrs); + if (failed(attrBuilder)) + return failure(); + call->addParamAttrs(argIdx, *attrBuilder); + } + } + } + + if (resAttrsArray && resAttrsArray.size() > 0) { + if (resAttrsArray.size() != 1) + return mlir::emitError(loc, "llvm.func cannot have multiple results"); + if (auto resAttrs = cast(resAttrsArray[0]); + !resAttrs.empty()) { + FailureOr attrBuilder = + moduleTranslation.convertParameterAttrs(loc, resAttrs); + if (failed(attrBuilder)) + return failure(); + call->addRetAttrs(*attrBuilder); + } + } + return success(); +} + +static LogicalResult +convertParameterAndResultAttrs(CallOpInterface callOp, llvm::CallBase *call, + LLVM::ModuleTranslation &moduleTranslation) { + return convertParameterAndResultAttrs( + callOp.getLoc(), callOp.getArgAttrsAttr(), callOp.getResAttrsAttr(), call, + moduleTranslation); +} + /// Builder for LLVM_CallIntrinsicOp static LogicalResult convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, @@ -201,6 +241,12 @@ convertCallLLVMIntrinsicOp(CallIntrinsicOp op, llvm::IRBuilderBase &builder, fn, moduleTranslation.lookupValues(op.getArgs()), convertOperandBundles(op.getOpBundleOperands(), op.getOpBundleTags(), moduleTranslation)); + + if (failed(convertParameterAndResultAttrs(op.getLoc(), op.getArgAttrsAttr(), + op.getResAttrsAttr(), inst, + moduleTranslation))) + return failure(); + if (op.getNumResults() == 1) moduleTranslation.mapValue(op->getResults().front()) = inst; return success(); @@ -224,39 +270,6 @@ static void convertLinkerOptionsOp(ArrayAttr options, linkerMDNode->addOperand(listMDNode); } -static LogicalResult -convertParameterAndResultAttrs(CallOpInterface callOp, llvm::CallBase *call, - LLVM::ModuleTranslation &moduleTranslation) { - if (ArrayAttr argAttrsArray = callOp.getArgAttrsAttr()) { - for (auto [argIdx, argAttrsAttr] : llvm::enumerate(argAttrsArray)) { - if (auto argAttrs = cast(argAttrsAttr); - !argAttrs.empty()) { - FailureOr attrBuilder = - moduleTranslation.convertParameterAttrs(callOp, argAttrs); - if (failed(attrBuilder)) - return failure(); - call->addParamAttrs(argIdx, *attrBuilder); - } - } - } - - ArrayAttr resAttrsArray = callOp.getResAttrsAttr(); - if (resAttrsArray && resAttrsArray.size() > 0) { - if (resAttrsArray.size() != 1) - return mlir::emitError(callOp.getLoc(), - "llvm.func cannot have multiple results"); - if (auto resAttrs = cast(resAttrsArray[0]); - !resAttrs.empty()) { - FailureOr attrBuilder = - moduleTranslation.convertParameterAttrs(callOp, resAttrs); - if (failed(attrBuilder)) - return failure(); - call->addRetAttrs(*attrBuilder); - } - } - return success(); -} - static LogicalResult convertOperationImpl(Operation &opInst, llvm::IRBuilderBase &builder, LLVM::ModuleTranslation &moduleTranslation) { diff --git a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp index 24f500557c6de..fbf2d709c240c 100644 --- a/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp +++ b/mlir/lib/Target/LLVMIR/LLVMImportInterface.cpp @@ -45,6 +45,11 @@ LogicalResult mlir::LLVMImportInterface::convertUnregisteredIntrinsic( moduleImport.setFastmathFlagsAttr(inst, op); + ArrayAttr argsAttr, resAttr; + moduleImport.convertParameterAttributes(inst, argsAttr, resAttr, builder); + op.setArgAttrsAttr(argsAttr); + op.setResAttrsAttr(resAttr); + // Update importer tracking of results. unsigned numRes = op.getNumResults(); if (numRes == 1) diff --git a/mlir/lib/Target/LLVMIR/ModuleImport.cpp b/mlir/lib/Target/LLVMIR/ModuleImport.cpp index 7ea82f61fadbb..2d3c0efd9a972 100644 --- a/mlir/lib/Target/LLVMIR/ModuleImport.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleImport.cpp @@ -2213,7 +2213,8 @@ void ModuleImport::convertParameterAttributes(llvm::Function *func, } void ModuleImport::convertParameterAttributes(llvm::CallBase *call, - CallOpInterface callOp, + ArrayAttr &argsAttr, + ArrayAttr &resAttr, OpBuilder &builder) { llvm::AttributeList llvmAttrs = call->getAttributes(); SmallVector llvmArgAttrsSet; @@ -2233,14 +2234,23 @@ void ModuleImport::convertParameterAttributes(llvm::CallBase *call, SmallVector argAttrs; for (auto &llvmArgAttrs : llvmArgAttrsSet) argAttrs.emplace_back(convertParameterAttribute(llvmArgAttrs, builder)); - callOp.setArgAttrsAttr(getArrayAttr(argAttrs)); + argsAttr = getArrayAttr(argAttrs); } llvm::AttributeSet llvmResAttr = llvmAttrs.getRetAttrs(); if (!llvmResAttr.hasAttributes()) return; DictionaryAttr resAttrs = convertParameterAttribute(llvmResAttr, builder); - callOp.setResAttrsAttr(getArrayAttr({resAttrs})); + resAttr = getArrayAttr({resAttrs}); +} + +void ModuleImport::convertParameterAttributes(llvm::CallBase *call, + CallOpInterface callOp, + OpBuilder &builder) { + ArrayAttr argsAttr, resAttr; + convertParameterAttributes(call, argsAttr, resAttr, builder); + callOp.setArgAttrsAttr(argsAttr); + callOp.setResAttrsAttr(resAttr); } template diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp index eda6b51ff45ea..46d73ded4ca9a 100644 --- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp +++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp @@ -1696,10 +1696,9 @@ ModuleTranslation::convertParameterAttrs(LLVMFuncOp func, int argIdx, } FailureOr -ModuleTranslation::convertParameterAttrs(CallOpInterface callOp, +ModuleTranslation::convertParameterAttrs(Location loc, DictionaryAttr paramAttrs) { llvm::AttrBuilder attrBuilder(llvmModule->getContext()); - Location loc = callOp.getLoc(); auto attrNameToKindMapping = getAttrNameToKindMapping(); for (auto namedAttr : paramAttrs) { diff --git a/mlir/test/Dialect/LLVMIR/call-intrin.mlir b/mlir/test/Dialect/LLVMIR/call-intrin.mlir index 24aa38fca4a65..ea15ec2d5f654 100644 --- a/mlir/test/Dialect/LLVMIR/call-intrin.mlir +++ b/mlir/test/Dialect/LLVMIR/call-intrin.mlir @@ -7,7 +7,7 @@ llvm.func @round_sse41() -> vector<4xf32> { %0 = llvm.mlir.constant(1 : i32) : i32 %1 = llvm.mlir.constant(dense<0.2> : vector<4xf32>) : vector<4xf32> - %res = llvm.call_intrinsic "llvm.x86.sse41.round.ss"(%1, %1, %0) : (vector<4xf32>, vector<4xf32>, i32) -> vector<4xf32> {fastmathFlags = #llvm.fastmath} + %res = llvm.call_intrinsic "llvm.x86.sse41.round.ss"(%1, %1, %0) {fastmathFlags = #llvm.fastmath} : (vector<4xf32>, vector<4xf32>, i32) -> vector<4xf32> llvm.return %res: vector<4xf32> } @@ -19,7 +19,7 @@ llvm.func @round_sse41() -> vector<4xf32> { // CHECK: } llvm.func @round_overloaded() -> f32 { %0 = llvm.mlir.constant(1.0 : f32) : f32 - %res = llvm.call_intrinsic "llvm.round"(%0) : (f32) -> f32 {} + %res = llvm.call_intrinsic "llvm.round"(%0) {} : (f32) -> f32 llvm.return %res: f32 } @@ -34,7 +34,7 @@ llvm.func @lifetime_start() { %0 = llvm.mlir.constant(4 : i64) : i64 %1 = llvm.mlir.constant(1 : i8) : i8 %2 = llvm.alloca %1 x f32 : (i8) -> !llvm.ptr - llvm.call_intrinsic "llvm.lifetime.start"(%0, %2) : (i64, !llvm.ptr) -> () {} + llvm.call_intrinsic "llvm.lifetime.start"(%0, %2) {} : (i64, !llvm.ptr) -> () llvm.return } @@ -64,7 +64,7 @@ llvm.func @bad_types() { %0 = llvm.mlir.constant(1 : i8) : i8 // expected-error@below {{call intrinsic signature i8 (i8) to overloaded intrinsic "llvm.round" does not match any of the overloads}} // expected-error@below {{LLVM Translation failed for operation: llvm.call_intrinsic}} - llvm.call_intrinsic "llvm.round"(%0) : (i8) -> i8 {} + llvm.call_intrinsic "llvm.round"(%0) {} : (i8) -> i8 llvm.return } @@ -102,6 +102,15 @@ llvm.func @bad_args() { %1 = llvm.mlir.constant(dense<0.2> : vector<4xf32>) : vector<4xf32> // expected-error @below {{intrinsic call operand #2 has type i64 but "llvm.x86.sse41.round.ss" expects i32}} // expected-error@below {{LLVM Translation failed for operation: llvm.call_intrinsic}} - %res = llvm.call_intrinsic "llvm.x86.sse41.round.ss"(%1, %1, %0) : (vector<4xf32>, vector<4xf32>, i64) -> vector<4xf32> {fastmathFlags = #llvm.fastmath} + %res = llvm.call_intrinsic "llvm.x86.sse41.round.ss"(%1, %1, %0) {fastmathFlags = #llvm.fastmath} : (vector<4xf32>, vector<4xf32>, i64) -> vector<4xf32> llvm.return } + +// ----- + +// CHECK-LABEL: intrinsic_call_arg_attrs +llvm.func @intrinsic_call_arg_attrs(%arg0: i32) -> i32 { + // CHECK: call i32 @llvm.riscv.sha256sig0(i32 signext %{{.*}}) + %0 = llvm.call_intrinsic "llvm.riscv.sha256sig0"(%arg0) : (i32 {llvm.signext}) -> (i32) + llvm.return %0 : i32 +} diff --git a/mlir/test/Dialect/LLVMIR/invalid.mlir b/mlir/test/Dialect/LLVMIR/invalid.mlir index 0415ab00bdb05..fcb6ae07f4912 100644 --- a/mlir/test/Dialect/LLVMIR/invalid.mlir +++ b/mlir/test/Dialect/LLVMIR/invalid.mlir @@ -1693,6 +1693,15 @@ llvm.func @wrong_number_of_bundle_types() { // ----- +llvm.func @wrong_number_of_bundle_types_intrin(%arg0: i32) -> i32 { + %0 = llvm.mlir.constant(0 : i32) : i32 + // expected-error@+1 {{expected 1 types for operand bundle operands for operand bundle #0, but actually got 2}} + %1 = llvm.call_intrinsic "llvm.riscv.sha256sig0"(%arg0) ["tag"(%0 : i32, i32)] : (i32 {llvm.signext}) -> (i32) + llvm.return %1 : i32 +} + +// ----- + llvm.func @foo() llvm.func @wrong_number_of_bundle_tags() { %0 = llvm.mlir.constant(0 : i32) : i32 diff --git a/mlir/test/Dialect/LLVMIR/roundtrip.mlir b/mlir/test/Dialect/LLVMIR/roundtrip.mlir index e0a17308af828..d0aa65d14a176 100644 --- a/mlir/test/Dialect/LLVMIR/roundtrip.mlir +++ b/mlir/test/Dialect/LLVMIR/roundtrip.mlir @@ -988,3 +988,17 @@ llvm.func @test_invoke_arg_attrs_indirect(%arg0: i16, %arg1: !llvm.ptr) -> i16 a ^bb2: llvm.return %0 : i16 } + +// CHECK-LABEL: intrinsic_call_arg_attrs +llvm.func @intrinsic_call_arg_attrs(%arg0: i32) -> i32 { + // CHECK: %{{.*}} = llvm.call_intrinsic "llvm.riscv.sha256sig0"({{.*}}) : (i32 {llvm.signext}) -> i32 + %0 = llvm.call_intrinsic "llvm.riscv.sha256sig0"(%arg0) : (i32 {llvm.signext}) -> (i32) + llvm.return %0 : i32 +} + +// CHECK-LABEL: intrinsic_call_arg_attrs_bundles +llvm.func @intrinsic_call_arg_attrs_bundles(%arg0: i32) -> i32 { + // CHECK: %{{.*}} = llvm.call_intrinsic "llvm.riscv.sha256sig0"({{.*}}) ["adazdazd"()] {constant} : (i32 {llvm.signext}) -> i32 + %0 = llvm.call_intrinsic "llvm.riscv.sha256sig0"(%arg0) ["adazdazd"()] {constant} : (i32 {llvm.signext}) -> (i32) + llvm.return %0 : i32 +} diff --git a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll index 554be8f797b75..5afc29a5642fc 100644 --- a/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll +++ b/mlir/test/Target/LLVMIR/Import/intrinsic-unregistered.ll @@ -66,3 +66,14 @@ define void @lround_test(float %0, double %1) { %3 = call i32 @llvm.lround.i32.f32(float %0) ret void } + +; // ----- + +declare i32 @llvm.riscv.sha256sig0(i32) + +; CHECK-LABEL: test_intrin_arg_attr +define signext i32 @test_intrin_arg_attr(i32 signext %a) nounwind { + ; CHECK: llvm.call_intrinsic "llvm.riscv.sha256sig0"({{.*}}) : (i32 {llvm.signext}) -> i32 + %val = call i32 @llvm.riscv.sha256sig0(i32 signext %a) + ret i32 %val +}