[Mlir-commits] [flang] [mlir] [MLIR][OpenMP] Fix type mismatch in linear clause for INTEGER(8) variables (PR #173982)
Krish Gupta
llvmlistbot at llvm.org
Fri Jan 2 02:24:52 PST 2026
https://github.com/KrxGu updated https://github.com/llvm/llvm-project/pull/173982
>From 8033c9e3776036373cb36f7fb1c86a7b0b05eeef Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Tue, 30 Dec 2025 17:56:00 +0530
Subject: [PATCH 1/6] [MLIR][OpenMP] Fix type mismatch in linear clause with
INTEGER(8) variables
Fixes #173332 where compiling OpenMP parallel do simd with a linear
clause on INTEGER(8) variables crashed with assertion failure. The
issue was in MLIR-to-LLVM translation where step and induction variable
types weren't normalized to the linear variable's type before arithmetic
operations.
The fix ensures all mul/add operations use consistent types by casting
both the induction variable and step to match linearVarTypes[index].
---
.../OpenMP/linear-i8-issue-173332.f90 | 20 ++++
.../OpenMP/parallel-do-simd-linear-i8.f90 | 93 +++++++++++++++++++
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 44 +++++++--
3 files changed, 147 insertions(+), 10 deletions(-)
create mode 100644 flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
create mode 100644 flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
diff --git a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
new file mode 100644
index 0000000000000..f2abf71cdb01f
--- /dev/null
+++ b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
@@ -0,0 +1,20 @@
+! Integration test to verify INTEGER(8) linear clause compiles successfully
+! This is a regression test for issue #173332
+! RUN: %flang_fc1 -fopenmp -emit-llvm %s -o - | FileCheck %s
+
+! CHECK-LABEL: define {{.*}} @_QPrepro_issue_173332
+subroutine repro_issue_173332
+ implicit none
+ integer(8) :: i, j
+
+ ! This used to fail with:
+ ! "Cannot create binary operator with two operands of differing type!"
+ ! The fix ensures all arithmetic is normalized to the linear variable's type (i64)
+ !$omp parallel do simd linear(j)
+ do i = 1,100,1
+ end do
+ !$omp end parallel do simd
+ ! CHECK: ret void
+ ! Verify that linear variable updates use consistent types (should see sext/trunc for type normalization)
+ ! CHECK: {{sext|trunc|mul i64}}
+end subroutine repro_issue_173332
diff --git a/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90 b/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
new file mode 100644
index 0000000000000..45f2c6bc5fae3
--- /dev/null
+++ b/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
@@ -0,0 +1,93 @@
+! Test lowering of OpenMP parallel do simd with linear clause on INTEGER(8) variable
+! This is a regression test for issue #173332
+! At MLIR level, the step type may differ from the variable type - this is legal and handled during translation
+
+! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s
+
+! CHECK-LABEL: func @_QPtest_linear_i8
+subroutine test_linear_i8
+ implicit none
+ integer(8) :: i, j
+
+ ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_linear_i8Ej"}
+ ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+ ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK: omp.parallel
+ ! CHECK: omp.wsloop
+ ! CHECK-SAME: linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
+ !$omp parallel do simd linear(j)
+ do i = 1,100,1
+ end do
+ !$omp end parallel do simd
+ ! CHECK: } {linear_var_types = [i64]}
+end subroutine
+
+! CHECK-LABEL: func @_QPtest_linear_i8_with_step
+subroutine test_linear_i8_with_step
+ implicit none
+ integer(8) :: i, j
+
+ ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_linear_i8_with_stepEj"}
+ ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_linear_i8_with_stepEj"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+ ! Step may be i32 at MLIR level - translation will handle type normalization
+ ! CHECK: omp.parallel
+ ! CHECK: omp.wsloop
+ ! CHECK-SAME: linear(%[[J]]#0 = {{.*}} : !fir.ref<i64>)
+ !$omp parallel do simd linear(j:2)
+ do i = 1,100,1
+ end do
+ !$omp end parallel do simd
+ ! CHECK: } {linear_var_types = [i64]}
+end subroutine
+
+! CHECK-LABEL: func @_QPtest_simd_linear_i8
+subroutine test_simd_linear_i8
+ implicit none
+ integer(8) :: i, j
+
+ ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_simd_linear_i8Ej"}
+ ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_simd_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+ ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
+ !$omp simd linear(j)
+ do i = 1,100,1
+ end do
+ !$omp end simd
+ ! CHECK: } {linear_var_types = [i64]}
+end subroutine
+
+! CHECK-LABEL: func @_QPtest_do_linear_i8
+subroutine test_do_linear_i8
+ implicit none
+ integer(8) :: i, j
+
+ ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_do_linear_i8Ej"}
+ ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_do_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
+ ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK: omp.wsloop linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
+ !$omp do linear(j)
+ do i = 1,100,1
+ end do
+ !$omp end do
+ ! CHECK: } {linear_var_types = [i64]}
+end subroutine
+
+! Test with multiple INTEGER(8) linear variables
+! CHECK-LABEL: func @_QPtest_multiple_i8
+subroutine test_multiple_i8
+ implicit none
+ integer(8) :: i, j, k
+
+ ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j"
+ ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]]
+ ! CHECK: %[[K_alloca:.*]] = fir.alloca i64 {bindc_name = "k"
+ ! CHECK: %[[K:.*]]:2 = hlfir.declare %[[K_alloca]]
+ ! CHECK: %[[STEP_J:.*]] = arith.constant 1 : i64
+ ! CHECK: %[[STEP_K:.*]] = arith.constant 1 : i64
+ ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP_J]] : !fir.ref<i64>, %[[K]]#0 = %[[STEP_K]] : !fir.ref<i64>)
+ !$omp simd linear(j,k)
+ do i = 1,100,1
+ end do
+ !$omp end simd
+ ! CHECK: } {linear_var_types = [i64, i64]}
+end subroutine
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 03d67a52853f6..693bf5fe88b9d 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -187,17 +187,41 @@ class LinearClauseProcessor {
llvm::Value *loopInductionVar) {
builder.SetInsertPoint(loopBody->getTerminator());
for (size_t index = 0; index < linearPreconditionVars.size(); index++) {
- // Emit increments for linear vars
- llvm::LoadInst *linearVarStart = builder.CreateLoad(
- linearVarTypes[index], linearPreconditionVars[index]);
- auto mulInst = builder.CreateMul(loopInductionVar, linearSteps[index]);
- if (linearVarTypes[index]->isIntegerTy()) {
- auto addInst = builder.CreateAdd(linearVarStart, mulInst);
- builder.CreateStore(addInst, linearLoopBodyTemps[index]);
- } else if (linearVarTypes[index]->isFloatingPointTy()) {
- auto cvt = builder.CreateSIToFP(mulInst, linearVarTypes[index]);
- auto addInst = builder.CreateFAdd(linearVarStart, cvt);
+ llvm::Type *linearVarType = linearVarTypes[index];
+ llvm::Value *iv = loopInductionVar;
+ llvm::Value *step = linearSteps[index];
+
+ // Helper to cast signed integers with sign extension or truncation
+ auto castSignedInt = [&](llvm::Value *val,
+ llvm::Type *targetType) -> llvm::Value * {
+ if (val->getType() == targetType)
+ return val;
+ return builder.CreateSExtOrTrunc(val, targetType);
+ };
+
+ if (linearVarType->isIntegerTy()) {
+ // Integer path: normalize all arithmetic to linearVarType
+ iv = castSignedInt(iv, linearVarType);
+ step = castSignedInt(step, linearVarType);
+
+ llvm::LoadInst *linearVarStart =
+ builder.CreateLoad(linearVarType, linearPreconditionVars[index]);
+ llvm::Value *mulInst = builder.CreateMul(iv, step);
+ llvm::Value *addInst = builder.CreateAdd(linearVarStart, mulInst);
builder.CreateStore(addInst, linearLoopBodyTemps[index]);
+ } else if (linearVarType->isFloatingPointTy()) {
+ // Float path: perform multiply in integer, then convert to float
+ llvm::Type *ivType = iv->getType();
+ if (ivType->isIntegerTy()) {
+ step = castSignedInt(step, ivType);
+ llvm::Value *mulInst = builder.CreateMul(iv, step);
+
+ llvm::LoadInst *linearVarStart =
+ builder.CreateLoad(linearVarType, linearPreconditionVars[index]);
+ llvm::Value *mulFp = builder.CreateSIToFP(mulInst, linearVarType);
+ llvm::Value *addInst = builder.CreateFAdd(linearVarStart, mulFp);
+ builder.CreateStore(addInst, linearLoopBodyTemps[index]);
+ }
}
}
}
>From be1d87da3dd3b198a09e8cdcbfd3ba1a9014e22b Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Tue, 30 Dec 2025 18:34:10 +0530
Subject: [PATCH 2/6] Address review feedback and fix test patterns
- Add error handling for invalid linear variable types
- Fix FileCheck patterns to use func.func instead of func
- Simplify test expectations to be more robust
- Use CHECK-DAG where order doesn't matter
---
.../OpenMP/linear-i8-issue-173332.f90 | 7 ++-
.../OpenMP/parallel-do-simd-linear-i8.f90 | 52 +++++++------------
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 24 +++++----
3 files changed, 36 insertions(+), 47 deletions(-)
diff --git a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
index f2abf71cdb01f..fdcef1dc24860 100644
--- a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
+++ b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
@@ -2,7 +2,6 @@
! This is a regression test for issue #173332
! RUN: %flang_fc1 -fopenmp -emit-llvm %s -o - | FileCheck %s
-! CHECK-LABEL: define {{.*}} @_QPrepro_issue_173332
subroutine repro_issue_173332
implicit none
integer(8) :: i, j
@@ -14,7 +13,7 @@ subroutine repro_issue_173332
do i = 1,100,1
end do
!$omp end parallel do simd
- ! CHECK: ret void
- ! Verify that linear variable updates use consistent types (should see sext/trunc for type normalization)
- ! CHECK: {{sext|trunc|mul i64}}
end subroutine repro_issue_173332
+
+! CHECK-LABEL: define {{.*}} @_QPrepro_issue_173332
+! CHECK: ret void
diff --git a/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90 b/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
index 45f2c6bc5fae3..9449efb38cd18 100644
--- a/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
+++ b/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
@@ -4,90 +4,76 @@
! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s
-! CHECK-LABEL: func @_QPtest_linear_i8
+! CHECK-LABEL: func.func @_QPtest_linear_i8
subroutine test_linear_i8
implicit none
integer(8) :: i, j
- ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_linear_i8Ej"}
- ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
- ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
- ! CHECK: omp.parallel
+ ! CHECK-DAG: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j"
+ ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]]
+ ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
! CHECK: omp.wsloop
- ! CHECK-SAME: linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
+ ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
!$omp parallel do simd linear(j)
do i = 1,100,1
end do
!$omp end parallel do simd
- ! CHECK: } {linear_var_types = [i64]}
end subroutine
-! CHECK-LABEL: func @_QPtest_linear_i8_with_step
+! CHECK-LABEL: func.func @_QPtest_linear_i8_with_step
subroutine test_linear_i8_with_step
implicit none
integer(8) :: i, j
- ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_linear_i8_with_stepEj"}
- ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_linear_i8_with_stepEj"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
- ! Step may be i32 at MLIR level - translation will handle type normalization
- ! CHECK: omp.parallel
+ ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_linear_i8_with_stepEj"}
! CHECK: omp.wsloop
- ! CHECK-SAME: linear(%[[J]]#0 = {{.*}} : !fir.ref<i64>)
+ ! CHECK: omp.simd linear(%[[J]]#0 = {{.*}} : !fir.ref<i64>)
!$omp parallel do simd linear(j:2)
do i = 1,100,1
end do
!$omp end parallel do simd
- ! CHECK: } {linear_var_types = [i64]}
end subroutine
-! CHECK-LABEL: func @_QPtest_simd_linear_i8
+! CHECK-LABEL: func.func @_QPtest_simd_linear_i8
subroutine test_simd_linear_i8
implicit none
integer(8) :: i, j
- ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_simd_linear_i8Ej"}
- ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_simd_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
- ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_simd_linear_i8Ej"}
+ ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
!$omp simd linear(j)
do i = 1,100,1
end do
!$omp end simd
- ! CHECK: } {linear_var_types = [i64]}
end subroutine
-! CHECK-LABEL: func @_QPtest_do_linear_i8
+! CHECK-LABEL: func.func @_QPtest_do_linear_i8
subroutine test_do_linear_i8
implicit none
integer(8) :: i, j
- ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j", uniq_name = "_QFtest_do_linear_i8Ej"}
- ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]] {uniq_name = "_QFtest_do_linear_i8Ej"} : (!fir.ref<i64>) -> (!fir.ref<i64>, !fir.ref<i64>)
- ! CHECK: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_do_linear_i8Ej"}
+ ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
! CHECK: omp.wsloop linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
!$omp do linear(j)
do i = 1,100,1
end do
!$omp end do
- ! CHECK: } {linear_var_types = [i64]}
end subroutine
! Test with multiple INTEGER(8) linear variables
-! CHECK-LABEL: func @_QPtest_multiple_i8
+! CHECK-LABEL: func.func @_QPtest_multiple_i8
subroutine test_multiple_i8
implicit none
integer(8) :: i, j, k
- ! CHECK: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j"
- ! CHECK: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]]
- ! CHECK: %[[K_alloca:.*]] = fir.alloca i64 {bindc_name = "k"
- ! CHECK: %[[K:.*]]:2 = hlfir.declare %[[K_alloca]]
- ! CHECK: %[[STEP_J:.*]] = arith.constant 1 : i64
- ! CHECK: %[[STEP_K:.*]] = arith.constant 1 : i64
- ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP_J]] : !fir.ref<i64>, %[[K]]#0 = %[[STEP_K]] : !fir.ref<i64>)
+ ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_multiple_i8Ej"}
+ ! CHECK-DAG: %[[K:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_multiple_i8Ek"}
+ ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
+ ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>, %[[K]]#0 = %[[STEP]] : !fir.ref<i64>)
!$omp simd linear(j,k)
do i = 1,100,1
end do
!$omp end simd
- ! CHECK: } {linear_var_types = [i64, i64]}
end subroutine
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 693bf5fe88b9d..643f0a0027350 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -212,16 +212,20 @@ class LinearClauseProcessor {
} else if (linearVarType->isFloatingPointTy()) {
// Float path: perform multiply in integer, then convert to float
llvm::Type *ivType = iv->getType();
- if (ivType->isIntegerTy()) {
- step = castSignedInt(step, ivType);
- llvm::Value *mulInst = builder.CreateMul(iv, step);
-
- llvm::LoadInst *linearVarStart =
- builder.CreateLoad(linearVarType, linearPreconditionVars[index]);
- llvm::Value *mulFp = builder.CreateSIToFP(mulInst, linearVarType);
- llvm::Value *addInst = builder.CreateFAdd(linearVarStart, mulFp);
- builder.CreateStore(addInst, linearLoopBodyTemps[index]);
- }
+ if (!ivType->isIntegerTy())
+ llvm_unreachable("OpenMP loop induction variable must be an integer "
+ "type when updating floating-point linear vars");
+ step = castSignedInt(step, ivType);
+ llvm::Value *mulInst = builder.CreateMul(iv, step);
+
+ llvm::LoadInst *linearVarStart =
+ builder.CreateLoad(linearVarType, linearPreconditionVars[index]);
+ llvm::Value *mulFp = builder.CreateSIToFP(mulInst, linearVarType);
+ llvm::Value *addInst = builder.CreateFAdd(linearVarStart, mulFp);
+ builder.CreateStore(addInst, linearLoopBodyTemps[index]);
+ } else {
+ llvm_unreachable(
+ "Linear variable must be of integer or floating-point type");
}
}
}
>From 8091494ea9c310f89ff5f3540dfb354891fdcc5a Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Tue, 30 Dec 2025 18:54:06 +0530
Subject: [PATCH 3/6] Fix integration test to prevent dead code elimination
- Initialize variable j and use it in the loop body
- Update CHECK-LABEL to match actual function name (repro_issue_173332_)
- Ensures the compiler generates IR for the test case
---
flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 | 4 +++-
1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
index fdcef1dc24860..f8bafbcbc5a49 100644
--- a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
+++ b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
@@ -6,14 +6,16 @@ subroutine repro_issue_173332
implicit none
integer(8) :: i, j
+ j = 0
! This used to fail with:
! "Cannot create binary operator with two operands of differing type!"
! The fix ensures all arithmetic is normalized to the linear variable's type (i64)
!$omp parallel do simd linear(j)
do i = 1,100,1
+ j = j + 1
end do
!$omp end parallel do simd
end subroutine repro_issue_173332
-! CHECK-LABEL: define {{.*}} @_QPrepro_issue_173332
+! CHECK-LABEL: define {{.*}} @repro_issue_173332_
! CHECK: ret void
>From 65faa1831135bc99492749c3d6fd277b35f7a101 Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Thu, 1 Jan 2026 02:07:06 +0530
Subject: [PATCH 4/6] Address reviewer feedback
- Remove unnecessary helper lambda (CreateSExtOrTrunc already handles same-type case)
- Move integer type check outside if-else for consistency across both paths
---
.../OpenMP/OpenMPToLLVMIRTranslation.cpp | 20 ++++++-------------
1 file changed, 6 insertions(+), 14 deletions(-)
diff --git a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
index 643f0a0027350..66c596a3c739a 100644
--- a/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp
@@ -191,18 +191,14 @@ class LinearClauseProcessor {
llvm::Value *iv = loopInductionVar;
llvm::Value *step = linearSteps[index];
- // Helper to cast signed integers with sign extension or truncation
- auto castSignedInt = [&](llvm::Value *val,
- llvm::Type *targetType) -> llvm::Value * {
- if (val->getType() == targetType)
- return val;
- return builder.CreateSExtOrTrunc(val, targetType);
- };
+ if (!iv->getType()->isIntegerTy())
+ llvm_unreachable("OpenMP loop induction variable must be an integer "
+ "type");
if (linearVarType->isIntegerTy()) {
// Integer path: normalize all arithmetic to linearVarType
- iv = castSignedInt(iv, linearVarType);
- step = castSignedInt(step, linearVarType);
+ iv = builder.CreateSExtOrTrunc(iv, linearVarType);
+ step = builder.CreateSExtOrTrunc(step, linearVarType);
llvm::LoadInst *linearVarStart =
builder.CreateLoad(linearVarType, linearPreconditionVars[index]);
@@ -211,11 +207,7 @@ class LinearClauseProcessor {
builder.CreateStore(addInst, linearLoopBodyTemps[index]);
} else if (linearVarType->isFloatingPointTy()) {
// Float path: perform multiply in integer, then convert to float
- llvm::Type *ivType = iv->getType();
- if (!ivType->isIntegerTy())
- llvm_unreachable("OpenMP loop induction variable must be an integer "
- "type when updating floating-point linear vars");
- step = castSignedInt(step, ivType);
+ step = builder.CreateSExtOrTrunc(step, iv->getType());
llvm::Value *mulInst = builder.CreateMul(iv, step);
llvm::LoadInst *linearVarStart =
>From 6de6646ba93134f0ffcdb67f5d7a7ea1c0a6052f Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Fri, 2 Jan 2026 00:07:12 +0530
Subject: [PATCH 5/6] Replace Fortran tests with direct MLIR translation test
- Remove flang integration and lowering tests per reviewer feedback
- Add MLIR test in openmp-llvm.mlir that directly tests the translation
- Test verifies i32 step with i64 linear variable generates correct sext
- Test confirms mul and add operations use consistent i64 types
Addresses review comments from NimishMishra and tblah
---
.../OpenMP/linear-i8-issue-173332.f90 | 21 -----
.../OpenMP/parallel-do-simd-linear-i8.f90 | 79 -------------------
mlir/test/Target/LLVMIR/openmp-llvm.mlir | 32 ++++++++
3 files changed, 32 insertions(+), 100 deletions(-)
delete mode 100644 flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
delete mode 100644 flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
diff --git a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 b/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
deleted file mode 100644
index f8bafbcbc5a49..0000000000000
--- a/flang/test/Integration/OpenMP/linear-i8-issue-173332.f90
+++ /dev/null
@@ -1,21 +0,0 @@
-! Integration test to verify INTEGER(8) linear clause compiles successfully
-! This is a regression test for issue #173332
-! RUN: %flang_fc1 -fopenmp -emit-llvm %s -o - | FileCheck %s
-
-subroutine repro_issue_173332
- implicit none
- integer(8) :: i, j
-
- j = 0
- ! This used to fail with:
- ! "Cannot create binary operator with two operands of differing type!"
- ! The fix ensures all arithmetic is normalized to the linear variable's type (i64)
- !$omp parallel do simd linear(j)
- do i = 1,100,1
- j = j + 1
- end do
- !$omp end parallel do simd
-end subroutine repro_issue_173332
-
-! CHECK-LABEL: define {{.*}} @repro_issue_173332_
-! CHECK: ret void
diff --git a/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90 b/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
deleted file mode 100644
index 9449efb38cd18..0000000000000
--- a/flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90
+++ /dev/null
@@ -1,79 +0,0 @@
-! Test lowering of OpenMP parallel do simd with linear clause on INTEGER(8) variable
-! This is a regression test for issue #173332
-! At MLIR level, the step type may differ from the variable type - this is legal and handled during translation
-
-! RUN: %flang_fc1 -fopenmp -emit-hlfir %s -o - 2>&1 | FileCheck %s
-
-! CHECK-LABEL: func.func @_QPtest_linear_i8
-subroutine test_linear_i8
- implicit none
- integer(8) :: i, j
-
- ! CHECK-DAG: %[[J_alloca:.*]] = fir.alloca i64 {bindc_name = "j"
- ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare %[[J_alloca]]
- ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
- ! CHECK: omp.wsloop
- ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
- !$omp parallel do simd linear(j)
- do i = 1,100,1
- end do
- !$omp end parallel do simd
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtest_linear_i8_with_step
-subroutine test_linear_i8_with_step
- implicit none
- integer(8) :: i, j
-
- ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_linear_i8_with_stepEj"}
- ! CHECK: omp.wsloop
- ! CHECK: omp.simd linear(%[[J]]#0 = {{.*}} : !fir.ref<i64>)
- !$omp parallel do simd linear(j:2)
- do i = 1,100,1
- end do
- !$omp end parallel do simd
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtest_simd_linear_i8
-subroutine test_simd_linear_i8
- implicit none
- integer(8) :: i, j
-
- ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_simd_linear_i8Ej"}
- ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
- ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
- !$omp simd linear(j)
- do i = 1,100,1
- end do
- !$omp end simd
-end subroutine
-
-! CHECK-LABEL: func.func @_QPtest_do_linear_i8
-subroutine test_do_linear_i8
- implicit none
- integer(8) :: i, j
-
- ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_do_linear_i8Ej"}
- ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
- ! CHECK: omp.wsloop linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>)
- !$omp do linear(j)
- do i = 1,100,1
- end do
- !$omp end do
-end subroutine
-
-! Test with multiple INTEGER(8) linear variables
-! CHECK-LABEL: func.func @_QPtest_multiple_i8
-subroutine test_multiple_i8
- implicit none
- integer(8) :: i, j, k
-
- ! CHECK-DAG: %[[J:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_multiple_i8Ej"}
- ! CHECK-DAG: %[[K:.*]]:2 = hlfir.declare {{.*}} {uniq_name = "_QFtest_multiple_i8Ek"}
- ! CHECK-DAG: %[[STEP:.*]] = arith.constant 1 : i32
- ! CHECK: omp.simd linear(%[[J]]#0 = %[[STEP]] : !fir.ref<i64>, %[[K]]#0 = %[[STEP]] : !fir.ref<i64>)
- !$omp simd linear(j,k)
- do i = 1,100,1
- end do
- !$omp end simd
-end subroutine
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 1eb501ca02703..8da8c73192c0e 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -769,6 +769,38 @@ llvm.func @simd_linear(%lb : i32, %ub : i32, %step : i32, %x : !llvm.ptr) {
// -----
+// Test linear clause with mismatched types (i32 step, i64 variable)
+// This is a regression test for issue #173332
+llvm.func @simd_linear_i64_var_i32_step(%lb : i32, %ub : i32, %x : !llvm.ptr) {
+ %step = llvm.mlir.constant(1 : i32) : i32
+
+// CHECK-LABEL: @simd_linear_i64_var_i32_step
+
+// CHECK: %[[LINEAR_VAR:.*]] = alloca i64
+// CHECK: %[[LINEAR_RESULT:.*]] = alloca i64
+
+// CHECK: omp_loop.preheader:
+// CHECK: %[[LOAD:.*]] = load i64, ptr {{.*}}
+// CHECK: store i64 %[[LOAD]], ptr %[[LINEAR_VAR]]
+
+// CHECK: omp_loop.body:
+// Verify type conversions: iv (i32) is extended to i64 before multiplication
+// CHECK: %[[IV_I64:.*]] = sext i32 %omp_loop.iv to i64
+// CHECK: %[[LOAD:.*]] = load i64, ptr %[[LINEAR_VAR]], {{.*}}!llvm.access.group
+// Verify multiplication and addition use consistent i64 types
+// CHECK: %[[MUL:.*]] = mul i64 %[[IV_I64]], {{.*}}
+// CHECK: %[[ADD:.*]] = add i64 %[[LOAD]], %[[MUL]]
+// CHECK: store i64 %[[ADD]], ptr %[[LINEAR_RESULT]], {{.*}}!llvm.access.group
+ omp.simd linear(%x = %step : !llvm.ptr) {
+ omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [i64]}
+ llvm.return
+}
+
+// -----
+
// CHECK-LABEL: @simd_simple_multiple
llvm.func @simd_simple_multiple(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
omp.simd {
>From eacad01bac70ae92489b60aee66016e99a3bda8a Mon Sep 17 00:00:00 2001
From: KrxGu <krishom70 at gmail.com>
Date: Fri, 2 Jan 2026 15:54:29 +0530
Subject: [PATCH 6/6] Add test for floating-point linear variables in SIMD
loops
Per reviewer feedback from NimishMishra, added test case for the
floating-point path in updateLinearVar to verify that i32 step values
are correctly handled with f64 linear variables.
---
mlir/test/Target/LLVMIR/openmp-llvm.mlir | 32 ++++++++++++++++++++++++
1 file changed, 32 insertions(+)
diff --git a/mlir/test/Target/LLVMIR/openmp-llvm.mlir b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
index 8da8c73192c0e..6011dc6604478 100644
--- a/mlir/test/Target/LLVMIR/openmp-llvm.mlir
+++ b/mlir/test/Target/LLVMIR/openmp-llvm.mlir
@@ -801,6 +801,38 @@ llvm.func @simd_linear_i64_var_i32_step(%lb : i32, %ub : i32, %x : !llvm.ptr) {
// -----
+// Test linear clause with floating-point variable and i32 step
+// This tests the floating-point path in updateLinearVar
+llvm.func @simd_linear_f64_var_i32_step(%lb : i32, %ub : i32, %x : !llvm.ptr) {
+ %step = llvm.mlir.constant(1 : i32) : i32
+
+// CHECK-LABEL: @simd_linear_f64_var_i32_step
+
+// CHECK: %[[LINEAR_VAR:.*]] = alloca double
+// CHECK: %[[LINEAR_RESULT:.*]] = alloca double
+
+// CHECK: omp_loop.preheader:
+// CHECK: %[[LOAD:.*]] = load double, ptr {{.*}}
+// CHECK: store double %[[LOAD]], ptr %[[LINEAR_VAR]]
+
+// CHECK: omp_loop.body:
+// Verify integer multiplication, load, and conversion to float
+// CHECK: mul i32 %omp_loop.iv
+// CHECK: %[[MUL_INT:.*]] = mul i32 %omp_loop.iv, {{.*}}
+// CHECK-NEXT: %[[LOAD:.*]] = load double, ptr %[[LINEAR_VAR]], {{.*}}!llvm.access.group
+// CHECK-NEXT: %[[MUL_FP:.*]] = sitofp i32 %[[MUL_INT]] to double
+// CHECK-NEXT: %[[ADD:.*]] = fadd double %[[LOAD]], %[[MUL_FP]]
+// CHECK-NEXT: store double %[[ADD]], ptr %[[LINEAR_RESULT]], {{.*}}!llvm.access.group
+ omp.simd linear(%x = %step : !llvm.ptr) {
+ omp.loop_nest (%iv) : i32 = (%lb) to (%ub) step (%step) {
+ omp.yield
+ }
+ } {linear_var_types = [f64]}
+ llvm.return
+}
+
+// -----
+
// CHECK-LABEL: @simd_simple_multiple
llvm.func @simd_simple_multiple(%lb1 : i64, %ub1 : i64, %step1 : i64, %lb2 : i64, %ub2 : i64, %step2 : i64, %arg0: !llvm.ptr, %arg1: !llvm.ptr) {
omp.simd {
More information about the Mlir-commits
mailing list