CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
415 lines
17 KiB
C++
415 lines
17 KiB
C++
//===- FIRCallInterfaceTest.cpp - fir::CallOp setCalleeFromCallable tests -===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Tests for CallOpInterface on fir::CallOp.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "gtest/gtest.h"
|
|
#include "mlir/Dialect/Func/IR/FuncOps.h"
|
|
#include "mlir/IR/Builders.h"
|
|
#include "mlir/IR/BuiltinAttributes.h"
|
|
#include "mlir/IR/BuiltinOps.h"
|
|
#include "mlir/Interfaces/CallInterfaces.h"
|
|
#include "flang/Optimizer/Dialect/FIROps.h"
|
|
#include "flang/Optimizer/Support/InitFIR.h"
|
|
#include "llvm/ADT/ArrayRef.h"
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
using namespace mlir;
|
|
|
|
namespace {
|
|
|
|
static bool isSymbolRef(mlir::CallInterfaceCallable callable) {
|
|
return llvm::isa<SymbolRefAttr>(callable);
|
|
}
|
|
static bool isValue(mlir::CallInterfaceCallable callable) {
|
|
return llvm::isa<Value>(callable);
|
|
}
|
|
|
|
/// Creates a module and a function with entry block. Builder insertion point is
|
|
/// set to the block start. Returns (func, block) so tests can create calls in
|
|
/// the block and use block arguments as callee/args.
|
|
std::pair<func::FuncOp, Block *> createModuleWithFunction(
|
|
OpBuilder &builder, Location loc, StringRef name, FunctionType funcType) {
|
|
ModuleOp module = ModuleOp::create(builder, loc);
|
|
builder.setInsertionPointToStart(module.getBody());
|
|
auto func = func::FuncOp::create(builder, loc, name, funcType);
|
|
func.setPrivate();
|
|
Block *block = func.addEntryBlock();
|
|
builder.setInsertionPointToStart(block);
|
|
return {func, block};
|
|
}
|
|
|
|
} // namespace
|
|
|
|
struct FIRCallInterfaceTest : public testing::Test {
|
|
void SetUp() override { fir::support::loadDialects(context); }
|
|
|
|
MLIRContext context;
|
|
};
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_directToDirect) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto funcType = builder.getFunctionType({}, {});
|
|
(void)createModuleWithFunction(builder, loc, "target", funcType);
|
|
|
|
// Direct call: fir.call @target()
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "target");
|
|
auto callOp = fir::CallOp::create(
|
|
builder, loc, callTargetRef, llvm::ArrayRef<mlir::Type>{}, ValueRange{});
|
|
ASSERT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 0u);
|
|
|
|
// Change to another symbol; should remain direct with no extra operand.
|
|
auto newCallTargetRef = FlatSymbolRefAttr::get(&context, "other");
|
|
callOp.setCalleeFromCallable(newCallTargetRef);
|
|
|
|
EXPECT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(llvm::cast<SymbolRefAttr>(callOp.getCallableForCallee())
|
|
.getRootReference()
|
|
.getValue(),
|
|
"other");
|
|
EXPECT_EQ(callOp.getNumOperands(), 0u);
|
|
EXPECT_TRUE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_indirectToDirect) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto funcType = builder.getFunctionType({}, {});
|
|
auto containerType = builder.getFunctionType({funcType}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
|
|
// Indirect call: fir.call %arg0()
|
|
Value callTargetValue = block->getArgument(0);
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{callTargetValue});
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_FALSE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
|
|
// Switch to direct call; operand 0 must be removed.
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "direct_target");
|
|
callOp.setCalleeFromCallable(callTargetRef);
|
|
|
|
EXPECT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(llvm::cast<SymbolRefAttr>(callOp.getCallableForCallee())
|
|
.getRootReference()
|
|
.getValue(),
|
|
"direct_target");
|
|
EXPECT_EQ(callOp.getNumOperands(), 0u);
|
|
EXPECT_TRUE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_directToIndirect) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto funcType = builder.getFunctionType({}, {});
|
|
auto containerType = builder.getFunctionType({funcType}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
|
|
// Direct call first
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "target");
|
|
auto callOp = fir::CallOp::create(
|
|
builder, loc, callTargetRef, llvm::ArrayRef<mlir::Type>{}, ValueRange{});
|
|
ASSERT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 0u);
|
|
|
|
// Switch to indirect; attribute must be unset, operand 0 set.
|
|
Value callTargetValue = block->getArgument(0);
|
|
callOp.setCalleeFromCallable(callTargetValue);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), callTargetValue);
|
|
EXPECT_FALSE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_indirectToIndirect) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto funcType = builder.getFunctionType({}, {});
|
|
auto containerType = builder.getFunctionType({funcType, funcType}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
|
|
Value callTarget0 = block->getArgument(0);
|
|
Value callTarget1 = block->getArgument(1);
|
|
|
|
// Indirect call: fir.call %arg0()
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{callTarget0});
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), callTarget0);
|
|
|
|
// Switch to other indirect call target; should remain indirect, operand 0
|
|
// updated.
|
|
callOp.setCalleeFromCallable(callTarget1);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), callTarget1);
|
|
EXPECT_FALSE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_directToIndirect_withArgs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value calleeVal = block->getArgument(0);
|
|
Value argVal = block->getArgument(1);
|
|
|
|
// Direct call with one argument: fir.call @target(%arg)
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "target");
|
|
auto callOp = fir::CallOp::create(builder, loc, callTargetRef,
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{argVal});
|
|
ASSERT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), argVal);
|
|
|
|
// Switch to indirect; callee must be inserted at 0, arg preserved.
|
|
callOp.setCalleeFromCallable(calleeVal);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), calleeVal);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
EXPECT_FALSE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest, setCalleeFromCallable_indirectToDirect_withArgs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value calleeVal = block->getArgument(0);
|
|
Value argVal = block->getArgument(1);
|
|
|
|
// Indirect call with one argument: fir.call %callee(%arg)
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{calleeVal, argVal});
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), calleeVal);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
|
|
// Switch to direct; callee operand must be removed, arg preserved.
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "direct_target");
|
|
callOp.setCalleeFromCallable(callTargetRef);
|
|
|
|
EXPECT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), argVal);
|
|
EXPECT_TRUE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
TEST_F(
|
|
FIRCallInterfaceTest, setCalleeFromCallable_indirectToIndirect_withArgs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value callee0 = block->getArgument(0);
|
|
Value callee1 = block->getArgument(1);
|
|
Value argVal = block->getArgument(2);
|
|
|
|
// Indirect call with one argument: fir.call %callee0(%arg)
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{callee0, argVal});
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), callee0);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
|
|
// Switch to other indirect callee; operand 0 updated, arg preserved.
|
|
callOp.setCalleeFromCallable(callee1);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), callee1);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
EXPECT_FALSE(callOp->getAttr(fir::CallOp::getCalleeAttrNameStr()));
|
|
}
|
|
|
|
static ArrayAttr makeArgAttrs(
|
|
MLIRContext *ctx, llvm::ArrayRef<DictionaryAttr> dicts) {
|
|
llvm::SmallVector<Attribute> attrs(dicts.begin(), dicts.end());
|
|
return ArrayAttr::get(ctx, attrs);
|
|
}
|
|
|
|
static DictionaryAttr makeTestArgDict(MLIRContext *ctx, StringRef value) {
|
|
return DictionaryAttr::get(ctx,
|
|
{NamedAttribute(
|
|
StringAttr::get(ctx, "test.attr"), StringAttr::get(ctx, value))});
|
|
}
|
|
|
|
TEST_F(
|
|
FIRCallInterfaceTest, setCalleeFromCallable_directToDirect_withArgAttrs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value argVal = block->getArgument(1);
|
|
|
|
// Direct call with one argument and arg_attrs.
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "target");
|
|
auto callOp = fir::CallOp::create(builder, loc, callTargetRef,
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{argVal});
|
|
callOp->setAttr(callOp.getArgAttrsAttrName(),
|
|
makeArgAttrs(&context, {makeTestArgDict(&context, "arg0")}));
|
|
ASSERT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
|
|
// Switch to another direct callee
|
|
auto newCallTargetRef = FlatSymbolRefAttr::get(&context, "other_target");
|
|
callOp.setCalleeFromCallable(newCallTargetRef);
|
|
|
|
EXPECT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(llvm::cast<SymbolRefAttr>(callOp.getCallableForCallee())
|
|
.getRootReference()
|
|
.getValue(),
|
|
"other_target");
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), argVal);
|
|
ArrayAttr argAttrs = callOp.getArgAttrsAttr();
|
|
ASSERT_TRUE(argAttrs);
|
|
ASSERT_EQ(argAttrs.size(), 1u);
|
|
EXPECT_EQ(llvm::cast<DictionaryAttr>(argAttrs[0]).get("test.attr"),
|
|
StringAttr::get(&context, "arg0"));
|
|
}
|
|
|
|
TEST_F(
|
|
FIRCallInterfaceTest, setCalleeFromCallable_directToIndirect_withArgAttrs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value calleeVal = block->getArgument(0);
|
|
Value argVal = block->getArgument(1);
|
|
|
|
// Direct call with one argument and arg_attrs for that argument.
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "target");
|
|
auto callOp = fir::CallOp::create(builder, loc, callTargetRef,
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{argVal});
|
|
callOp->setAttr(callOp.getArgAttrsAttrName(),
|
|
makeArgAttrs(&context, {makeTestArgDict(&context, "arg0")}));
|
|
ASSERT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
|
|
// Switch to indirect
|
|
callOp.setCalleeFromCallable(calleeVal);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), calleeVal);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
ArrayAttr argAttrs = callOp.getArgAttrsAttr();
|
|
ASSERT_TRUE(argAttrs);
|
|
ASSERT_EQ(argAttrs.size(), 2u);
|
|
// First entry is empty dict for callee.
|
|
EXPECT_TRUE(llvm::cast<DictionaryAttr>(argAttrs[0]).empty());
|
|
// Second entry preserves the argument's attribute.
|
|
auto argDict = llvm::cast<DictionaryAttr>(argAttrs[1]);
|
|
EXPECT_EQ(argDict.get("test.attr"), StringAttr::get(&context, "arg0"));
|
|
}
|
|
|
|
TEST_F(
|
|
FIRCallInterfaceTest, setCalleeFromCallable_indirectToDirect_withArgAttrs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value calleeVal = block->getArgument(0);
|
|
Value argVal = block->getArgument(1);
|
|
|
|
// Indirect call with callee + one argument
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{calleeVal, argVal});
|
|
callOp->setAttr(callOp.getArgAttrsAttrName(),
|
|
makeArgAttrs(&context,
|
|
{DictionaryAttr::get(&context, {}),
|
|
makeTestArgDict(&context, "arg0")}));
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
|
|
// Switch to direct
|
|
auto callTargetRef = FlatSymbolRefAttr::get(&context, "direct_target");
|
|
callOp.setCalleeFromCallable(callTargetRef);
|
|
|
|
EXPECT_TRUE(isSymbolRef(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 1u);
|
|
EXPECT_EQ(callOp.getOperand(0), argVal);
|
|
ArrayAttr argAttrs = callOp.getArgAttrsAttr();
|
|
ASSERT_TRUE(argAttrs);
|
|
ASSERT_EQ(argAttrs.size(), 1u);
|
|
EXPECT_EQ(llvm::cast<DictionaryAttr>(argAttrs[0]).get("test.attr"),
|
|
StringAttr::get(&context, "arg0"));
|
|
}
|
|
|
|
TEST_F(FIRCallInterfaceTest,
|
|
setCalleeFromCallable_indirectToIndirect_withArgAttrs) {
|
|
OpBuilder builder(&context);
|
|
auto loc = builder.getUnknownLoc();
|
|
auto i32Ty = builder.getI32Type();
|
|
auto funcType = builder.getFunctionType({i32Ty}, {});
|
|
auto containerType = builder.getFunctionType({funcType, funcType, i32Ty}, {});
|
|
auto [func, block] =
|
|
createModuleWithFunction(builder, loc, "container", containerType);
|
|
Value callee0 = block->getArgument(0);
|
|
Value callee1 = block->getArgument(1);
|
|
Value argVal = block->getArgument(2);
|
|
|
|
// Indirect call with one argument and arg_attrs
|
|
auto callOp = fir::CallOp::create(builder, loc, SymbolRefAttr{},
|
|
llvm::ArrayRef<mlir::Type>{}, ValueRange{callee0, argVal});
|
|
callOp->setAttr(callOp.getArgAttrsAttrName(),
|
|
makeArgAttrs(&context,
|
|
{DictionaryAttr::get(&context, {}),
|
|
makeTestArgDict(&context, "arg0")}));
|
|
ASSERT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
|
|
// Switch to other indirect callee
|
|
callOp.setCalleeFromCallable(callee1);
|
|
|
|
EXPECT_TRUE(isValue(callOp.getCallableForCallee()));
|
|
EXPECT_EQ(callOp.getNumOperands(), 2u);
|
|
EXPECT_EQ(callOp.getOperand(0), callee1);
|
|
EXPECT_EQ(callOp.getOperand(1), argVal);
|
|
ArrayAttr argAttrs = callOp.getArgAttrsAttr();
|
|
ASSERT_TRUE(argAttrs);
|
|
ASSERT_EQ(argAttrs.size(), 2u);
|
|
EXPECT_TRUE(llvm::cast<DictionaryAttr>(argAttrs[0]).empty());
|
|
EXPECT_EQ(llvm::cast<DictionaryAttr>(argAttrs[1]).get("test.attr"),
|
|
StringAttr::get(&context, "arg0"));
|
|
}
|