[flang-commits] [flang] [mlir] [MLIR][OpenMP] Fix type mismatch in linear clause for INTEGER(8) variables (PR #173982)
Krish Gupta via flang-commits
flang-commits at lists.llvm.org
Tue Dec 30 04:29:07 PST 2025
https://github.com/KrxGu created https://github.com/llvm/llvm-project/pull/173982
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
>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] [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]);
+ }
}
}
}
More information about the flang-commits
mailing list