Skip to content

Commit 6f489fb

Browse files
authored
Reapply "[flang] Lower EOSHIFT into hlfir.eoshift." (llvm#153907) (llvm#154241)
This reverts commit 5178aef. In addition: * Scalar constant UNSIGNED BOUNDARY is explicitly casted to the result type so that the generated hlfir.eoshift operation is valid. The lowering produces signless constants by default. It might be a bigger issue in lowering, so I just want to "fix" it for EOSHIFT in this patch. * Since we have to create unsigned integer constant during HLFIR inlining, I added code in createIntegerConstant to make it possible.
1 parent c79a88e commit 6f489fb

File tree

4 files changed

+366
-2
lines changed

4 files changed

+366
-2
lines changed

flang/lib/Lower/HlfirIntrinsics.cpp

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,17 @@ class HlfirCShiftLowering : public HlfirTransformationalIntrinsic {
170170
mlir::Type stmtResultType) override;
171171
};
172172

173+
class HlfirEOShiftLowering : public HlfirTransformationalIntrinsic {
174+
public:
175+
using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
176+
177+
protected:
178+
mlir::Value
179+
lowerImpl(const Fortran::lower::PreparedActualArguments &loweredActuals,
180+
const fir::IntrinsicArgumentLoweringRules *argLowering,
181+
mlir::Type stmtResultType) override;
182+
};
183+
173184
class HlfirReshapeLowering : public HlfirTransformationalIntrinsic {
174185
public:
175186
using HlfirTransformationalIntrinsic::HlfirTransformationalIntrinsic;
@@ -430,6 +441,46 @@ mlir::Value HlfirCShiftLowering::lowerImpl(
430441
return createOp<hlfir::CShiftOp>(resultType, operands);
431442
}
432443

444+
mlir::Value HlfirEOShiftLowering::lowerImpl(
445+
const Fortran::lower::PreparedActualArguments &loweredActuals,
446+
const fir::IntrinsicArgumentLoweringRules *argLowering,
447+
mlir::Type stmtResultType) {
448+
auto operands = getOperandVector(loweredActuals, argLowering);
449+
assert(operands.size() == 4);
450+
mlir::Value array = operands[0];
451+
mlir::Value shift = operands[1];
452+
mlir::Value boundary = operands[2];
453+
mlir::Value dim = operands[3];
454+
// If DIM is present, then dereference it if it is a ref.
455+
if (dim)
456+
dim = hlfir::loadTrivialScalar(loc, builder, hlfir::Entity{dim});
457+
458+
mlir::Type resultType = computeResultType(array, stmtResultType);
459+
460+
if (boundary && fir::isa_trivial(boundary.getType())) {
461+
mlir::Type elementType = hlfir::getFortranElementType(resultType);
462+
if (auto logicalTy = mlir::dyn_cast<fir::LogicalType>(elementType)) {
463+
// Scalar logical constant boundary might be represented using i1, i2, ...
464+
// type. We need to cast it to fir.logical type of the ARRAY/result.
465+
if (boundary.getType() != logicalTy)
466+
boundary = builder.createConvert(loc, logicalTy, boundary);
467+
} else {
468+
// When the boundary is a constant like '1u', the lowering converts
469+
// it into a signless arith.constant value (which is a requirement
470+
// of the Arith dialect). If the ARRAY/RESULT is also UNSIGNED,
471+
// we have to cast the boundary to the same unsigned type.
472+
auto resultIntTy = mlir::dyn_cast<mlir::IntegerType>(elementType);
473+
auto boundaryIntTy =
474+
mlir::dyn_cast<mlir::IntegerType>(boundary.getType());
475+
if (resultIntTy && boundaryIntTy &&
476+
resultIntTy.getSignedness() != boundaryIntTy.getSignedness())
477+
boundary = builder.createConvert(loc, resultIntTy, boundary);
478+
}
479+
}
480+
481+
return createOp<hlfir::EOShiftOp>(resultType, array, shift, boundary, dim);
482+
}
483+
433484
mlir::Value HlfirReshapeLowering::lowerImpl(
434485
const Fortran::lower::PreparedActualArguments &loweredActuals,
435486
const fir::IntrinsicArgumentLoweringRules *argLowering,
@@ -489,6 +540,9 @@ std::optional<hlfir::EntityWithAttributes> Fortran::lower::lowerHlfirIntrinsic(
489540
if (name == "cshift")
490541
return HlfirCShiftLowering{builder, loc}.lower(loweredActuals, argLowering,
491542
stmtResultType);
543+
if (name == "eoshift")
544+
return HlfirEOShiftLowering{builder, loc}.lower(loweredActuals, argLowering,
545+
stmtResultType);
492546
if (name == "reshape")
493547
return HlfirReshapeLowering{builder, loc}.lower(loweredActuals, argLowering,
494548
stmtResultType);

flang/lib/Optimizer/Builder/FIRBuilder.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,8 +147,20 @@ mlir::Value fir::FirOpBuilder::createIntegerConstant(mlir::Location loc,
147147
assert((cst >= 0 || mlir::isa<mlir::IndexType>(ty) ||
148148
mlir::cast<mlir::IntegerType>(ty).getWidth() <= 64) &&
149149
"must use APint");
150-
return mlir::arith::ConstantOp::create(*this, loc, ty,
151-
getIntegerAttr(ty, cst));
150+
151+
mlir::Type cstType = ty;
152+
if (auto intType = mlir::dyn_cast<mlir::IntegerType>(ty)) {
153+
// Signed and unsigned constants must be encoded as signless
154+
// arith.constant followed by fir.convert cast.
155+
if (intType.isUnsigned())
156+
cstType = mlir::IntegerType::get(getContext(), intType.getWidth());
157+
else if (intType.isSigned())
158+
TODO(loc, "signed integer constant");
159+
}
160+
161+
mlir::Value cstValue = mlir::arith::ConstantOp::create(
162+
*this, loc, cstType, getIntegerAttr(cstType, cst));
163+
return createConvert(loc, ty, cstValue);
152164
}
153165

154166
mlir::Value fir::FirOpBuilder::createAllOnesInteger(mlir::Location loc,

flang/test/HLFIR/simplify-hlfir-intrinsics-eoshift.fir

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,6 +697,33 @@ func.func @_QPeoshift7(%arg0: !fir.ref<i32> {fir.bindc_name = "n"}, %arg1: !fir.
697697
// CHECK: return
698698
// CHECK: }
699699

700+
// Test UNSIGNED data type.
701+
// The default value of the BOUNDARY must be an integer 0
702+
// converted to ui32 type.
703+
// subroutine eoshift8(array)
704+
// unsigned :: array(:,:)
705+
// array = EOSHIFT(array, shift=1, dim=2)
706+
// end subroutine
707+
func.func @_QPeoshift8(%arg0: !fir.box<!fir.array<?x?xui32>> {fir.bindc_name = "array"}) {
708+
%c2_i32 = arith.constant 2 : i32
709+
%c1_i32 = arith.constant 1 : i32
710+
%0 = fir.dummy_scope : !fir.dscope
711+
%1:2 = hlfir.declare %arg0 dummy_scope %0 {uniq_name = "_QFeoshift8Earray"} : (!fir.box<!fir.array<?x?xui32>>, !fir.dscope) -> (!fir.box<!fir.array<?x?xui32>>, !fir.box<!fir.array<?x?xui32>>)
712+
%2 = hlfir.eoshift %1#0 %c1_i32 dim %c2_i32 : (!fir.box<!fir.array<?x?xui32>>, i32, i32) -> !hlfir.expr<?x?xui32>
713+
hlfir.assign %2 to %1#0 : !hlfir.expr<?x?xui32>, !fir.box<!fir.array<?x?xui32>>
714+
hlfir.destroy %2 : !hlfir.expr<?x?xui32>
715+
return
716+
}
717+
// CHECK-LABEL: func.func @_QPeoshift8(
718+
// CHECK-DAG: hlfir.elemental %{{.*}} unordered : (!fir.shape<2>) -> !hlfir.expr<?x?xui32> {
719+
// CHECK-DAG: %[[VAL_24:.*]] = fir.load %{{.*}} : !fir.ref<ui32>
720+
// CHECK-DAG: fir.result %[[VAL_24]] : ui32
721+
// CHECK-DAG: } else {
722+
// CHECK-DAG: fir.result %[[VAL_12:.*]] : ui32
723+
// CHECK-DAG: }
724+
// CHECK-DAG: %[[VAL_12]] = fir.convert %[[VAL_1:.*]] : (i32) -> ui32
725+
// CHECK-DAG: %[[VAL_1]] = arith.constant 0 : i32
726+
700727
// ! Tests for CHARACTER type (lowered via hlfir.elemental).
701728

702729
// ! Test contiguous 1D array with statically absent boundary.

0 commit comments

Comments
 (0)