[flang-commits] [flang] [mlir] [MLIR][OpenMP] Fix type mismatch in linear clause for INTEGER(8) variables (PR #173982)

via flang-commits flang-commits at lists.llvm.org
Tue Dec 30 04:29:39 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir

Author: Krish Gupta (KrxGu)

<details>
<summary>Changes</summary>

Fixes #<!-- -->173332 

The compiler was crashing when compiling OpenMP `parallel do simd` with a `linear` clause on `INTEGER(8)` variables. The assertion failure occurred during MLIR-to-LLVM translation:
Cannot create binary operator with two operands of differing type!

**Root Cause:**
The bug was in `LinearClauseProcessor::updateLinearVar()` where the step value (i32) and induction variable were multiplied without normalizing to the linear variable's type (i64), causing type mismatches in LLVM IR generation.

**Solution:**
Updated the translation logic to cast both the induction variable and step value to `linearVarTypes[index]` before performing arithmetic operations. This ensures type consistency for both integer and floating-point linear variables.

**Testing:**
- Added integration test verifying successful compilation to LLVM IR
- Added lowering test for MLIR generation with various linear clause forms
- Verified the exact reproducer from the issue now compiles without errors

---
Full diff: https://github.com/llvm/llvm-project/pull/173982.diff


3 Files Affected:

- (added) flang/test/Integration/OpenMP/linear-i8-issue-173332.f90 (+20) 
- (added) flang/test/Lower/OpenMP/parallel-do-simd-linear-i8.f90 (+93) 
- (modified) mlir/lib/Target/LLVMIR/Dialect/OpenMP/OpenMPToLLVMIRTranslation.cpp (+34-10) 


``````````diff
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]);
+        }
       }
     }
   }

``````````

</details>


https://github.com/llvm/llvm-project/pull/173982


More information about the flang-commits mailing list