summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVitaly Buka <vitalybuka@google.com>2024-04-10 15:09:22 -0700
committerVitaly Buka <vitalybuka@google.com>2024-04-10 15:09:22 -0700
commit3143c5bed137957d78daf72d3bbf26362d6291ac (patch)
tree11b1437a369425ee275622868c4d63a79bfda0c4
parent93133e271d02ed558a040469115315e8a66af4a5 (diff)
parent9f6d08f2566a26144ea1753f80aebb1f2ecfdc63 (diff)
Created using spr 1.3.4 [skip ci]
-rw-r--r--clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp2
-rw-r--r--clang-tools-extra/docs/ReleaseNotes.rst2
-rw-r--r--clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp23
-rw-r--r--clang/docs/HIPSupport.rst14
-rw-r--r--clang/docs/ReleaseNotes.rst6
-rw-r--r--clang/docs/tools/clang-formatted-files.txt4
-rw-r--r--clang/include/clang/AST/OpenACCClause.h38
-rw-r--r--clang/include/clang/AST/StmtOpenMP.h11
-rw-r--r--clang/include/clang/Basic/DiagnosticGroups.td3
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td14
-rw-r--r--clang/include/clang/Basic/OpenACCKinds.h24
-rw-r--r--clang/include/clang/Driver/Options.td5
-rw-r--r--clang/include/clang/Sema/Sema.h63
-rw-r--r--clang/include/clang/Sema/SemaOpenACC.h19
-rw-r--r--clang/include/clang/Sema/SemaSYCL.h65
-rw-r--r--clang/lib/AST/Interp/ByteCodeExprGen.cpp109
-rw-r--r--clang/lib/AST/Interp/ByteCodeStmtGen.cpp2
-rw-r--r--clang/lib/AST/Interp/Context.cpp3
-rw-r--r--clang/lib/AST/Interp/Descriptor.h1
-rw-r--r--clang/lib/AST/Interp/EvalEmitter.cpp3
-rw-r--r--clang/lib/AST/Interp/FunctionPointer.h10
-rw-r--r--clang/lib/AST/Interp/Interp.cpp5
-rw-r--r--clang/lib/AST/Interp/Interp.h85
-rw-r--r--clang/lib/AST/Interp/InterpBlock.cpp4
-rw-r--r--clang/lib/AST/Interp/InterpBuiltin.cpp46
-rw-r--r--clang/lib/AST/Interp/Opcodes.td12
-rw-r--r--clang/lib/AST/Interp/Pointer.cpp187
-rw-r--r--clang/lib/AST/Interp/Pointer.h383
-rw-r--r--clang/lib/AST/Interp/PrimType.h4
-rw-r--r--clang/lib/AST/Interp/Program.cpp7
-rw-r--r--clang/lib/AST/OpenACCClause.cpp19
-rw-r--r--clang/lib/AST/ParentMapContext.cpp25
-rw-r--r--clang/lib/AST/StmtOpenMP.cpp3
-rw-r--r--clang/lib/AST/StmtProfile.cpp5
-rw-r--r--clang/lib/AST/TextNodeDumper.cpp11
-rw-r--r--clang/lib/AST/TypePrinter.cpp9
-rw-r--r--clang/lib/Basic/Targets/AArch64.cpp5
-rw-r--r--clang/lib/CodeGen/CGCall.cpp6
-rw-r--r--clang/lib/CodeGen/CGCleanup.cpp12
-rw-r--r--clang/lib/CodeGen/CGCleanup.h57
-rw-r--r--clang/lib/CodeGen/CGDecl.cpp58
-rw-r--r--clang/lib/CodeGen/CGExpr.cpp12
-rw-r--r--clang/lib/CodeGen/CGExprAgg.cpp87
-rw-r--r--clang/lib/CodeGen/CGExprCXX.cpp38
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntime.cpp15
-rw-r--r--clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp7
-rw-r--r--clang/lib/CodeGen/CGStmtOpenMP.cpp87
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp6
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.h96
-rw-r--r--clang/lib/CodeGen/CodeGenModule.cpp8
-rw-r--r--clang/lib/CodeGen/Targets/X86.cpp5
-rw-r--r--clang/lib/Driver/ToolChains/AMDGPU.cpp4
-rw-r--r--clang/lib/Driver/ToolChains/Flang.cpp9
-rw-r--r--clang/lib/Format/TokenAnnotator.cpp3
-rw-r--r--clang/lib/Format/UnwrappedLineParser.cpp20
-rw-r--r--clang/lib/Headers/intrin.h2
-rw-r--r--clang/lib/Parse/ParseExpr.cpp5
-rw-r--r--clang/lib/Parse/ParseOpenACC.cpp14
-rw-r--r--clang/lib/Sema/Sema.cpp6
-rw-r--r--clang/lib/Sema/SemaChecking.cpp22
-rw-r--r--clang/lib/Sema/SemaDecl.cpp12
-rw-r--r--clang/lib/Sema/SemaExpr.cpp27
-rw-r--r--clang/lib/Sema/SemaExprCXX.cpp78
-rw-r--r--clang/lib/Sema/SemaExprMember.cpp42
-rw-r--r--clang/lib/Sema/SemaOpenACC.cpp65
-rw-r--r--clang/lib/Sema/SemaOpenMP.cpp86
-rw-r--r--clang/lib/Sema/SemaSYCL.cpp52
-rw-r--r--clang/lib/Sema/SemaTemplateInstantiateDecl.cpp8
-rw-r--r--clang/lib/Sema/SemaTemplateVariadic.cpp11
-rw-r--r--clang/lib/Sema/TreeTransform.h53
-rw-r--r--clang/lib/Serialization/ASTReader.cpp16
-rw-r--r--clang/lib/Serialization/ASTReaderStmt.cpp1
-rw-r--r--clang/lib/Serialization/ASTWriter.cpp28
-rw-r--r--clang/lib/Serialization/ASTWriterStmt.cpp1
-rw-r--r--clang/test/APINotes/instancetype.m1
-rw-r--r--clang/test/AST/Interp/builtin-functions.cpp120
-rw-r--r--clang/test/AST/Interp/c.c18
-rw-r--r--clang/test/AST/Interp/const-eval.c192
-rw-r--r--clang/test/AST/Interp/functions.cpp15
-rw-r--r--clang/test/AST/Interp/vectors.cpp22
-rw-r--r--clang/test/CodeGen/X86/x86_64-arguments.c18
-rw-r--r--clang/test/CodeGenCXX/arm64ec-vectorcall.cpp14
-rw-r--r--clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp364
-rw-r--r--clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp93
-rw-r--r--clang/test/Driver/amdgpu-features.c6
-rw-r--r--clang/test/Driver/linker-wrapper-libs.c4
-rw-r--r--clang/test/Driver/lld-repro.c8
-rw-r--r--clang/test/Modules/home-is-cwd-search-paths.c34
-rw-r--r--clang/test/OpenMP/nvptx_target_teams_generic_loop_codegen.cpp48
-rw-r--r--clang/test/OpenMP/nvptx_target_teams_generic_loop_generic_mode_codegen.cpp397
-rw-r--r--clang/test/OpenMP/target_teams_generic_loop_codegen.cpp1132
-rw-r--r--clang/test/OpenMP/target_teams_generic_loop_codegen_as_distribute.cpp587
-rw-r--r--clang/test/OpenMP/target_teams_generic_loop_codegen_as_parallel_for.cpp3998
-rw-r--r--clang/test/OpenMP/target_teams_generic_loop_if_codegen.cpp694
-rw-r--r--clang/test/OpenMP/target_teams_generic_loop_private_codegen.cpp1420
-rw-r--r--clang/test/OpenMP/teams_generic_loop_codegen-1.cpp1324
-rw-r--r--clang/test/OpenMP/teams_generic_loop_codegen.cpp630
-rw-r--r--clang/test/OpenMP/teams_generic_loop_collapse_codegen.cpp808
-rw-r--r--clang/test/OpenMP/teams_generic_loop_private_codegen.cpp685
-rw-r--r--clang/test/OpenMP/teams_generic_loop_reduction_codegen.cpp785
-rw-r--r--clang/test/ParserOpenACC/parse-clauses.c20
-rw-r--r--clang/test/Sema/aarch64-incompat-sm-builtin-calls.c6
-rw-r--r--clang/test/Sema/aarch64-sme-func-attrs.c136
-rw-r--r--clang/test/SemaCXX/type-traits.cpp1
-rw-r--r--clang/test/SemaOpenACC/compute-construct-ast.cpp14
-rw-r--r--clang/test/SemaOpenACC/compute-construct-clause-ast.cpp74
-rw-r--r--clang/test/SemaOpenACC/compute-construct-default-clause.c55
-rw-r--r--clang/test/SemaOpenACC/compute-construct-default-clause.cpp39
-rw-r--r--clang/test/SemaTemplate/alias-templates.cpp23
-rw-r--r--clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp44
-rw-r--r--clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp121
-rw-r--r--clang/unittests/Format/FormatTest.cpp9
-rw-r--r--clang/unittests/Format/TokenAnnotatorTest.cpp25
-rw-r--r--flang/include/flang/Frontend/PreprocessorOptions.h3
-rw-r--r--flang/include/flang/Parser/parsing.h3
-rw-r--r--flang/include/flang/Parser/preprocessor.h (renamed from flang/lib/Parser/preprocessor.h)15
-rw-r--r--flang/include/flang/Parser/token-sequence.h (renamed from flang/lib/Parser/token-sequence.h)4
-rw-r--r--flang/lib/Frontend/CompilerInvocation.cpp1
-rw-r--r--flang/lib/Frontend/FrontendActions.cpp4
-rw-r--r--flang/lib/Parser/parsing.cpp17
-rw-r--r--flang/lib/Parser/preprocessor.cpp68
-rw-r--r--flang/lib/Parser/prescan.cpp4
-rw-r--r--flang/lib/Parser/prescan.h2
-rw-r--r--flang/lib/Parser/token-sequence.cpp3
-rw-r--r--flang/test/Driver/driver-help-hidden.f901
-rw-r--r--flang/test/Driver/driver-help.f902
-rw-r--r--flang/test/Preprocessing/show-macros1.F9014
-rw-r--r--flang/test/Preprocessing/show-macros2.F906
-rw-r--r--flang/test/Preprocessing/show-macros3.F909
-rw-r--r--libc/docs/gpu/building.rst7
-rw-r--r--libc/hdr/CMakeLists.txt2
-rw-r--r--libcxx/docs/Status/Cxx2cIssues.csv1
-rw-r--r--libcxx/include/CMakeLists.txt2
-rw-r--r--libcxx/include/__algorithm/simd_utils.h2
-rw-r--r--libcxx/include/__chrono/leap_second.h4
-rw-r--r--libcxx/include/__chrono/sys_info.h51
-rw-r--r--libcxx/include/__chrono/time_zone.h11
-rw-r--r--libcxx/include/__chrono/time_zone_link.h4
-rw-r--r--libcxx/include/__config4
-rw-r--r--libcxx/include/__locale12
-rw-r--r--libcxx/include/__stop_token/stop_callback.h9
-rw-r--r--libcxx/include/__utility/private_constructor_tag.h28
-rw-r--r--libcxx/include/chrono13
-rw-r--r--libcxx/include/libcxx.imp1
-rw-r--r--libcxx/include/module.modulemap24
-rw-r--r--libcxx/modules/std/chrono.inc2
-rw-r--r--libcxx/src/CMakeLists.txt2
-rw-r--r--libcxx/src/include/tzdb/leap_second_private.h27
-rw-r--r--libcxx/src/include/tzdb/time_zone_link_private.h27
-rw-r--r--libcxx/src/include/tzdb/time_zone_private.h11
-rw-r--r--libcxx/src/include/tzdb/types_private.h15
-rw-r--r--libcxx/src/locale.cpp2
-rw-r--r--libcxx/src/time_zone.cpp865
-rw-r--r--libcxx/src/tzdb.cpp8
-rw-r--r--libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp1
-rw-r--r--libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp2
-rw-r--r--libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp2
-rw-r--r--libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp199
-rw-r--r--libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.rule_selection.pass.cpp185
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx23.csv1
-rw-r--r--libcxx/test/libcxx/transitive_includes/cxx26.csv1
-rw-r--r--libcxx/test/libcxx/utilities/utility/private_constructor_tag.compile.pass.cpp19
-rw-r--r--libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/sys_info.members.pass.cpp48
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp2
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp1374
-rw-r--r--libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/sys_info.zdump.pass.cpp129
-rw-r--r--libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp2
-rw-r--r--libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp2
-rw-r--r--libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp2
-rw-r--r--libcxx/test/support/test_chrono_leap_second.h9
-rw-r--r--libcxx/utils/ci/Dockerfile35
-rwxr-xr-xlibcxx/utils/ci/run-buildbot2
-rw-r--r--libcxx/utils/generate_iwyu_mapping.py1
-rw-r--r--libcxx/utils/libcxx/test/features.py6
-rw-r--r--lld/COFF/ICF.cpp2
-rw-r--r--lld/ELF/SyntheticSections.cpp381
-rw-r--r--lld/ELF/SyntheticSections.h8
-rw-r--r--lld/ELF/Writer.cpp290
-rw-r--r--lld/ELF/Writer.h3
-rw-r--r--lld/test/COFF/arm64x-icf.s37
-rw-r--r--lldb/cmake/caches/Apple-lldb-Linux.cmake2
-rw-r--r--llvm/include/llvm/Analysis/VecFuncs.def6
-rw-r--r--llvm/include/llvm/CodeGen/MachineCombinerPattern.h2
-rw-r--r--llvm/include/llvm/Support/raw_socket_stream.h86
-rw-r--r--llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h15
-rw-r--r--llvm/lib/Analysis/LoopAccessAnalysis.cpp27
-rw-r--r--llvm/lib/Analysis/ScalarEvolution.cpp6
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp228
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp6
-rw-r--r--llvm/lib/Support/raw_socket_stream.cpp253
-rw-r--r--llvm/lib/Target/AArch64/AArch64ISelLowering.cpp21
-rw-r--r--llvm/lib/Target/AMDGPU/AMDGPU.td4
-rw-r--r--llvm/lib/Target/AMDGPU/GCNSubtarget.h3
-rw-r--r--llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp8
-rw-r--r--llvm/lib/Target/AMDGPU/SIInstructions.td8
-rw-r--r--llvm/lib/Target/AMDGPU/SIRegisterInfo.td2
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp57
-rw-r--r--llvm/lib/Target/LoongArch/LoongArchFrameLowering.h3
-rw-r--r--llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp6
-rw-r--r--llvm/lib/Target/RISCV/RISCVFrameLowering.cpp40
-rw-r--r--llvm/lib/Target/RISCV/RISCVISelLowering.cpp98
-rw-r--r--llvm/lib/Target/RISCV/RISCVInstrInfo.cpp151
-rw-r--r--llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp3
-rw-r--r--llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp35
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp218
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h42
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp98
-rw-r--r--llvm/lib/Target/SPIRV/SPIRVUtils.cpp16
-rw-r--r--llvm/lib/Target/X86/X86ISelLowering.cpp25
-rw-r--r--llvm/lib/Transforms/IPO/SampleProfile.cpp2
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp14
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp42
-rw-r--r--llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp24
-rw-r--r--llvm/lib/Transforms/Utils/CodeMoverUtils.cpp17
-rw-r--r--llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp477
-rw-r--r--llvm/test/Analysis/CostModel/RISCV/active_lane_mask.ll44
-rw-r--r--llvm/test/Analysis/CostModel/RISCV/rvv-select.ll64
-rw-r--r--llvm/test/Analysis/ScalarEvolution/pr87798.ll68
-rw-r--r--llvm/test/CodeGen/AArch64/lrint-conv.ll66
-rw-r--r--llvm/test/CodeGen/AArch64/sve2-bsl.ll28
-rw-r--r--llvm/test/CodeGen/AArch64/vector-lrint.ll39
-rw-r--r--llvm/test/CodeGen/AMDGPU/insert_waitcnt_for_precise_memory.ll1658
-rw-r--r--llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll6
-rw-r--r--llvm/test/CodeGen/RISCV/interrupt-attr-nocall.ll318
-rw-r--r--llvm/test/CodeGen/RISCV/interrupt-attr.ll1272
-rw-r--r--llvm/test/CodeGen/RISCV/rv64zba.ll40
-rw-r--r--llvm/test/CodeGen/RISCV/rvv/ctlz-sdnode.ll336
-rw-r--r--llvm/test/CodeGen/RISCV/rvv/cttz-sdnode.ll204
-rw-r--r--llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll20
-rw-r--r--llvm/test/CodeGen/RISCV/rvv/vwadd-sdnode.ll156
-rw-r--r--llvm/test/CodeGen/RISCV/rvv/vwsll-sdnode.ll23
-rw-r--r--llvm/test/CodeGen/SPIRV/SampledImageRetType.ll9
-rw-r--r--llvm/test/CodeGen/SPIRV/hlsl-intrinsics/all.ll187
-rw-r--r--llvm/test/CodeGen/X86/bitreverse.ll281
-rw-r--r--llvm/test/CodeGen/X86/mmx-intrinsics.ll2717
-rw-r--r--llvm/test/CodeGen/X86/uint_to_fp.ll54
-rw-r--r--llvm/test/CodeGen/X86/vector-bitreverse.ll46
-rw-r--r--llvm/test/Instrumentation/MemorySanitizer/overflow.ll130
-rw-r--r--llvm/test/Instrumentation/MemorySanitizer/saturating.ll113
-rw-r--r--llvm/test/Transforms/InstCombine/and-or-icmps.ll60
-rw-r--r--llvm/test/Transforms/InstCombine/known-bits.ll369
-rw-r--r--llvm/test/Transforms/InstCombine/logical-select.ll218
-rw-r--r--llvm/test/Transforms/InstCombine/shl-demand.ll118
-rw-r--r--llvm/test/Transforms/InstCombine/vector-reduce-min-max-known.ll274
-rw-r--r--llvm/test/Transforms/InstSimplify/icmp.ll138
-rw-r--r--llvm/test/Transforms/InstSimplify/known-non-zero.ll211
-rw-r--r--llvm/test/Transforms/LoopVectorize/AArch64/veclib-function-calls.ll66
-rw-r--r--llvm/test/Transforms/PhaseOrdering/AArch64/hoist-runtime-checks.ll143
-rw-r--r--llvm/test/Transforms/SLPVectorizer/AArch64/extractelements-to-shuffle.ll40
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/ext-int-reduced-not-operand.ll9
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/extractlements-gathered-first-node.ll18
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/gather-move-out-of-loop.ll10
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/gathered-delayed-nodes-with-reused-user.ll18
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-reused-as-last-inst.ll12
-rw-r--r--llvm/test/Transforms/SLPVectorizer/X86/reorder_with_external_users.ll16
-rw-r--r--llvm/test/Transforms/SLPVectorizer/alternate-non-profitable.ll36
-rw-r--r--llvm/test/Transforms/Util/add-TLI-mappings.ll32
-rw-r--r--llvm/test/Transforms/lower-builtin-allow-check-remarks.ll24
-rw-r--r--llvm/unittests/Bitcode/BitReaderTest.cpp2
-rw-r--r--llvm/unittests/Support/raw_socket_stream_test.cpp73
-rw-r--r--llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp5
-rw-r--r--mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorOps.td89
-rw-r--r--mlir/include/mlir/IR/OpDefinition.h2
-rw-r--r--mlir/include/mlir/IR/Operation.h9
-rw-r--r--mlir/lib/Bytecode/Writer/IRNumbering.cpp14
-rw-r--r--mlir/lib/Dialect/ArmNeon/Transforms/LowerContractionToSMMLAPattern.cpp3
-rw-r--r--mlir/test/Dialect/ArmNeon/lower-to-arm-neon.mlir11
-rw-r--r--mlir/test/Dialect/SparseTensor/invalid.mlir6
-rw-r--r--mlir/test/Dialect/SparseTensor/roundtrip.mlir14
-rw-r--r--mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_pack.mlir10
-rw-r--r--openmp/libomptarget/DeviceRTL/CMakeLists.txt5
-rw-r--r--openmp/libomptarget/DeviceRTL/src/LibC.cpp15
-rw-r--r--openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp4
-rw-r--r--openmp/libomptarget/src/interface.cpp2
-rw-r--r--openmp/runtime/test/lit.cfg4
-rw-r--r--polly/lib/Analysis/ScopDetectionDiagnostic.cpp2
-rw-r--r--polly/lib/Support/GICHelper.cpp15
-rw-r--r--polly/lib/Transform/MatmulOptimizer.cpp8
-rw-r--r--utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel1
287 files changed, 21887 insertions, 10466 deletions
diff --git a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
index 69b7d40ef628..ad8048e2a92b 100644
--- a/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
+++ b/clang-tools-extra/clang-tidy/utils/RenamerClangTidyCheck.cpp
@@ -489,7 +489,7 @@ void RenamerClangTidyCheck::checkNamedDecl(const NamedDecl *Decl,
}
Failure.Info = std::move(Info);
- addUsage(Decl, Range);
+ addUsage(Decl, Range, &SourceMgr);
}
void RenamerClangTidyCheck::check(const MatchFinder::MatchResult &Result) {
diff --git a/clang-tools-extra/docs/ReleaseNotes.rst b/clang-tools-extra/docs/ReleaseNotes.rst
index a7193e90c38d..b66be44e9f8a 100644
--- a/clang-tools-extra/docs/ReleaseNotes.rst
+++ b/clang-tools-extra/docs/ReleaseNotes.rst
@@ -268,7 +268,7 @@ Changes in existing checks
<clang-tidy/checks/readability/identifier-naming>` check in `GetConfigPerFile`
mode by resolving symbolic links to header files. Fixed handling of Hungarian
Prefix when configured to `LowerCase`. Added support for renaming designated
- initializers.
+ initializers. Added support for renaming macro arguments.
- Improved :doc:`readability-implicit-bool-conversion
<clang-tidy/checks/readability/implicit-bool-conversion>` check to provide
diff --git a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
index 57ef4aae5ddb..99149fe86ace 100644
--- a/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
+++ b/clang-tools-extra/test/clang-tidy/checkers/readability/identifier-naming.cpp
@@ -108,10 +108,12 @@ USER_NS::object g_s2;
// NO warnings or fixes expected as USER_NS and object are declared in a header file
SYSTEM_MACRO(var1);
-// NO warnings or fixes expected as var1 is from macro expansion
+// CHECK-MESSAGES: :[[@LINE-1]]:14: warning: invalid case style for global variable 'var1' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}SYSTEM_MACRO(g_var1);
USER_MACRO(var2);
-// NO warnings or fixes expected as var2 is declared in a macro expansion
+// CHECK-MESSAGES: :[[@LINE-1]]:12: warning: invalid case style for global variable 'var2' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}USER_MACRO(g_var2);
#define BLA int FOO_bar
BLA;
@@ -602,9 +604,20 @@ static void static_Function() {
// CHECK-FIXES: {{^}}#define MY_TEST_MACRO(X) X()
void MY_TEST_Macro(function) {}
-// CHECK-FIXES: {{^}}void MY_TEST_MACRO(function) {}
-}
-}
+// CHECK-MESSAGES: :[[@LINE-1]]:20: warning: invalid case style for global function 'function' [readability-identifier-naming]
+// CHECK-FIXES: {{^}}void MY_TEST_MACRO(Function) {}
+
+#define MY_CAT_IMPL(l, r) l ## r
+#define MY_CAT(l, r) MY_CAT_IMPL(l, r)
+#define MY_MACRO2(foo) int MY_CAT(awesome_, MY_CAT(foo, __COUNTER__)) = 0
+#define MY_MACRO3(foo) int MY_CAT(awesome_, foo) = 0
+MY_MACRO2(myglob);
+MY_MACRO3(myglob);
+// No suggestions should occur even though the resulting decl of awesome_myglob#
+// or awesome_myglob are not entirely within a macro argument.
+
+} // namespace InlineNamespace
+} // namespace FOO_NS
template <typename t_t> struct a {
// CHECK-MESSAGES: :[[@LINE-1]]:32: warning: invalid case style for struct 'a'
diff --git a/clang/docs/HIPSupport.rst b/clang/docs/HIPSupport.rst
index 543c82cf9024..5ba84c2f6705 100644
--- a/clang/docs/HIPSupport.rst
+++ b/clang/docs/HIPSupport.rst
@@ -208,6 +208,20 @@ Host Code Compilation
- These relocatable objects are then linked together.
- Host code within a TU can call host functions and launch kernels from another TU.
+Syntax Difference with CUDA
+===========================
+
+Clang's front end, used for both CUDA and HIP programming models, shares the same parsing and semantic analysis mechanisms. This includes the resolution of overloads concerning device and host functions. While there exists a comprehensive documentation on the syntax differences between Clang and NVCC for CUDA at `Dialect Differences Between Clang and NVCC <https://llvm.org/docs/CompileCudaWithLLVM.html#dialect-differences-between-clang-and-nvcc>`_, it is important to note that these differences also apply to HIP code compilation.
+
+Predefined Macros for Differentiation
+-------------------------------------
+
+To facilitate differentiation between HIP and CUDA code, as well as between device and host compilations within HIP, Clang defines specific macros:
+
+- ``__HIP__`` : This macro is defined only when compiling HIP code. It can be used to conditionally compile code specific to HIP, enabling developers to write portable code that can be compiled for both CUDA and HIP.
+
+- ``__HIP_DEVICE_COMPILE__`` : Defined exclusively during HIP device compilation, this macro allows for conditional compilation of device-specific code. It provides a mechanism to segregate device and host code, ensuring that each can be optimized for their respective execution environments.
+
Function Pointers Support
=========================
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index f96cebbde3d8..c4a4893aec5c 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -520,12 +520,11 @@ Bug Fixes to C++ Support
- Fix an issue caused by not handling invalid cases when substituting into the parameter mapping of a constraint. Fixes (#GH86757).
- Fixed a bug that prevented member function templates of class templates declared with a deduced return type
from being explicitly specialized for a given implicit instantiation of the class template.
-- Fixed a crash when ``this`` is used in a dependent class scope function template specialization
- that instantiates to a static member function.
- Fix crash when inheriting from a cv-qualified type. Fixes:
(`#35603 <https://github.com/llvm/llvm-project/issues/35603>`_)
- Fix a crash when the using enum declaration uses an anonymous enumeration. Fixes (#GH86790).
+- Handled an edge case in ``getFullyPackExpandedSize`` so that we now avoid a false-positive diagnostic. (#GH84220)
- Clang now correctly tracks type dependence of by-value captures in lambdas with an explicit
object parameter.
Fixes (#GH70604), (#GH79754), (#GH84163), (#GH84425), (#GH86054), (#GH86398), and (#GH86399).
@@ -647,6 +646,9 @@ Fixed Point Support in Clang
AST Matchers
------------
+- Fixes a long-standing performance issue in parent map generation for
+ ancestry-based matchers such as ``hasParent`` and ``hasAncestor``, making
+ them significantly faster.
- ``isInStdNamespace`` now supports Decl declared with ``extern "C++"``.
- Add ``isExplicitObjectMemberFunction``.
- Fixed ``forEachArgumentWithParam`` and ``forEachArgumentWithParamType`` to
diff --git a/clang/docs/tools/clang-formatted-files.txt b/clang/docs/tools/clang-formatted-files.txt
index 70687c23b15e..8fd4fed25a32 100644
--- a/clang/docs/tools/clang-formatted-files.txt
+++ b/clang/docs/tools/clang-formatted-files.txt
@@ -2147,8 +2147,10 @@ flang/include/flang/Parser/message.h
flang/include/flang/Parser/parse-state.h
flang/include/flang/Parser/parse-tree-visitor.h
flang/include/flang/Parser/parsing.h
+flang/include/flang/Parser/preprocessor.h
flang/include/flang/Parser/provenance.h
flang/include/flang/Parser/source.h
+flang/include/flang/Parser/token-sequence.h
flang/include/flang/Parser/tools.h
flang/include/flang/Parser/unparse.h
flang/include/flang/Parser/user-state.h
@@ -2319,7 +2321,6 @@ flang/lib/Parser/openmp-parsers.cpp
flang/lib/Parser/parse-tree.cpp
flang/lib/Parser/parsing.cpp
flang/lib/Parser/preprocessor.cpp
-flang/lib/Parser/preprocessor.h
flang/lib/Parser/prescan.cpp
flang/lib/Parser/prescan.h
flang/lib/Parser/program-parsers.cpp
@@ -2328,7 +2329,6 @@ flang/lib/Parser/source.cpp
flang/lib/Parser/stmt-parser.h
flang/lib/Parser/token-parsers.h
flang/lib/Parser/token-sequence.cpp
-flang/lib/Parser/token-sequence.h
flang/lib/Parser/tools.cpp
flang/lib/Parser/type-parser-implementation.h
flang/lib/Parser/type-parsers.h
diff --git a/clang/include/clang/AST/OpenACCClause.h b/clang/include/clang/AST/OpenACCClause.h
index 06a0098bbda4..27e4e1a12c98 100644
--- a/clang/include/clang/AST/OpenACCClause.h
+++ b/clang/include/clang/AST/OpenACCClause.h
@@ -51,6 +51,36 @@ public:
SourceLocation getLParenLoc() const { return LParenLoc; }
};
+/// A 'default' clause, has the optional 'none' or 'present' argument.
+class OpenACCDefaultClause : public OpenACCClauseWithParams {
+ friend class ASTReaderStmt;
+ friend class ASTWriterStmt;
+
+ OpenACCDefaultClauseKind DefaultClauseKind;
+
+protected:
+ OpenACCDefaultClause(OpenACCDefaultClauseKind K, SourceLocation BeginLoc,
+ SourceLocation LParenLoc, SourceLocation EndLoc)
+ : OpenACCClauseWithParams(OpenACCClauseKind::Default, BeginLoc, LParenLoc,
+ EndLoc),
+ DefaultClauseKind(K) {
+ assert((DefaultClauseKind == OpenACCDefaultClauseKind::None ||
+ DefaultClauseKind == OpenACCDefaultClauseKind::Present) &&
+ "Invalid Clause Kind");
+ }
+
+public:
+ OpenACCDefaultClauseKind getDefaultClauseKind() const {
+ return DefaultClauseKind;
+ }
+
+ static OpenACCDefaultClause *Create(const ASTContext &C,
+ OpenACCDefaultClauseKind K,
+ SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc);
+};
+
template <class Impl> class OpenACCClauseVisitor {
Impl &getDerived() { return static_cast<Impl &>(*this); }
@@ -66,6 +96,8 @@ public:
switch (C->getClauseKind()) {
case OpenACCClauseKind::Default:
+ VisitOpenACCDefaultClause(*cast<OpenACCDefaultClause>(C));
+ return;
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
@@ -112,6 +144,10 @@ public:
}
llvm_unreachable("Invalid Clause kind");
}
+
+ void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause) {
+ return getDerived().VisitOpenACCDefaultClause(Clause);
+ }
};
class OpenACCClausePrinter final
@@ -128,6 +164,8 @@ public:
}
}
OpenACCClausePrinter(raw_ostream &OS) : OS(OS) {}
+
+ void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
};
} // namespace clang
diff --git a/clang/include/clang/AST/StmtOpenMP.h b/clang/include/clang/AST/StmtOpenMP.h
index 3cb3c1014d73..f735fa5643ae 100644
--- a/clang/include/clang/AST/StmtOpenMP.h
+++ b/clang/include/clang/AST/StmtOpenMP.h
@@ -6109,6 +6109,8 @@ public:
class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
friend class ASTStmtReader;
friend class OMPExecutableDirective;
+ /// true if loop directive's associated loop can be a parallel for.
+ bool CanBeParallelFor = false;
/// Build directive with the given start and end location.
///
/// \param StartLoc Starting location of the directive kind.
@@ -6131,6 +6133,9 @@ class OMPTargetTeamsGenericLoopDirective final : public OMPLoopDirective {
llvm::omp::OMPD_target_teams_loop, SourceLocation(),
SourceLocation(), CollapsedNum) {}
+ /// Set whether associated loop can be a parallel for.
+ void setCanBeParallelFor(bool ParFor) { CanBeParallelFor = ParFor; }
+
public:
/// Creates directive with a list of \p Clauses.
///
@@ -6145,7 +6150,7 @@ public:
static OMPTargetTeamsGenericLoopDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses,
- Stmt *AssociatedStmt, const HelperExprs &Exprs);
+ Stmt *AssociatedStmt, const HelperExprs &Exprs, bool CanBeParallelFor);
/// Creates an empty directive with the place
/// for \a NumClauses clauses.
@@ -6159,6 +6164,10 @@ public:
unsigned CollapsedNum,
EmptyShell);
+ /// Return true if current loop directive's associated loop can be a
+ /// parallel for.
+ bool canBeParallelFor() const { return CanBeParallelFor; }
+
static bool classof(const Stmt *T) {
return T->getStmtClass() == OMPTargetTeamsGenericLoopDirectiveClass;
}
diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td
index 5251774ff4ef..47747d8704b6 100644
--- a/clang/include/clang/Basic/DiagnosticGroups.td
+++ b/clang/include/clang/Basic/DiagnosticGroups.td
@@ -1412,6 +1412,9 @@ def MultiGPU: DiagGroup<"multi-gpu">;
// libc and the CRT to be skipped.
def AVRRtlibLinkingQuirks : DiagGroup<"avr-rtlib-linking-quirks">;
+// A warning group related to AArch64 SME function attribues.
+def AArch64SMEAttributes : DiagGroup<"aarch64-sme-attributes">;
+
// A warning group for things that will change semantics in the future.
def FutureCompat : DiagGroup<"future-compat">;
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 1c068f6cdb42..059a8f58da5d 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -3755,6 +3755,16 @@ def err_sme_definition_using_za_in_non_sme_target : Error<
"function using ZA state requires 'sme'">;
def err_sme_definition_using_zt0_in_non_sme2_target : Error<
"function using ZT0 state requires 'sme2'">;
+def warn_sme_streaming_pass_return_vl_to_non_streaming : Warning<
+ "passing a VL-dependent argument to/from a function that has a different"
+ " streaming-mode. The streaming and non-streaming vector lengths may be"
+ " different">,
+ InGroup<AArch64SMEAttributes>, DefaultIgnore;
+def warn_sme_locally_streaming_has_vl_args_returns : Warning<
+ "passing/returning a VL-dependent argument to/from a __arm_locally_streaming"
+ " function. The streaming and non-streaming vector"
+ " lengths may be different">,
+ InGroup<AArch64SMEAttributes>, DefaultIgnore;
def err_conflicting_attributes_arm_state : Error<
"conflicting attributes for state '%0'">;
def err_sme_streaming_cannot_be_multiversioned : Error<
@@ -12255,6 +12265,10 @@ def err_acc_construct_appertainment
"be used in a statement context">;
def err_acc_clause_appertainment
: Error<"OpenACC '%1' clause is not valid on '%0' directive">;
+def err_acc_duplicate_clause_disallowed
+ : Error<"OpenACC '%1' clause cannot appear more than once on a '%0' "
+ "directive">;
+def note_acc_previous_clause_here : Note<"previous clause is here">;
def err_acc_branch_in_out_compute_construct
: Error<"invalid %select{branch|return|throw}0 %select{out of|into}1 "
"OpenACC Compute Construct">;
diff --git a/clang/include/clang/Basic/OpenACCKinds.h b/clang/include/clang/Basic/OpenACCKinds.h
index 95fc35a5bedb..3414df999917 100644
--- a/clang/include/clang/Basic/OpenACCKinds.h
+++ b/clang/include/clang/Basic/OpenACCKinds.h
@@ -419,6 +419,30 @@ enum class OpenACCDefaultClauseKind {
Invalid,
};
+template <typename StreamTy>
+inline StreamTy &printOpenACCDefaultClauseKind(StreamTy &Out,
+ OpenACCDefaultClauseKind K) {
+ switch (K) {
+ case OpenACCDefaultClauseKind::None:
+ return Out << "none";
+ case OpenACCDefaultClauseKind::Present:
+ return Out << "present";
+ case OpenACCDefaultClauseKind::Invalid:
+ return Out << "<invalid>";
+ }
+ llvm_unreachable("Unknown OpenACCDefaultClauseKind enum");
+}
+
+inline const StreamingDiagnostic &operator<<(const StreamingDiagnostic &Out,
+ OpenACCDefaultClauseKind K) {
+ return printOpenACCDefaultClauseKind(Out, K);
+}
+
+inline llvm::raw_ostream &operator<<(llvm::raw_ostream &Out,
+ OpenACCDefaultClauseKind K) {
+ return printOpenACCDefaultClauseKind(Out, K);
+}
+
enum class OpenACCReductionOperator {
/// '+'.
Addition,
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index f745e573eb26..7ac36222644a 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1449,7 +1449,7 @@ def dD : Flag<["-"], "dD">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>
def dI : Flag<["-"], "dI">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>,
HelpText<"Print include directives in -E mode in addition to normal output">,
MarshallingInfoFlag<PreprocessorOutputOpts<"ShowIncludeDirectives">>;
-def dM : Flag<["-"], "dM">, Group<d_Group>, Visibility<[ClangOption, CC1Option]>,
+def dM : Flag<["-"], "dM">, Group<d_Group>, Visibility<[ClangOption, CC1Option, FlangOption, FC1Option]>,
HelpText<"Print macro definitions in -E mode instead of normal output">;
def dead__strip : Flag<["-"], "dead_strip">;
def dependency_file : Separate<["-"], "dependency-file">,
@@ -4912,6 +4912,9 @@ defm tgsplit : SimpleMFlag<"tgsplit", "Enable", "Disable",
defm wavefrontsize64 : SimpleMFlag<"wavefrontsize64",
"Specify wavefront size 64", "Specify wavefront size 32",
" mode (AMDGPU only)">;
+defm amdgpu_precise_memory_op
+ : SimpleMFlag<"amdgpu-precise-memory-op", "Enable", "Disable",
+ " precise memory mode (AMDGPU only)">;
defm unsafe_fp_atomics : BoolMOption<"unsafe-fp-atomics",
TargetOpts<"AllowAMDGPUUnsafeFPAtomics">, DefaultFalse,
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index f311f9f37434..e3e255a0dd76 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -184,6 +184,7 @@ class PseudoObjectExpr;
class QualType;
class SemaHLSL;
class SemaOpenACC;
+class SemaSYCL;
class StandardConversionSequence;
class Stmt;
class StringLiteral;
@@ -467,7 +468,6 @@ class Sema final : public SemaBase {
// 37. Name Lookup for RISC-V Vector Intrinsic (SemaRISCVVectorLookup.cpp)
// 38. CUDA (SemaCUDA.cpp)
// 39. OpenMP Directives and Clauses (SemaOpenMP.cpp)
- // 40. SYCL Constructs (SemaSYCL.cpp)
/// \name Semantic Analysis
/// Implementations are in Sema.cpp
@@ -974,6 +974,11 @@ public:
return *OpenACCPtr;
}
+ SemaSYCL &SYCL() {
+ assert(SYCLPtr);
+ return *SYCLPtr;
+ }
+
protected:
friend class Parser;
friend class InitializationSequence;
@@ -1006,6 +1011,7 @@ private:
std::unique_ptr<SemaHLSL> HLSLPtr;
std::unique_ptr<SemaOpenACC> OpenACCPtr;
+ std::unique_ptr<SemaSYCL> SYCLPtr;
///@}
@@ -5439,8 +5445,7 @@ public:
ExprResult BuildDeclarationNameExpr(const CXXScopeSpec &SS, LookupResult &R,
bool NeedsADL,
- bool AcceptInvalidDecl = false,
- bool NeedUnresolved = false);
+ bool AcceptInvalidDecl = false);
ExprResult BuildDeclarationNameExpr(
const CXXScopeSpec &SS, const DeclarationNameInfo &NameInfo, NamedDecl *D,
NamedDecl *FoundD = nullptr,
@@ -5456,15 +5461,6 @@ public:
ExprResult ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind);
ExprResult ActOnIntegerConstant(SourceLocation Loc, uint64_t Val);
- ExprResult BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
- SourceLocation LParen,
- SourceLocation RParen,
- TypeSourceInfo *TSI);
- ExprResult ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
- SourceLocation LParen,
- SourceLocation RParen,
- ParsedType ParsedTy);
-
bool CheckLoopHintExpr(Expr *E, SourceLocation Loc);
ExprResult ActOnNumericConstant(const Token &Tok, Scope *UDLScope = nullptr);
@@ -6592,10 +6588,7 @@ public:
SourceLocation RParenLoc);
//// ActOnCXXThis - Parse 'this' pointer.
- ExprResult ActOnCXXThis(SourceLocation Loc);
-
- /// Check whether the type of 'this' is valid in the current context.
- bool CheckCXXThisType(SourceLocation Loc, QualType Type);
+ ExprResult ActOnCXXThis(SourceLocation loc);
/// Build a CXXThisExpr and mark it referenced in the current context.
Expr *BuildCXXThisExpr(SourceLocation Loc, QualType Type, bool IsImplicit);
@@ -14520,44 +14513,6 @@ private:
OpenMPDirectiveKind CancelRegion);
///@}
-
- //
- //
- // -------------------------------------------------------------------------
- //
- //
-
- /// \name SYCL Constructs
- /// Implementations are in SemaSYCL.cpp
- ///@{
-
-public:
- /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
- /// context is "used as device code".
- ///
- /// - If CurLexicalContext is a kernel function or it is known that the
- /// function will be emitted for the device, emits the diagnostics
- /// immediately.
- /// - If CurLexicalContext is a function and we are compiling
- /// for the device, but we don't know that this function will be codegen'ed
- /// for devive yet, creates a diagnostic which is emitted if and when we
- /// realize that the function will be codegen'ed.
- ///
- /// Example usage:
- ///
- /// Diagnose __float128 type usage only from SYCL device code if the current
- /// target doesn't support it
- /// if (!S.Context.getTargetInfo().hasFloat128Type() &&
- /// S.getLangOpts().SYCLIsDevice)
- /// SYCLDiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128";
- SemaDiagnosticBuilder SYCLDiagIfDeviceCode(SourceLocation Loc,
- unsigned DiagID);
-
- void deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
- llvm::DenseSet<QualType> Visited,
- ValueDecl *DeclToCheck);
-
- ///@}
};
DeductionFailureInfo
diff --git a/clang/include/clang/Sema/SemaOpenACC.h b/clang/include/clang/Sema/SemaOpenACC.h
index 45929e4a9db3..27aaee164a28 100644
--- a/clang/include/clang/Sema/SemaOpenACC.h
+++ b/clang/include/clang/Sema/SemaOpenACC.h
@@ -19,6 +19,7 @@
#include "clang/Basic/SourceLocation.h"
#include "clang/Sema/Ownership.h"
#include "clang/Sema/SemaBase.h"
+#include <variant>
namespace clang {
class OpenACCClause;
@@ -35,7 +36,11 @@ public:
SourceRange ClauseRange;
SourceLocation LParenLoc;
- // TODO OpenACC: Add variant here to store details of individual clauses.
+ struct DefaultDetails {
+ OpenACCDefaultClauseKind DefaultClauseKind;
+ };
+
+ std::variant<DefaultDetails> Details;
public:
OpenACCParsedClause(OpenACCDirectiveKind DirKind,
@@ -52,8 +57,20 @@ public:
SourceLocation getEndLoc() const { return ClauseRange.getEnd(); }
+ OpenACCDefaultClauseKind getDefaultClauseKind() const {
+ assert(ClauseKind == OpenACCClauseKind::Default &&
+ "Parsed clause is not a default clause");
+ return std::get<DefaultDetails>(Details).DefaultClauseKind;
+ }
+
void setLParenLoc(SourceLocation EndLoc) { LParenLoc = EndLoc; }
void setEndLoc(SourceLocation EndLoc) { ClauseRange.setEnd(EndLoc); }
+
+ void setDefaultDetails(OpenACCDefaultClauseKind DefKind) {
+ assert(ClauseKind == OpenACCClauseKind::Default &&
+ "Parsed clause is not a default clause");
+ Details = DefaultDetails{DefKind};
+ }
};
SemaOpenACC(Sema &S);
diff --git a/clang/include/clang/Sema/SemaSYCL.h b/clang/include/clang/Sema/SemaSYCL.h
new file mode 100644
index 000000000000..f0dcb92ee9ab
--- /dev/null
+++ b/clang/include/clang/Sema/SemaSYCL.h
@@ -0,0 +1,65 @@
+//===----- SemaSYCL.h ------- Semantic Analysis for SYCL constructs -------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+/// \file
+/// This file declares semantic analysis for SYCL constructs.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_SEMA_SEMASYCL_H
+#define LLVM_CLANG_SEMA_SEMASYCL_H
+
+#include "clang/AST/Decl.h"
+#include "clang/AST/Type.h"
+#include "clang/Basic/SourceLocation.h"
+#include "clang/Sema/Ownership.h"
+#include "clang/Sema/SemaBase.h"
+#include "llvm/ADT/DenseSet.h"
+
+namespace clang {
+
+class SemaSYCL : public SemaBase {
+public:
+ SemaSYCL(Sema &S);
+
+ /// Creates a SemaDiagnosticBuilder that emits the diagnostic if the current
+ /// context is "used as device code".
+ ///
+ /// - If CurLexicalContext is a kernel function or it is known that the
+ /// function will be emitted for the device, emits the diagnostics
+ /// immediately.
+ /// - If CurLexicalContext is a function and we are compiling
+ /// for the device, but we don't know yet that this function will be
+ /// codegen'ed for the devive, creates a diagnostic which is emitted if and
+ /// when we realize that the function will be codegen'ed.
+ ///
+ /// Example usage:
+ ///
+ /// Diagnose __float128 type usage only from SYCL device code if the current
+ /// target doesn't support it
+ /// if (!S.Context.getTargetInfo().hasFloat128Type() &&
+ /// S.getLangOpts().SYCLIsDevice)
+ /// DiagIfDeviceCode(Loc, diag::err_type_unsupported) << "__float128";
+ SemaDiagnosticBuilder DiagIfDeviceCode(SourceLocation Loc, unsigned DiagID);
+
+ void deepTypeCheckForDevice(SourceLocation UsedAt,
+ llvm::DenseSet<QualType> Visited,
+ ValueDecl *DeclToCheck);
+
+ ExprResult BuildUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ TypeSourceInfo *TSI);
+ ExprResult ActOnUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ ParsedType ParsedTy);
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_SEMA_SEMASYCL_H
diff --git a/clang/lib/AST/Interp/ByteCodeExprGen.cpp b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
index a1ce65751483..84bacd457c85 100644
--- a/clang/lib/AST/Interp/ByteCodeExprGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeExprGen.cpp
@@ -173,10 +173,18 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return this->emitCastFloatingIntegral(*ToT, CE);
}
- case CK_NullToPointer:
+ case CK_NullToPointer: {
if (DiscardResult)
return true;
- return this->emitNull(classifyPrim(CE->getType()), CE);
+
+ const Descriptor *Desc = nullptr;
+ const QualType PointeeType = CE->getType()->getPointeeType();
+ if (!PointeeType.isNull()) {
+ if (std::optional<PrimType> T = classify(PointeeType))
+ Desc = P.createDescriptor(SubExpr, *T);
+ }
+ return this->emitNull(classifyPrim(CE->getType()), Desc, CE);
+ }
case CK_PointerToIntegral: {
if (DiscardResult)
@@ -199,6 +207,41 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
return true;
}
+ case CK_IntegralToPointer: {
+ QualType IntType = SubExpr->getType();
+ assert(IntType->isIntegralOrEnumerationType());
+ if (!this->visit(SubExpr))
+ return false;
+ // FIXME: I think the discard is wrong since the int->ptr cast might cause a
+ // diagnostic.
+ PrimType T = classifyPrim(IntType);
+ if (DiscardResult)
+ return this->emitPop(T, CE);
+
+ QualType PtrType = CE->getType();
+ assert(PtrType->isPointerType());
+
+ const Descriptor *Desc;
+ if (std::optional<PrimType> T = classify(PtrType->getPointeeType()))
+ Desc = P.createDescriptor(SubExpr, *T);
+ else if (PtrType->getPointeeType()->isVoidType())
+ Desc = nullptr;
+ else
+ Desc = P.createDescriptor(CE, PtrType->getPointeeType().getTypePtr(),
+ Descriptor::InlineDescMD, true, false,
+ /*IsMutable=*/false, nullptr);
+
+ if (!this->emitGetIntPtr(T, Desc, CE))
+ return false;
+
+ PrimType DestPtrT = classifyPrim(PtrType);
+ if (DestPtrT == PT_Ptr)
+ return true;
+
+ // In case we're converting the integer to a non-Pointer.
+ return this->emitDecayPtr(PT_Ptr, DestPtrT, CE);
+ }
+
case CK_AtomicToNonAtomic:
case CK_ConstructorConversion:
case CK_FunctionToPointerDecay:
@@ -207,13 +250,31 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
case CK_UserDefinedConversion:
return this->delegate(SubExpr);
- case CK_BitCast:
+ case CK_BitCast: {
+ // Reject bitcasts to atomic types.
if (CE->getType()->isAtomicType()) {
if (!this->discard(SubExpr))
return false;
return this->emitInvalidCast(CastKind::Reinterpret, CE);
}
- return this->delegate(SubExpr);
+
+ if (DiscardResult)
+ return this->discard(SubExpr);
+
+ std::optional<PrimType> FromT = classify(SubExpr->getType());
+ std::optional<PrimType> ToT = classifyPrim(CE->getType());
+ if (!FromT || !ToT)
+ return false;
+
+ assert(isPtrType(*FromT));
+ assert(isPtrType(*ToT));
+ if (FromT == ToT)
+ return this->delegate(SubExpr);
+
+ if (!this->visit(SubExpr))
+ return false;
+ return this->emitDecayPtr(*FromT, *ToT, CE);
+ }
case CK_IntegralToBoolean:
case CK_IntegralCast: {
@@ -245,7 +306,7 @@ bool ByteCodeExprGen<Emitter>::VisitCastExpr(const CastExpr *CE) {
if (!this->visit(SubExpr))
return false;
- if (!this->emitNull(PtrT, CE))
+ if (!this->emitNull(PtrT, nullptr, CE))
return false;
return this->emitNE(PtrT, CE);
@@ -455,7 +516,7 @@ bool ByteCodeExprGen<Emitter>::VisitBinaryOperator(const BinaryOperator *BO) {
// Pointer arithmetic special case.
if (BO->getOpcode() == BO_Add || BO->getOpcode() == BO_Sub) {
- if (T == PT_Ptr || (LT == PT_Ptr && RT == PT_Ptr))
+ if (isPtrType(*T) || (isPtrType(*LT) && isPtrType(*RT)))
return this->VisitPointerArithBinOp(BO);
}
@@ -1033,6 +1094,34 @@ bool ByteCodeExprGen<Emitter>::VisitInitListExpr(const InitListExpr *E) {
return true;
}
+ if (const auto *VecT = E->getType()->getAs<VectorType>()) {
+ unsigned NumVecElements = VecT->getNumElements();
+ assert(NumVecElements >= E->getNumInits());
+
+ QualType ElemQT = VecT->getElementType();
+ PrimType ElemT = classifyPrim(ElemQT);
+
+ // All initializer elements.
+ unsigned InitIndex = 0;
+ for (const Expr *Init : E->inits()) {
+ if (!this->visit(Init))
+ return false;
+
+ if (!this->emitInitElem(ElemT, InitIndex, E))
+ return false;
+ ++InitIndex;
+ }
+
+ // Fill the rest with zeroes.
+ for (; InitIndex != NumVecElements; ++InitIndex) {
+ if (!this->visitZeroInitializer(ElemT, ElemQT, E))
+ return false;
+ if (!this->emitInitElem(ElemT, InitIndex, E))
+ return false;
+ }
+ return true;
+ }
+
return false;
}
@@ -2326,7 +2415,7 @@ bool ByteCodeExprGen<Emitter>::visitBool(const Expr *E) {
// Convert pointers to bool.
if (T == PT_Ptr || T == PT_FnPtr) {
- if (!this->emitNull(*T, E))
+ if (!this->emitNull(*T, nullptr, E))
return false;
return this->emitNE(*T, E);
}
@@ -2366,9 +2455,9 @@ bool ByteCodeExprGen<Emitter>::visitZeroInitializer(PrimType T, QualType QT,
case PT_IntAPS:
return this->emitZeroIntAPS(Ctx.getBitWidth(QT), E);
case PT_Ptr:
- return this->emitNullPtr(E);
+ return this->emitNullPtr(nullptr, E);
case PT_FnPtr:
- return this->emitNullFnPtr(E);
+ return this->emitNullFnPtr(nullptr, E);
case PT_Float: {
return this->emitConstFloat(APFloat::getZero(Ctx.getFloatSemantics(QT)), E);
}
@@ -2952,7 +3041,7 @@ bool ByteCodeExprGen<Emitter>::VisitCXXNullPtrLiteralExpr(
if (DiscardResult)
return true;
- return this->emitNullPtr(E);
+ return this->emitNullPtr(nullptr, E);
}
template <class Emitter>
diff --git a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
index 675063e74898..55a06f37a0c3 100644
--- a/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
+++ b/clang/lib/AST/Interp/ByteCodeStmtGen.cpp
@@ -110,7 +110,7 @@ bool ByteCodeStmtGen<Emitter>::emitLambdaStaticInvokerBody(
// one here, and we don't need one either because the lambda cannot have
// any captures, as verified above. Emit a null pointer. This is then
// special-cased when interpreting to not emit any misleading diagnostics.
- if (!this->emitNullPtr(MD))
+ if (!this->emitNullPtr(nullptr, MD))
return false;
// Forward all arguments from the static invoker to the lambda call operator.
diff --git a/clang/lib/AST/Interp/Context.cpp b/clang/lib/AST/Interp/Context.cpp
index 15a9d46880e9..274178837bf0 100644
--- a/clang/lib/AST/Interp/Context.cpp
+++ b/clang/lib/AST/Interp/Context.cpp
@@ -120,7 +120,8 @@ std::optional<PrimType> Context::classify(QualType T) const {
if (T->isBooleanType())
return PT_Bool;
- if (T->isAnyComplexType())
+ // We map these to primitive arrays.
+ if (T->isAnyComplexType() || T->isVectorType())
return std::nullopt;
if (T->isSignedIntegerOrEnumerationType()) {
diff --git a/clang/lib/AST/Interp/Descriptor.h b/clang/lib/AST/Interp/Descriptor.h
index 4e257361ad14..c386fc8ac7b0 100644
--- a/clang/lib/AST/Interp/Descriptor.h
+++ b/clang/lib/AST/Interp/Descriptor.h
@@ -168,6 +168,7 @@ public:
const Decl *asDecl() const { return Source.dyn_cast<const Decl *>(); }
const Expr *asExpr() const { return Source.dyn_cast<const Expr *>(); }
+ const DeclTy &getSource() const { return Source; }
const ValueDecl *asValueDecl() const {
return dyn_cast_if_present<ValueDecl>(asDecl());
diff --git a/clang/lib/AST/Interp/EvalEmitter.cpp b/clang/lib/AST/Interp/EvalEmitter.cpp
index caffb69d83e3..d764b4b6f6d1 100644
--- a/clang/lib/AST/Interp/EvalEmitter.cpp
+++ b/clang/lib/AST/Interp/EvalEmitter.cpp
@@ -51,7 +51,8 @@ EvaluationResult EvalEmitter::interpretDecl(const VarDecl *VD,
this->CheckFullyInitialized = CheckFullyInitialized;
this->ConvertResultToRValue =
VD->getAnyInitializer() &&
- (VD->getAnyInitializer()->getType()->isAnyComplexType());
+ (VD->getAnyInitializer()->getType()->isAnyComplexType() ||
+ VD->getAnyInitializer()->getType()->isVectorType());
EvalResult.setSource(VD);
if (!this->visitDecl(VD) && EvalResult.empty())
diff --git a/clang/lib/AST/Interp/FunctionPointer.h b/clang/lib/AST/Interp/FunctionPointer.h
index 2ff691b1cd3e..f61f9ded0bf0 100644
--- a/clang/lib/AST/Interp/FunctionPointer.h
+++ b/clang/lib/AST/Interp/FunctionPointer.h
@@ -22,7 +22,11 @@ private:
const Function *Func;
public:
- FunctionPointer() : Func(nullptr) {}
+ // FIXME: We might want to track the fact that the Function pointer
+ // has been created from an integer and is most likely garbage anyway.
+ FunctionPointer(uintptr_t IntVal = 0, const Descriptor *Desc = nullptr)
+ : Func(reinterpret_cast<const Function *>(IntVal)) {}
+
FunctionPointer(const Function *Func) : Func(Func) { assert(Func); }
const Function *getFunction() const { return Func; }
@@ -53,6 +57,10 @@ public:
return toAPValue().getAsString(Ctx, Func->getDecl()->getType());
}
+ uint64_t getIntegerRepresentation() const {
+ return static_cast<uint64_t>(reinterpret_cast<uintptr_t>(Func));
+ }
+
ComparisonCategoryResult compare(const FunctionPointer &RHS) const {
if (Func == RHS.Func)
return ComparisonCategoryResult::Equal;
diff --git a/clang/lib/AST/Interp/Interp.cpp b/clang/lib/AST/Interp/Interp.cpp
index 0ce64a572c26..e5e2c932f500 100644
--- a/clang/lib/AST/Interp/Interp.cpp
+++ b/clang/lib/AST/Interp/Interp.cpp
@@ -282,6 +282,8 @@ bool CheckConstant(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
}
static bool CheckConstant(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
+ if (Ptr.isIntegralPointer())
+ return true;
return CheckConstant(S, OpPC, Ptr.getDeclDesc());
}
@@ -335,6 +337,9 @@ bool CheckConst(InterpState &S, CodePtr OpPC, const Pointer &Ptr) {
return true;
}
+ if (!Ptr.isBlockPointer())
+ return false;
+
const QualType Ty = Ptr.getType();
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_modify_const_type) << Ty;
diff --git a/clang/lib/AST/Interp/Interp.h b/clang/lib/AST/Interp/Interp.h
index 2c733c90f5f2..c7012aa4ec68 100644
--- a/clang/lib/AST/Interp/Interp.h
+++ b/clang/lib/AST/Interp/Interp.h
@@ -804,8 +804,7 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
for (const auto &P : {LHS, RHS}) {
if (P.isZero())
continue;
- if (const ValueDecl *VD = P.getDeclDesc()->asValueDecl();
- VD && VD->isWeak()) {
+ if (P.isWeak()) {
const SourceInfo &Loc = S.Current->getSource(OpPC);
S.FFDiag(Loc, diag::note_constexpr_pointer_weak_comparison)
<< P.toDiagnosticString(S.getCtx());
@@ -824,9 +823,9 @@ inline bool CmpHelperEQ<Pointer>(InterpState &S, CodePtr OpPC, CompareFn Fn) {
// element in the same array are NOT equal. They have the same Base value,
// but a different Offset. This is a pretty rare case, so we fix this here
// by comparing pointers to the first elements.
- if (!LHS.isDummy() && LHS.isArrayRoot())
+ if (!LHS.isZero() && !LHS.isDummy() && LHS.isArrayRoot())
VL = LHS.atIndex(0).getByteOffset();
- if (!RHS.isDummy() && RHS.isArrayRoot())
+ if (!RHS.isZero() && !RHS.isDummy() && RHS.isArrayRoot())
VR = RHS.atIndex(0).getByteOffset();
S.Stk.push<BoolT>(BoolT::from(Fn(Compare(VL, VR))));
@@ -1387,6 +1386,8 @@ bool Load(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.peek<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
+ if (!Ptr.isBlockPointer())
+ return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
@@ -1396,6 +1397,8 @@ bool LoadPop(InterpState &S, CodePtr OpPC) {
const Pointer &Ptr = S.Stk.pop<Pointer>();
if (!CheckLoad(S, OpPC, Ptr))
return false;
+ if (!Ptr.isBlockPointer())
+ return false;
S.Stk.push<T>(Ptr.deref<T>());
return true;
}
@@ -1534,8 +1537,12 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
return true;
}
- if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex))
- return false;
+ if (!CheckNull(S, OpPC, Ptr, CSK_ArrayIndex)) {
+ // The CheckNull will have emitted a note already, but we only
+ // abort in C++, since this is fine in C.
+ if (S.getLangOpts().CPlusPlus)
+ return false;
+ }
// Arrays of unknown bounds cannot have pointers into them.
if (!CheckArray(S, OpPC, Ptr))
@@ -1561,23 +1568,25 @@ bool OffsetHelper(InterpState &S, CodePtr OpPC, const T &Offset,
Invalid = true;
};
- T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
- if constexpr (Op == ArithOp::Add) {
- // If the new offset would be negative, bail out.
- if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
- DiagInvalidOffset();
-
- // If the new offset would be out of bounds, bail out.
- if (Offset.isPositive() && Offset > MaxOffset)
- DiagInvalidOffset();
- } else {
- // If the new offset would be negative, bail out.
- if (Offset.isPositive() && Index < Offset)
- DiagInvalidOffset();
-
- // If the new offset would be out of bounds, bail out.
- if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
- DiagInvalidOffset();
+ if (Ptr.isBlockPointer()) {
+ T MaxOffset = T::from(MaxIndex - Index, Offset.bitWidth());
+ if constexpr (Op == ArithOp::Add) {
+ // If the new offset would be negative, bail out.
+ if (Offset.isNegative() && (Offset.isMin() || -Offset > Index))
+ DiagInvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (Offset.isPositive() && Offset > MaxOffset)
+ DiagInvalidOffset();
+ } else {
+ // If the new offset would be negative, bail out.
+ if (Offset.isPositive() && Index < Offset)
+ DiagInvalidOffset();
+
+ // If the new offset would be out of bounds, bail out.
+ if (Offset.isNegative() && (Offset.isMin() || -Offset > MaxOffset))
+ DiagInvalidOffset();
+ }
}
if (Invalid && !Ptr.isDummy() && S.getLangOpts().CPlusPlus)
@@ -1661,6 +1670,11 @@ inline bool SubPtr(InterpState &S, CodePtr OpPC) {
const Pointer &LHS = S.Stk.pop<Pointer>();
const Pointer &RHS = S.Stk.pop<Pointer>();
+ if (RHS.isZero()) {
+ S.Stk.push<T>(T::from(LHS.getIndex()));
+ return true;
+ }
+
if (!Pointer::hasSameBase(LHS, RHS) && S.getLangOpts().CPlusPlus) {
// TODO: Diagnose.
return false;
@@ -1839,8 +1853,9 @@ static inline bool ZeroIntAPS(InterpState &S, CodePtr OpPC, uint32_t BitWidth) {
}
template <PrimType Name, class T = typename PrimConv<Name>::T>
-inline bool Null(InterpState &S, CodePtr OpPC) {
- S.Stk.push<T>();
+inline bool Null(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
+ // Note: Desc can be null.
+ S.Stk.push<T>(0, Desc);
return true;
}
@@ -2244,6 +2259,14 @@ inline bool GetFnPtr(InterpState &S, CodePtr OpPC, const Function *Func) {
return true;
}
+template <PrimType Name, class T = typename PrimConv<Name>::T>
+inline bool GetIntPtr(InterpState &S, CodePtr OpPC, const Descriptor *Desc) {
+ const T &IntVal = S.Stk.pop<T>();
+
+ S.Stk.push<Pointer>(static_cast<uint64_t>(IntVal), Desc);
+ return true;
+}
+
/// Just emit a diagnostic. The expression that caused emission of this
/// op is not valid in a constant context.
inline bool Invalid(InterpState &S, CodePtr OpPC) {
@@ -2300,6 +2323,18 @@ inline bool CheckNonNullArg(InterpState &S, CodePtr OpPC) {
return false;
}
+/// OldPtr -> Integer -> NewPtr.
+template <PrimType TIn, PrimType TOut>
+inline bool DecayPtr(InterpState &S, CodePtr OpPC) {
+ static_assert(isPtrType(TIn) && isPtrType(TOut));
+ using FromT = typename PrimConv<TIn>::T;
+ using ToT = typename PrimConv<TOut>::T;
+
+ const FromT &OldPtr = S.Stk.pop<FromT>();
+ S.Stk.push<ToT>(ToT(OldPtr.getIntegerRepresentation(), nullptr));
+ return true;
+}
+
//===----------------------------------------------------------------------===//
// Read opcode arguments
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/Interp/InterpBlock.cpp b/clang/lib/AST/Interp/InterpBlock.cpp
index a62128d9cfae..9b33d1b778fb 100644
--- a/clang/lib/AST/Interp/InterpBlock.cpp
+++ b/clang/lib/AST/Interp/InterpBlock.cpp
@@ -73,7 +73,7 @@ void Block::replacePointer(Pointer *Old, Pointer *New) {
removePointer(Old);
addPointer(New);
- Old->Pointee = nullptr;
+ Old->PointeeStorage.BS.Pointee = nullptr;
#ifndef NDEBUG
assert(!hasPointer(Old));
@@ -104,7 +104,7 @@ DeadBlock::DeadBlock(DeadBlock *&Root, Block *Blk)
// Transfer pointers.
B.Pointers = Blk->Pointers;
for (Pointer *P = Blk->Pointers; P; P = P->Next)
- P->Pointee = &B;
+ P->PointeeStorage.BS.Pointee = &B;
}
void DeadBlock::free() {
diff --git a/clang/lib/AST/Interp/InterpBuiltin.cpp b/clang/lib/AST/Interp/InterpBuiltin.cpp
index 1bf5d55314f1..984ba4f7f268 100644
--- a/clang/lib/AST/Interp/InterpBuiltin.cpp
+++ b/clang/lib/AST/Interp/InterpBuiltin.cpp
@@ -16,6 +16,16 @@
namespace clang {
namespace interp {
+static unsigned callArgSize(const InterpState &S, const CallExpr *C) {
+ unsigned O = 0;
+
+ for (const Expr *E : C->arguments()) {
+ O += align(primSize(*S.getContext().classify(E)));
+ }
+
+ return O;
+}
+
template <typename T>
static T getParam(const InterpFrame *Frame, unsigned Index) {
assert(Frame->getFunction()->getNumParams() > Index);
@@ -816,9 +826,10 @@ static bool interp__builtin_carryop(InterpState &S, CodePtr OpPC,
static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
+ unsigned CallSize = callArgSize(S, Call);
unsigned BuiltinOp = Func->getBuiltinID();
PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = peekToAPSInt(S.Stk, ValT);
+ const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
// When the argument is 0, the result of GCC builtins is undefined, whereas
// for Microsoft intrinsics, the result is the bit-width of the argument.
@@ -826,8 +837,19 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
BuiltinOp != Builtin::BI__lzcnt &&
BuiltinOp != Builtin::BI__lzcnt64;
- if (ZeroIsUndefined && Val == 0)
- return false;
+ if (Val == 0) {
+ if (Func->getBuiltinID() == Builtin::BI__builtin_clzg &&
+ Call->getNumArgs() == 2) {
+ // We have a fallback parameter.
+ PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
+ const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
+ pushInteger(S, Fallback, Call->getType());
+ return true;
+ }
+
+ if (ZeroIsUndefined)
+ return false;
+ }
pushInteger(S, Val.countl_zero(), Call->getType());
return true;
@@ -836,11 +858,21 @@ static bool interp__builtin_clz(InterpState &S, CodePtr OpPC,
static bool interp__builtin_ctz(InterpState &S, CodePtr OpPC,
const InterpFrame *Frame, const Function *Func,
const CallExpr *Call) {
+ unsigned CallSize = callArgSize(S, Call);
PrimType ValT = *S.getContext().classify(Call->getArg(0));
- const APSInt &Val = peekToAPSInt(S.Stk, ValT);
-
- if (Val == 0)
+ const APSInt &Val = peekToAPSInt(S.Stk, ValT, CallSize);
+
+ if (Val == 0) {
+ if (Func->getBuiltinID() == Builtin::BI__builtin_ctzg &&
+ Call->getNumArgs() == 2) {
+ // We have a fallback parameter.
+ PrimType FallbackT = *S.getContext().classify(Call->getArg(1));
+ const APSInt &Fallback = peekToAPSInt(S.Stk, FallbackT);
+ pushInteger(S, Fallback, Call->getType());
+ return true;
+ }
return false;
+ }
pushInteger(S, Val.countr_zero(), Call->getType());
return true;
@@ -1223,6 +1255,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_clzl:
case Builtin::BI__builtin_clzll:
case Builtin::BI__builtin_clzs:
+ case Builtin::BI__builtin_clzg:
case Builtin::BI__lzcnt16: // Microsoft variants of count leading-zeroes
case Builtin::BI__lzcnt:
case Builtin::BI__lzcnt64:
@@ -1234,6 +1267,7 @@ bool InterpretBuiltin(InterpState &S, CodePtr OpPC, const Function *F,
case Builtin::BI__builtin_ctzl:
case Builtin::BI__builtin_ctzll:
case Builtin::BI__builtin_ctzs:
+ case Builtin::BI__builtin_ctzg:
if (!interp__builtin_ctz(S, OpPC, Frame, F, Call))
return false;
break;
diff --git a/clang/lib/AST/Interp/Opcodes.td b/clang/lib/AST/Interp/Opcodes.td
index 6e79a03203d2..e17be3afd257 100644
--- a/clang/lib/AST/Interp/Opcodes.td
+++ b/clang/lib/AST/Interp/Opcodes.td
@@ -59,6 +59,7 @@ def ArgCastKind : ArgType { let Name = "CastKind"; }
def ArgCallExpr : ArgType { let Name = "const CallExpr *"; }
def ArgOffsetOfExpr : ArgType { let Name = "const OffsetOfExpr *"; }
def ArgDeclRef : ArgType { let Name = "const DeclRefExpr *"; }
+def ArgDesc : ArgType { let Name = "const Descriptor *"; }
def ArgCCI : ArgType { let Name = "const ComparisonCategoryInfo *"; }
//===----------------------------------------------------------------------===//
@@ -272,6 +273,7 @@ def ZeroIntAPS : Opcode {
// [] -> [Pointer]
def Null : Opcode {
let Types = [PtrTypeClass];
+ let Args = [ArgDesc];
let HasGroup = 1;
}
@@ -530,6 +532,11 @@ def GetFnPtr : Opcode {
let Args = [ArgFunction];
}
+def GetIntPtr : Opcode {
+ let Types = [AluTypeClass];
+ let Args = [ArgDesc];
+ let HasGroup = 1;
+}
//===----------------------------------------------------------------------===//
// Binary operators.
@@ -662,6 +669,11 @@ def CastPointerIntegral : Opcode {
let HasGroup = 1;
}
+def DecayPtr : Opcode {
+ let Types = [PtrTypeClass, PtrTypeClass];
+ let HasGroup = 1;
+}
+
//===----------------------------------------------------------------------===//
// Comparison opcodes.
//===----------------------------------------------------------------------===//
diff --git a/clang/lib/AST/Interp/Pointer.cpp b/clang/lib/AST/Interp/Pointer.cpp
index 53998cc3233c..e163e658d462 100644
--- a/clang/lib/AST/Interp/Pointer.cpp
+++ b/clang/lib/AST/Interp/Pointer.cpp
@@ -26,60 +26,95 @@ Pointer::Pointer(Block *Pointee)
Pointer::Pointer(Block *Pointee, unsigned BaseAndOffset)
: Pointer(Pointee, BaseAndOffset, BaseAndOffset) {}
-Pointer::Pointer(const Pointer &P) : Pointer(P.Pointee, P.Base, P.Offset) {}
+Pointer::Pointer(const Pointer &P)
+ : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
+ StorageKind(P.StorageKind) {
-Pointer::Pointer(Pointer &&P)
- : Pointee(P.Pointee), Base(P.Base), Offset(P.Offset) {
- if (Pointee)
- Pointee->replacePointer(&P, this);
+ if (isBlockPointer() && PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->addPointer(this);
}
Pointer::Pointer(Block *Pointee, unsigned Base, unsigned Offset)
- : Pointee(Pointee), Base(Base), Offset(Offset) {
+ : Offset(Offset), StorageKind(Storage::Block) {
assert((Base == RootPtrMark || Base % alignof(void *) == 0) && "wrong base");
+
+ PointeeStorage.BS = {Pointee, Base};
+
if (Pointee)
Pointee->addPointer(this);
}
+Pointer::Pointer(Pointer &&P)
+ : Offset(P.Offset), PointeeStorage(P.PointeeStorage),
+ StorageKind(P.StorageKind) {
+
+ if (StorageKind == Storage::Block && PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->replacePointer(&P, this);
+}
+
Pointer::~Pointer() {
- if (Pointee) {
- Pointee->removePointer(this);
- Pointee->cleanup();
+ if (isIntegralPointer())
+ return;
+
+ if (PointeeStorage.BS.Pointee) {
+ PointeeStorage.BS.Pointee->removePointer(this);
+ PointeeStorage.BS.Pointee->cleanup();
}
}
void Pointer::operator=(const Pointer &P) {
- Block *Old = Pointee;
- if (Pointee)
- Pointee->removePointer(this);
+ if (!this->isIntegralPointer() || !P.isBlockPointer())
+ assert(P.StorageKind == StorageKind);
- Offset = P.Offset;
- Base = P.Base;
+ bool WasBlockPointer = isBlockPointer();
+ StorageKind = P.StorageKind;
+ if (StorageKind == Storage::Block) {
+ Block *Old = PointeeStorage.BS.Pointee;
+ if (WasBlockPointer && PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->removePointer(this);
- Pointee = P.Pointee;
- if (Pointee)
- Pointee->addPointer(this);
+ Offset = P.Offset;
+ PointeeStorage.BS = P.PointeeStorage.BS;
+
+ if (PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->addPointer(this);
+
+ if (WasBlockPointer && Old)
+ Old->cleanup();
- if (Old)
- Old->cleanup();
+ } else if (StorageKind == Storage::Int) {
+ PointeeStorage.Int = P.PointeeStorage.Int;
+ } else {
+ assert(false && "Unhandled storage kind");
+ }
}
void Pointer::operator=(Pointer &&P) {
- Block *Old = Pointee;
+ if (!this->isIntegralPointer() || !P.isBlockPointer())
+ assert(P.StorageKind == StorageKind);
- if (Pointee)
- Pointee->removePointer(this);
+ bool WasBlockPointer = isBlockPointer();
+ StorageKind = P.StorageKind;
+ if (StorageKind == Storage::Block) {
+ Block *Old = PointeeStorage.BS.Pointee;
+ if (WasBlockPointer && PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->removePointer(this);
- Offset = P.Offset;
- Base = P.Base;
+ Offset = P.Offset;
+ PointeeStorage.BS = P.PointeeStorage.BS;
- Pointee = P.Pointee;
- if (Pointee)
- Pointee->replacePointer(&P, this);
+ if (PointeeStorage.BS.Pointee)
+ PointeeStorage.BS.Pointee->addPointer(this);
+
+ if (WasBlockPointer && Old)
+ Old->cleanup();
- if (Old)
- Old->cleanup();
+ } else if (StorageKind == Storage::Int) {
+ PointeeStorage.Int = P.PointeeStorage.Int;
+ } else {
+ assert(false && "Unhandled storage kind");
+ }
}
APValue Pointer::toAPValue() const {
@@ -88,6 +123,11 @@ APValue Pointer::toAPValue() const {
if (isZero())
return APValue(static_cast<const Expr *>(nullptr), CharUnits::Zero(), Path,
/*IsOnePastEnd=*/false, /*IsNullPtr=*/true);
+ if (isIntegralPointer())
+ return APValue(static_cast<const Expr *>(nullptr),
+ CharUnits::fromQuantity(asIntPointer().Value + this->Offset),
+ Path,
+ /*IsOnePastEnd=*/false, /*IsNullPtr=*/false);
// Build the lvalue base from the block.
const Descriptor *Desc = getDeclDesc();
@@ -137,19 +177,52 @@ APValue Pointer::toAPValue() const {
return APValue(Base, Offset, Path, IsOnePastEnd, /*IsNullPtr=*/false);
}
+void Pointer::print(llvm::raw_ostream &OS) const {
+ OS << PointeeStorage.BS.Pointee << " (";
+ if (isBlockPointer()) {
+ OS << "Block) {";
+
+ if (PointeeStorage.BS.Base == RootPtrMark)
+ OS << "rootptr, ";
+ else
+ OS << PointeeStorage.BS.Base << ", ";
+
+ if (Offset == PastEndMark)
+ OS << "pastend, ";
+ else
+ OS << Offset << ", ";
+
+ if (isBlockPointer() && PointeeStorage.BS.Pointee)
+ OS << PointeeStorage.BS.Pointee->getSize();
+ else
+ OS << "nullptr";
+ } else {
+ OS << "Int) {";
+ OS << PointeeStorage.Int.Value << ", " << PointeeStorage.Int.Desc;
+ }
+ OS << "}";
+}
+
std::string Pointer::toDiagnosticString(const ASTContext &Ctx) const {
- if (!Pointee)
+ if (isZero())
return "nullptr";
+ if (isIntegralPointer())
+ return (Twine("&(") + Twine(asIntPointer().Value + Offset) + ")").str();
+
return toAPValue().getAsString(Ctx, getType());
}
bool Pointer::isInitialized() const {
- assert(Pointee && "Cannot check if null pointer was initialized");
+ if (isIntegralPointer())
+ return true;
+
+ assert(PointeeStorage.BS.Pointee &&
+ "Cannot check if null pointer was initialized");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
- if (isStatic() && Base == 0)
+ if (isStatic() && PointeeStorage.BS.Base == 0)
return true;
InitMapPtr &IM = getInitMap();
@@ -164,17 +237,20 @@ bool Pointer::isInitialized() const {
}
// Field has its bit in an inline descriptor.
- return Base == 0 || getInlineDesc()->IsInitialized;
+ return PointeeStorage.BS.Base == 0 || getInlineDesc()->IsInitialized;
}
void Pointer::initialize() const {
- assert(Pointee && "Cannot initialize null pointer");
+ if (isIntegralPointer())
+ return;
+
+ assert(PointeeStorage.BS.Pointee && "Cannot initialize null pointer");
const Descriptor *Desc = getFieldDesc();
assert(Desc);
if (Desc->isPrimitiveArray()) {
// Primitive global arrays don't have an initmap.
- if (isStatic() && Base == 0)
+ if (isStatic() && PointeeStorage.BS.Base == 0)
return;
// Nothing to do for these.
@@ -200,13 +276,15 @@ void Pointer::initialize() const {
}
// Field has its bit in an inline descriptor.
- assert(Base != 0 && "Only composite fields can be initialised");
+ assert(PointeeStorage.BS.Base != 0 &&
+ "Only composite fields can be initialised");
getInlineDesc()->IsInitialized = true;
}
void Pointer::activate() const {
// Field has its bit in an inline descriptor.
- assert(Base != 0 && "Only composite fields can be initialised");
+ assert(PointeeStorage.BS.Base != 0 &&
+ "Only composite fields can be initialised");
getInlineDesc()->IsActive = true;
}
@@ -215,11 +293,23 @@ void Pointer::deactivate() const {
}
bool Pointer::hasSameBase(const Pointer &A, const Pointer &B) {
- return A.Pointee == B.Pointee;
+ // Two null pointers always have the same base.
+ if (A.isZero() && B.isZero())
+ return true;
+
+ if (A.isIntegralPointer() && B.isIntegralPointer())
+ return true;
+
+ if (A.isIntegralPointer() || B.isIntegralPointer())
+ return A.getSource() == B.getSource();
+
+ return A.asBlockPointer().Pointee == B.asBlockPointer().Pointee;
}
bool Pointer::hasSameArray(const Pointer &A, const Pointer &B) {
- return hasSameBase(A, B) && A.Base == B.Base && A.getFieldDesc()->IsArray;
+ return hasSameBase(A, B) &&
+ A.PointeeStorage.BS.Base == B.PointeeStorage.BS.Base &&
+ A.getFieldDesc()->IsArray;
}
std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
@@ -342,6 +432,25 @@ std::optional<APValue> Pointer::toRValue(const Context &Ctx) const {
return false;
}
+ // Vector types.
+ if (const auto *VT = Ty->getAs<VectorType>()) {
+ assert(Ptr.getFieldDesc()->isPrimitiveArray());
+ QualType ElemTy = VT->getElementType();
+ PrimType ElemT = *Ctx.classify(ElemTy);
+
+ SmallVector<APValue> Values;
+ Values.reserve(VT->getNumElements());
+ for (unsigned I = 0; I != VT->getNumElements(); ++I) {
+ TYPE_SWITCH(ElemT, {
+ Values.push_back(Ptr.atIndex(I).deref<T>().toAPValue());
+ });
+ }
+
+ assert(Values.size() == VT->getNumElements());
+ R = APValue(Values.data(), Values.size());
+ return true;
+ }
+
llvm_unreachable("invalid value to return");
};
diff --git a/clang/lib/AST/Interp/Pointer.h b/clang/lib/AST/Interp/Pointer.h
index fffb4aba492f..fcd00aac62f9 100644
--- a/clang/lib/AST/Interp/Pointer.h
+++ b/clang/lib/AST/Interp/Pointer.h
@@ -28,11 +28,26 @@ class Block;
class DeadBlock;
class Pointer;
class Context;
+template <unsigned A, bool B> class Integral;
enum PrimType : unsigned;
class Pointer;
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P);
+struct BlockPointer {
+ /// The block the pointer is pointing to.
+ Block *Pointee;
+ /// Start of the current subfield.
+ unsigned Base;
+};
+
+struct IntPointer {
+ const Descriptor *Desc;
+ uint64_t Value;
+};
+
+enum class Storage { Block, Int };
+
/// A pointer to a memory block, live or dead.
///
/// This object can be allocated into interpreter stack frames. If pointing to
@@ -68,11 +83,20 @@ private:
static constexpr unsigned RootPtrMark = ~0u;
public:
- Pointer() {}
+ Pointer() {
+ StorageKind = Storage::Int;
+ PointeeStorage.Int.Value = 0;
+ PointeeStorage.Int.Desc = nullptr;
+ }
Pointer(Block *B);
Pointer(Block *B, unsigned BaseAndOffset);
Pointer(const Pointer &P);
Pointer(Pointer &&P);
+ Pointer(uint64_t Address, const Descriptor *Desc, unsigned Offset = 0)
+ : Offset(Offset), StorageKind(Storage::Int) {
+ PointeeStorage.Int.Value = Address;
+ PointeeStorage.Int.Desc = Desc;
+ }
~Pointer();
void operator=(const Pointer &P);
@@ -80,21 +104,30 @@ public:
/// Equality operators are just for tests.
bool operator==(const Pointer &P) const {
- return Pointee == P.Pointee && Base == P.Base && Offset == P.Offset;
- }
+ if (P.StorageKind != StorageKind)
+ return false;
+ if (isIntegralPointer())
+ return P.asIntPointer().Value == asIntPointer().Value &&
+ Offset == P.Offset;
- bool operator!=(const Pointer &P) const {
- return Pointee != P.Pointee || Base != P.Base || Offset != P.Offset;
+ assert(isBlockPointer());
+ return P.asBlockPointer().Pointee == asBlockPointer().Pointee &&
+ P.asBlockPointer().Base == asBlockPointer().Base &&
+ Offset == P.Offset;
}
+ bool operator!=(const Pointer &P) const { return !(P == *this); }
+
/// Converts the pointer to an APValue.
APValue toAPValue() const;
/// Converts the pointer to a string usable in diagnostics.
std::string toDiagnosticString(const ASTContext &Ctx) const;
- unsigned getIntegerRepresentation() const {
- return reinterpret_cast<uintptr_t>(Pointee) + Offset;
+ uint64_t getIntegerRepresentation() const {
+ if (isIntegralPointer())
+ return asIntPointer().Value + (Offset * elemSize());
+ return reinterpret_cast<uint64_t>(asBlockPointer().Pointee) + Offset;
}
/// Converts the pointer to an APValue that is an rvalue.
@@ -102,20 +135,27 @@ public:
/// Offsets a pointer inside an array.
[[nodiscard]] Pointer atIndex(unsigned Idx) const {
- if (Base == RootPtrMark)
- return Pointer(Pointee, RootPtrMark, getDeclDesc()->getSize());
+ if (isIntegralPointer())
+ return Pointer(asIntPointer().Value, asIntPointer().Desc, Idx);
+
+ if (asBlockPointer().Base == RootPtrMark)
+ return Pointer(asBlockPointer().Pointee, RootPtrMark,
+ getDeclDesc()->getSize());
unsigned Off = Idx * elemSize();
if (getFieldDesc()->ElemDesc)
Off += sizeof(InlineDescriptor);
else
Off += sizeof(InitMapPtr);
- return Pointer(Pointee, Base, Base + Off);
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
+ asBlockPointer().Base + Off);
}
/// Creates a pointer to a field.
[[nodiscard]] Pointer atField(unsigned Off) const {
unsigned Field = Offset + Off;
- return Pointer(Pointee, Field, Field);
+ if (isIntegralPointer())
+ return Pointer(asIntPointer().Value + Field, asIntPointer().Desc);
+ return Pointer(asBlockPointer().Pointee, Field, Field);
}
/// Subtract the given offset from the current Base and Offset
@@ -123,44 +163,49 @@ public:
[[nodiscard]] Pointer atFieldSub(unsigned Off) const {
assert(Offset >= Off);
unsigned O = Offset - Off;
- return Pointer(Pointee, O, O);
+ return Pointer(asBlockPointer().Pointee, O, O);
}
/// Restricts the scope of an array element pointer.
[[nodiscard]] Pointer narrow() const {
+ if (!isBlockPointer())
+ return *this;
+ assert(isBlockPointer());
// Null pointers cannot be narrowed.
if (isZero() || isUnknownSizeArray())
return *this;
// Pointer to an array of base types - enter block.
- if (Base == RootPtrMark)
- return Pointer(Pointee, sizeof(InlineDescriptor),
+ if (asBlockPointer().Base == RootPtrMark)
+ return Pointer(asBlockPointer().Pointee, sizeof(InlineDescriptor),
Offset == 0 ? Offset : PastEndMark);
// Pointer is one past end - magic offset marks that.
if (isOnePastEnd())
- return Pointer(Pointee, Base, PastEndMark);
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
+ PastEndMark);
// Primitive arrays are a bit special since they do not have inline
// descriptors. If Offset != Base, then the pointer already points to
// an element and there is nothing to do. Otherwise, the pointer is
// adjusted to the first element of the array.
if (inPrimitiveArray()) {
- if (Offset != Base)
+ if (Offset != asBlockPointer().Base)
return *this;
- return Pointer(Pointee, Base, Offset + sizeof(InitMapPtr));
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
+ Offset + sizeof(InitMapPtr));
}
// Pointer is to a field or array element - enter it.
- if (Offset != Base)
- return Pointer(Pointee, Offset, Offset);
+ if (Offset != asBlockPointer().Base)
+ return Pointer(asBlockPointer().Pointee, Offset, Offset);
// Enter the first element of an array.
if (!getFieldDesc()->isArray())
return *this;
- const unsigned NewBase = Base + sizeof(InlineDescriptor);
- return Pointer(Pointee, NewBase, NewBase);
+ const unsigned NewBase = asBlockPointer().Base + sizeof(InlineDescriptor);
+ return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
}
/// Expands a pointer to the containing array, undoing narrowing.
@@ -172,72 +217,109 @@ public:
Adjust = sizeof(InitMapPtr);
else
Adjust = sizeof(InlineDescriptor);
- return Pointer(Pointee, Base, Base + getSize() + Adjust);
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
+ asBlockPointer().Base + getSize() + Adjust);
}
// Do not step out of array elements.
- if (Base != Offset)
+ if (asBlockPointer().Base != Offset)
return *this;
// If at base, point to an array of base types.
- if (Base == 0 || Base == sizeof(InlineDescriptor))
- return Pointer(Pointee, RootPtrMark, 0);
+ if (asBlockPointer().Base == 0 ||
+ asBlockPointer().Base == sizeof(InlineDescriptor))
+ return Pointer(asBlockPointer().Pointee, RootPtrMark, 0);
// Step into the containing array, if inside one.
- unsigned Next = Base - getInlineDesc()->Offset;
+ unsigned Next = asBlockPointer().Base - getInlineDesc()->Offset;
const Descriptor *Desc =
Next == 0 ? getDeclDesc() : getDescriptor(Next)->Desc;
if (!Desc->IsArray)
return *this;
- return Pointer(Pointee, Next, Offset);
+ return Pointer(asBlockPointer().Pointee, Next, Offset);
}
/// Checks if the pointer is null.
- bool isZero() const { return Pointee == nullptr; }
+ bool isZero() const {
+ if (Offset != 0)
+ return false;
+
+ if (isBlockPointer())
+ return asBlockPointer().Pointee == nullptr;
+ assert(isIntegralPointer());
+ return asIntPointer().Value == 0;
+ }
/// Checks if the pointer is live.
- bool isLive() const { return Pointee && !Pointee->IsDead; }
+ bool isLive() const {
+ if (isIntegralPointer())
+ return true;
+ return asBlockPointer().Pointee && !asBlockPointer().Pointee->IsDead;
+ }
/// Checks if the item is a field in an object.
bool isField() const {
+ if (isIntegralPointer())
+ return false;
+
+ unsigned Base = asBlockPointer().Base;
return Base != 0 && Base != sizeof(InlineDescriptor) &&
Base != RootPtrMark && getFieldDesc()->asDecl();
}
/// Accessor for information about the declaration site.
const Descriptor *getDeclDesc() const {
- assert(Pointee);
- return Pointee->Desc;
+ if (isIntegralPointer())
+ return asIntPointer().Desc;
+
+ assert(isBlockPointer());
+ assert(asBlockPointer().Pointee);
+ return asBlockPointer().Pointee->Desc;
}
SourceLocation getDeclLoc() const { return getDeclDesc()->getLocation(); }
+ /// Returns the expression or declaration the pointer has been created for.
+ DeclTy getSource() const {
+ if (isBlockPointer())
+ return getDeclDesc()->getSource();
+
+ assert(isIntegralPointer());
+ return asIntPointer().Desc ? asIntPointer().Desc->getSource() : DeclTy();
+ }
+
/// Returns a pointer to the object of which this pointer is a field.
[[nodiscard]] Pointer getBase() const {
- if (Base == RootPtrMark) {
+ if (asBlockPointer().Base == RootPtrMark) {
assert(Offset == PastEndMark && "cannot get base of a block");
- return Pointer(Pointee, Base, 0);
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
}
- unsigned NewBase = Base - getInlineDesc()->Offset;
- return Pointer(Pointee, NewBase, NewBase);
+ unsigned NewBase = asBlockPointer().Base - getInlineDesc()->Offset;
+ return Pointer(asBlockPointer().Pointee, NewBase, NewBase);
}
/// Returns the parent array.
[[nodiscard]] Pointer getArray() const {
- if (Base == RootPtrMark) {
+ if (asBlockPointer().Base == RootPtrMark) {
assert(Offset != 0 && Offset != PastEndMark && "not an array element");
- return Pointer(Pointee, Base, 0);
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base, 0);
}
- assert(Offset != Base && "not an array element");
- return Pointer(Pointee, Base, Base);
+ assert(Offset != asBlockPointer().Base && "not an array element");
+ return Pointer(asBlockPointer().Pointee, asBlockPointer().Base,
+ asBlockPointer().Base);
}
/// Accessors for information about the innermost field.
const Descriptor *getFieldDesc() const {
- if (Base == 0 || Base == sizeof(InlineDescriptor) || Base == RootPtrMark)
+ if (isIntegralPointer())
+ return asIntPointer().Desc;
+ if (isBlockPointer() &&
+ (asBlockPointer().Base == 0 ||
+ asBlockPointer().Base == sizeof(InlineDescriptor) ||
+ asBlockPointer().Base == RootPtrMark))
return getDeclDesc();
return getInlineDesc()->Desc;
}
/// Returns the type of the innermost field.
QualType getType() const {
- if (inPrimitiveArray() && Offset != Base) {
+ if (inPrimitiveArray() && Offset != asBlockPointer().Base) {
// Unfortunately, complex types are not array types in clang, but they are
// for us.
if (const auto *AT = getFieldDesc()->getType()->getAsArrayTypeUnsafe())
@@ -248,58 +330,104 @@ public:
return getFieldDesc()->getType();
}
- [[nodiscard]] Pointer getDeclPtr() const { return Pointer(Pointee); }
+ [[nodiscard]] Pointer getDeclPtr() const {
+ return Pointer(asBlockPointer().Pointee);
+ }
/// Returns the element size of the innermost field.
size_t elemSize() const {
- if (Base == RootPtrMark)
+ if (isIntegralPointer()) {
+ if (!asIntPointer().Desc)
+ return 1;
+ return asIntPointer().Desc->getElemSize();
+ }
+
+ if (asBlockPointer().Base == RootPtrMark)
return getDeclDesc()->getSize();
return getFieldDesc()->getElemSize();
}
/// Returns the total size of the innermost field.
- size_t getSize() const { return getFieldDesc()->getSize(); }
+ size_t getSize() const {
+ assert(isBlockPointer());
+ return getFieldDesc()->getSize();
+ }
/// Returns the offset into an array.
unsigned getOffset() const {
assert(Offset != PastEndMark && "invalid offset");
- if (Base == RootPtrMark)
+ if (asBlockPointer().Base == RootPtrMark)
return Offset;
unsigned Adjust = 0;
- if (Offset != Base) {
+ if (Offset != asBlockPointer().Base) {
if (getFieldDesc()->ElemDesc)
Adjust = sizeof(InlineDescriptor);
else
Adjust = sizeof(InitMapPtr);
}
- return Offset - Base - Adjust;
+ return Offset - asBlockPointer().Base - Adjust;
}
/// Whether this array refers to an array, but not
/// to the first element.
- bool isArrayRoot() const { return inArray() && Offset == Base; }
+ bool isArrayRoot() const {
+ return inArray() && Offset == asBlockPointer().Base;
+ }
/// Checks if the innermost field is an array.
- bool inArray() const { return getFieldDesc()->IsArray; }
+ bool inArray() const {
+ if (isBlockPointer())
+ return getFieldDesc()->IsArray;
+ return false;
+ }
/// Checks if the structure is a primitive array.
- bool inPrimitiveArray() const { return getFieldDesc()->isPrimitiveArray(); }
+ bool inPrimitiveArray() const {
+ if (isBlockPointer())
+ return getFieldDesc()->isPrimitiveArray();
+ return false;
+ }
/// Checks if the structure is an array of unknown size.
bool isUnknownSizeArray() const {
+ if (!isBlockPointer())
+ return false;
// If this points inside a dummy block, return true.
// FIXME: This might change in the future. If it does, we need
// to set the proper Ctor/Dtor functions for dummy Descriptors.
- if (Base != 0 && Base != sizeof(InlineDescriptor) && isDummy())
+ if (asBlockPointer().Base != 0 &&
+ asBlockPointer().Base != sizeof(InlineDescriptor) && isDummy())
return true;
return getFieldDesc()->isUnknownSizeArray();
}
/// Checks if the pointer points to an array.
- bool isArrayElement() const { return inArray() && Base != Offset; }
+ bool isArrayElement() const {
+ if (isBlockPointer())
+ return inArray() && asBlockPointer().Base != Offset;
+ return false;
+ }
/// Pointer points directly to a block.
bool isRoot() const {
- return (Base == 0 || Base == RootPtrMark) && Offset == 0;
+ return (asBlockPointer().Base == 0 ||
+ asBlockPointer().Base == RootPtrMark) &&
+ Offset == 0;
}
/// If this pointer has an InlineDescriptor we can use to initialize.
- bool canBeInitialized() const { return Pointee && Base > 0; }
+ bool canBeInitialized() const {
+ if (!isBlockPointer())
+ return false;
+
+ return asBlockPointer().Pointee && asBlockPointer().Base > 0;
+ }
+
+ [[nodiscard]] const BlockPointer &asBlockPointer() const {
+ assert(isBlockPointer());
+ return PointeeStorage.BS;
+ }
+ [[nodiscard]] const IntPointer &asIntPointer() const {
+ assert(isIntegralPointer());
+ return PointeeStorage.Int;
+ }
+ bool isBlockPointer() const { return StorageKind == Storage::Block; }
+ bool isIntegralPointer() const { return StorageKind == Storage::Int; }
/// Returns the record descriptor of a class.
const Record *getRecord() const { return getFieldDesc()->ElemRecord; }
@@ -315,71 +443,119 @@ public:
bool isUnion() const;
/// Checks if the storage is extern.
- bool isExtern() const { return Pointee && Pointee->isExtern(); }
+ bool isExtern() const {
+ if (isBlockPointer())
+ return asBlockPointer().Pointee && asBlockPointer().Pointee->isExtern();
+ return false;
+ }
/// Checks if the storage is static.
bool isStatic() const {
- assert(Pointee);
- return Pointee->isStatic();
+ if (isIntegralPointer())
+ return true;
+ assert(asBlockPointer().Pointee);
+ return asBlockPointer().Pointee->isStatic();
}
/// Checks if the storage is temporary.
bool isTemporary() const {
- assert(Pointee);
- return Pointee->isTemporary();
+ if (isBlockPointer()) {
+ assert(asBlockPointer().Pointee);
+ return asBlockPointer().Pointee->isTemporary();
+ }
+ return false;
}
/// Checks if the storage is a static temporary.
bool isStaticTemporary() const { return isStatic() && isTemporary(); }
/// Checks if the field is mutable.
bool isMutable() const {
- return Base != 0 && Base != sizeof(InlineDescriptor) &&
+ if (!isBlockPointer())
+ return false;
+ return asBlockPointer().Base != 0 &&
+ asBlockPointer().Base != sizeof(InlineDescriptor) &&
getInlineDesc()->IsFieldMutable;
}
+
+ bool isWeak() const {
+ if (isIntegralPointer())
+ return false;
+
+ assert(isBlockPointer());
+ if (const ValueDecl *VD = getDeclDesc()->asValueDecl())
+ return VD->isWeak();
+ return false;
+ }
/// Checks if an object was initialized.
bool isInitialized() const;
/// Checks if the object is active.
bool isActive() const {
- return Base == 0 || Base == sizeof(InlineDescriptor) ||
+ if (!isBlockPointer())
+ return true;
+ return asBlockPointer().Base == 0 ||
+ asBlockPointer().Base == sizeof(InlineDescriptor) ||
getInlineDesc()->IsActive;
}
/// Checks if a structure is a base class.
bool isBaseClass() const { return isField() && getInlineDesc()->IsBase; }
/// Checks if the pointer points to a dummy value.
bool isDummy() const {
- if (!Pointee)
+ if (!isBlockPointer())
return false;
+
+ if (!asBlockPointer().Pointee)
+ return false;
+
return getDeclDesc()->isDummy();
}
/// Checks if an object or a subfield is mutable.
bool isConst() const {
- return (Base == 0 || Base == sizeof(InlineDescriptor))
+ if (isIntegralPointer())
+ return true;
+ return (asBlockPointer().Base == 0 ||
+ asBlockPointer().Base == sizeof(InlineDescriptor))
? getDeclDesc()->IsConst
: getInlineDesc()->IsConst;
}
/// Returns the declaration ID.
std::optional<unsigned> getDeclID() const {
- assert(Pointee);
- return Pointee->getDeclID();
+ if (isBlockPointer()) {
+ assert(asBlockPointer().Pointee);
+ return asBlockPointer().Pointee->getDeclID();
+ }
+ return std::nullopt;
}
/// Returns the byte offset from the start.
unsigned getByteOffset() const {
+ if (isIntegralPointer())
+ return asIntPointer().Value + Offset;
return Offset;
}
/// Returns the number of elements.
- unsigned getNumElems() const { return getSize() / elemSize(); }
+ unsigned getNumElems() const {
+ if (isIntegralPointer())
+ return ~unsigned(0);
+ return getSize() / elemSize();
+ }
- const Block *block() const { return Pointee; }
+ const Block *block() const { return asBlockPointer().Pointee; }
/// Returns the index into an array.
int64_t getIndex() const {
+ if (!isBlockPointer())
+ return 0;
+
+ if (isZero())
+ return 0;
+
if (isElementPastEnd())
return 1;
// narrow()ed element in a composite array.
- if (Base > sizeof(InlineDescriptor) && Base == Offset)
+ if (asBlockPointer().Base > sizeof(InlineDescriptor) &&
+ asBlockPointer().Base == Offset)
return 0;
if (auto ElemSize = elemSize())
@@ -389,7 +565,10 @@ public:
/// Checks if the index is one past end.
bool isOnePastEnd() const {
- if (!Pointee)
+ if (isIntegralPointer())
+ return false;
+
+ if (!asBlockPointer().Pointee)
return false;
return isElementPastEnd() || getSize() == getOffset();
}
@@ -400,20 +579,25 @@ public:
/// Dereferences the pointer, if it's live.
template <typename T> T &deref() const {
assert(isLive() && "Invalid pointer");
- assert(Pointee);
+ assert(isBlockPointer());
+ assert(asBlockPointer().Pointee);
+ assert(Offset + sizeof(T) <=
+ asBlockPointer().Pointee->getDescriptor()->getAllocSize());
+
if (isArrayRoot())
- return *reinterpret_cast<T *>(Pointee->rawData() + Base +
- sizeof(InitMapPtr));
+ return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() +
+ asBlockPointer().Base + sizeof(InitMapPtr));
- assert(Offset + sizeof(T) <= Pointee->getDescriptor()->getAllocSize());
- return *reinterpret_cast<T *>(Pointee->rawData() + Offset);
+ return *reinterpret_cast<T *>(asBlockPointer().Pointee->rawData() + Offset);
}
/// Dereferences a primitive element.
template <typename T> T &elem(unsigned I) const {
assert(I < getNumElems());
- assert(Pointee);
- return reinterpret_cast<T *>(Pointee->data() + sizeof(InitMapPtr))[I];
+ assert(isBlockPointer());
+ assert(asBlockPointer().Pointee);
+ return reinterpret_cast<T *>(asBlockPointer().Pointee->data() +
+ sizeof(InitMapPtr))[I];
}
/// Initializes a field.
@@ -442,24 +626,7 @@ public:
static bool hasSameArray(const Pointer &A, const Pointer &B);
/// Prints the pointer.
- void print(llvm::raw_ostream &OS) const {
- OS << Pointee << " {";
- if (Base == RootPtrMark)
- OS << "rootptr, ";
- else
- OS << Base << ", ";
-
- if (Offset == PastEndMark)
- OS << "pastend, ";
- else
- OS << Offset << ", ";
-
- if (Pointee)
- OS << Pointee->getSize();
- else
- OS << "nullptr";
- OS << "}";
- }
+ void print(llvm::raw_ostream &OS) const;
private:
friend class Block;
@@ -469,33 +636,41 @@ private:
Pointer(Block *Pointee, unsigned Base, unsigned Offset);
/// Returns the embedded descriptor preceding a field.
- InlineDescriptor *getInlineDesc() const { return getDescriptor(Base); }
+ InlineDescriptor *getInlineDesc() const {
+ return getDescriptor(asBlockPointer().Base);
+ }
/// Returns a descriptor at a given offset.
InlineDescriptor *getDescriptor(unsigned Offset) const {
assert(Offset != 0 && "Not a nested pointer");
- assert(Pointee);
- return reinterpret_cast<InlineDescriptor *>(Pointee->rawData() + Offset) -
+ assert(isBlockPointer());
+ assert(!isZero());
+ return reinterpret_cast<InlineDescriptor *>(
+ asBlockPointer().Pointee->rawData() + Offset) -
1;
}
/// Returns a reference to the InitMapPtr which stores the initialization map.
InitMapPtr &getInitMap() const {
- assert(Pointee);
- return *reinterpret_cast<InitMapPtr *>(Pointee->rawData() + Base);
+ assert(isBlockPointer());
+ assert(!isZero());
+ return *reinterpret_cast<InitMapPtr *>(asBlockPointer().Pointee->rawData() +
+ asBlockPointer().Base);
}
- /// The block the pointer is pointing to.
- Block *Pointee = nullptr;
- /// Start of the current subfield.
- unsigned Base = 0;
- /// Offset into the block.
+ /// Offset into the storage.
unsigned Offset = 0;
/// Previous link in the pointer chain.
Pointer *Prev = nullptr;
/// Next link in the pointer chain.
Pointer *Next = nullptr;
+
+ union {
+ BlockPointer BS;
+ IntPointer Int;
+ } PointeeStorage;
+ Storage StorageKind = Storage::Int;
};
inline llvm::raw_ostream &operator<<(llvm::raw_ostream &OS, const Pointer &P) {
diff --git a/clang/lib/AST/Interp/PrimType.h b/clang/lib/AST/Interp/PrimType.h
index 2bc83b334643..05a094d0c5b1 100644
--- a/clang/lib/AST/Interp/PrimType.h
+++ b/clang/lib/AST/Interp/PrimType.h
@@ -46,6 +46,10 @@ enum PrimType : unsigned {
PT_FnPtr,
};
+inline constexpr bool isPtrType(PrimType T) {
+ return T == PT_Ptr || T == PT_FnPtr;
+}
+
enum class CastKind : uint8_t {
Reinterpret,
Atomic,
diff --git a/clang/lib/AST/Interp/Program.cpp b/clang/lib/AST/Interp/Program.cpp
index 25e938e01503..82367164743f 100644
--- a/clang/lib/AST/Interp/Program.cpp
+++ b/clang/lib/AST/Interp/Program.cpp
@@ -411,5 +411,12 @@ Descriptor *Program::createDescriptor(const DeclTy &D, const Type *Ty,
IsMutable);
}
+ // Same with vector types.
+ if (const auto *VT = Ty->getAs<VectorType>()) {
+ PrimType ElemTy = *Ctx.classify(VT->getElementType());
+ return allocateDescriptor(D, ElemTy, MDSize, VT->getNumElements(), IsConst,
+ IsTemporary, IsMutable);
+ }
+
return nullptr;
}
diff --git a/clang/lib/AST/OpenACCClause.cpp b/clang/lib/AST/OpenACCClause.cpp
index e1db872f25c3..c83128b60e3a 100644
--- a/clang/lib/AST/OpenACCClause.cpp
+++ b/clang/lib/AST/OpenACCClause.cpp
@@ -15,3 +15,22 @@
#include "clang/AST/ASTContext.h"
using namespace clang;
+
+OpenACCDefaultClause *OpenACCDefaultClause::Create(const ASTContext &C,
+ OpenACCDefaultClauseKind K,
+ SourceLocation BeginLoc,
+ SourceLocation LParenLoc,
+ SourceLocation EndLoc) {
+ void *Mem =
+ C.Allocate(sizeof(OpenACCDefaultClause), alignof(OpenACCDefaultClause));
+
+ return new (Mem) OpenACCDefaultClause(K, BeginLoc, LParenLoc, EndLoc);
+}
+
+//===----------------------------------------------------------------------===//
+// OpenACC clauses printing methods
+//===----------------------------------------------------------------------===//
+void OpenACCClausePrinter::VisitOpenACCDefaultClause(
+ const OpenACCDefaultClause &C) {
+ OS << "default(" << C.getDefaultClauseKind() << ")";
+}
diff --git a/clang/lib/AST/ParentMapContext.cpp b/clang/lib/AST/ParentMapContext.cpp
index 21cfd5b1de6e..9723c0cfa83b 100644
--- a/clang/lib/AST/ParentMapContext.cpp
+++ b/clang/lib/AST/ParentMapContext.cpp
@@ -61,7 +61,26 @@ class ParentMapContext::ParentMap {
template <typename, typename...> friend struct ::MatchParents;
/// Contains parents of a node.
- using ParentVector = llvm::SmallVector<DynTypedNode, 2>;
+ class ParentVector {
+ public:
+ ParentVector() = default;
+ explicit ParentVector(size_t N, const DynTypedNode &Value) {
+ Items.reserve(N);
+ for (; N > 0; --N)
+ push_back(Value);
+ }
+ bool contains(const DynTypedNode &Value) {
+ return Seen.contains(Value);
+ }
+ void push_back(const DynTypedNode &Value) {
+ if (!Value.getMemoizationData() || Seen.insert(Value).second)
+ Items.push_back(Value);
+ }
+ llvm::ArrayRef<DynTypedNode> view() const { return Items; }
+ private:
+ llvm::SmallVector<DynTypedNode, 2> Items;
+ llvm::SmallDenseSet<DynTypedNode, 2> Seen;
+ };
/// Maps from a node to its parents. This is used for nodes that have
/// pointer identity only, which are more common and we can save space by
@@ -99,7 +118,7 @@ class ParentMapContext::ParentMap {
return llvm::ArrayRef<DynTypedNode>();
}
if (const auto *V = I->second.template dyn_cast<ParentVector *>()) {
- return llvm::ArrayRef(*V);
+ return V->view();
}
return getSingleDynTypedNodeFromParentMap(I->second);
}
@@ -252,7 +271,7 @@ public:
const auto *S = It->second.dyn_cast<const Stmt *>();
if (!S) {
if (auto *Vec = It->second.dyn_cast<ParentVector *>())
- return llvm::ArrayRef(*Vec);
+ return Vec->view();
return getSingleDynTypedNodeFromParentMap(It->second);
}
const auto *P = dyn_cast<Expr>(S);
diff --git a/clang/lib/AST/StmtOpenMP.cpp b/clang/lib/AST/StmtOpenMP.cpp
index 426b35848cb5..d8519b2071e6 100644
--- a/clang/lib/AST/StmtOpenMP.cpp
+++ b/clang/lib/AST/StmtOpenMP.cpp
@@ -2431,7 +2431,7 @@ OMPTeamsGenericLoopDirective::CreateEmpty(const ASTContext &C,
OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
unsigned CollapsedNum, ArrayRef<OMPClause *> Clauses, Stmt *AssociatedStmt,
- const HelperExprs &Exprs) {
+ const HelperExprs &Exprs, bool CanBeParallelFor) {
auto *Dir = createDirective<OMPTargetTeamsGenericLoopDirective>(
C, Clauses, AssociatedStmt,
numLoopChildren(CollapsedNum, OMPD_target_teams_loop), StartLoc, EndLoc,
@@ -2473,6 +2473,7 @@ OMPTargetTeamsGenericLoopDirective *OMPTargetTeamsGenericLoopDirective::Create(
Dir->setCombinedNextUpperBound(Exprs.DistCombinedFields.NUB);
Dir->setCombinedDistCond(Exprs.DistCombinedFields.DistCond);
Dir->setCombinedParForInDistCond(Exprs.DistCombinedFields.ParForInDistCond);
+ Dir->setCanBeParallelFor(CanBeParallelFor);
return Dir;
}
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index bec8bc71f555..be3dd4b673cf 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2456,7 +2456,12 @@ public:
Visit(Clause);
}
}
+ void VisitOpenACCDefaultClause(const OpenACCDefaultClause &Clause);
};
+
+/// Nothing to do here, there are no sub-statements.
+void OpenACCClauseProfiler::VisitOpenACCDefaultClause(
+ const OpenACCDefaultClause &Clause) {}
} // namespace
void StmtProfiler::VisitOpenACCComputeConstruct(
diff --git a/clang/lib/AST/TextNodeDumper.cpp b/clang/lib/AST/TextNodeDumper.cpp
index 431f5d8bdb2b..085a7f51ce99 100644
--- a/clang/lib/AST/TextNodeDumper.cpp
+++ b/clang/lib/AST/TextNodeDumper.cpp
@@ -390,6 +390,17 @@ void TextNodeDumper::Visit(const OpenACCClause *C) {
{
ColorScope Color(OS, ShowColors, AttrColor);
OS << C->getClauseKind();
+
+ // Handle clauses with parens for types that have no children, likely
+ // because there is no sub expression.
+ switch (C->getClauseKind()) {
+ case OpenACCClauseKind::Default:
+ OS << '(' << cast<OpenACCDefaultClause>(C)->getDefaultClauseKind() << ')';
+ break;
+ default:
+ // Nothing to do here.
+ break;
+ }
}
dumpPointer(C);
dumpSourceRange(SourceRange(C->getBeginLoc(), C->getEndLoc()));
diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp
index 075c8aba11fc..9602f448e942 100644
--- a/clang/lib/AST/TypePrinter.cpp
+++ b/clang/lib/AST/TypePrinter.cpp
@@ -1213,10 +1213,13 @@ void TypePrinter::printDecltypeBefore(const DecltypeType *T, raw_ostream &OS) {
void TypePrinter::printPackIndexingBefore(const PackIndexingType *T,
raw_ostream &OS) {
- if (T->hasSelectedType())
+ if (T->hasSelectedType()) {
OS << T->getSelectedType();
- else
- OS << T->getPattern() << "...[" << T->getIndexExpr() << "]";
+ } else {
+ OS << T->getPattern() << "...[";
+ T->getIndexExpr()->printPretty(OS, nullptr, Policy);
+ OS << "]";
+ }
spaceBeforePlaceHolder(OS);
}
diff --git a/clang/lib/Basic/Targets/AArch64.cpp b/clang/lib/Basic/Targets/AArch64.cpp
index 1569b5e04b77..c8d243a8fb7a 100644
--- a/clang/lib/Basic/Targets/AArch64.cpp
+++ b/clang/lib/Basic/Targets/AArch64.cpp
@@ -1543,10 +1543,13 @@ WindowsARM64TargetInfo::getBuiltinVaListKind() const {
TargetInfo::CallingConvCheckResult
WindowsARM64TargetInfo::checkCallingConvention(CallingConv CC) const {
switch (CC) {
+ case CC_X86VectorCall:
+ if (getTriple().isWindowsArm64EC())
+ return CCCR_OK;
+ return CCCR_Ignore;
case CC_X86StdCall:
case CC_X86ThisCall:
case CC_X86FastCall:
- case CC_X86VectorCall:
return CCCR_Ignore;
case CC_C:
case CC_OpenCLKernel:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index f12765b82693..3f5463a9a70e 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -5591,6 +5591,12 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
/*AttrOnCallSite=*/true,
/*IsThunk=*/false);
+ if (CallingConv == llvm::CallingConv::X86_VectorCall &&
+ getTarget().getTriple().isWindowsArm64EC()) {
+ CGM.Error(Loc, "__vectorcall calling convention is not currently "
+ "supported");
+ }
+
if (const FunctionDecl *FD = dyn_cast_or_null<FunctionDecl>(CurFuncDecl)) {
if (FD->hasAttr<StrictFPAttr>())
// All calls within a strictfp function are marked strictfp
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index e6f8e6873004..5bf48bc22a54 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -667,7 +667,8 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// - whether there's a fallthrough
llvm::BasicBlock *FallthroughSource = Builder.GetInsertBlock();
- bool HasFallthrough = (FallthroughSource != nullptr && IsActive);
+ bool HasFallthrough =
+ FallthroughSource != nullptr && (IsActive || HasExistingBranches);
// Branch-through fall-throughs leave the insertion point set to the
// end of the last cleanup, which points to the current scope. The
@@ -692,7 +693,11 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
// If we have a prebranched fallthrough into an inactive normal
// cleanup, rewrite it so that it leads to the appropriate place.
- if (Scope.isNormalCleanup() && HasPrebranchedFallthrough && !IsActive) {
+ if (Scope.isNormalCleanup() && HasPrebranchedFallthrough &&
+ !RequiresNormalCleanup) {
+ // FIXME: Come up with a program which would need forwarding prebranched
+ // fallthrough and add tests. Otherwise delete this and assert against it.
+ assert(!IsActive);
llvm::BasicBlock *prebranchDest;
// If the prebranch is semantically branching through the next
@@ -765,6 +770,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
EmitSehCppScopeEnd();
}
destroyOptimisticNormalEntry(*this, Scope);
+ Scope.MarkEmitted();
EHStack.popCleanup();
} else {
// If we have a fallthrough and no other need for the cleanup,
@@ -781,6 +787,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
destroyOptimisticNormalEntry(*this, Scope);
+ Scope.MarkEmitted();
EHStack.popCleanup();
EmitCleanup(*this, Fn, cleanupFlags, NormalActiveFlag);
@@ -916,6 +923,7 @@ void CodeGenFunction::PopCleanupBlock(bool FallthroughIsBranchThrough) {
}
// IV. Pop the cleanup and emit it.
+ Scope.MarkEmitted();
EHStack.popCleanup();
assert(EHStack.hasNormalCleanups() == HasEnclosingCleanups);
diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h
index 03e4a29d7b3d..c73c97146abc 100644
--- a/clang/lib/CodeGen/CGCleanup.h
+++ b/clang/lib/CodeGen/CGCleanup.h
@@ -16,8 +16,11 @@
#include "EHScopeStack.h"
#include "Address.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SetVector.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
+#include "llvm/IR/Instruction.h"
namespace llvm {
class BasicBlock;
@@ -266,6 +269,51 @@ class alignas(8) EHCleanupScope : public EHScope {
};
mutable struct ExtInfo *ExtInfo;
+ /// Erases auxillary allocas and their usages for an unused cleanup.
+ /// Cleanups should mark these allocas as 'used' if the cleanup is
+ /// emitted, otherwise these instructions would be erased.
+ struct AuxillaryAllocas {
+ SmallVector<llvm::Instruction *, 1> AuxAllocas;
+ bool used = false;
+
+ // Records a potentially unused instruction to be erased later.
+ void Add(llvm::AllocaInst *Alloca) { AuxAllocas.push_back(Alloca); }
+
+ // Mark all recorded instructions as used. These will not be erased later.
+ void MarkUsed() {
+ used = true;
+ AuxAllocas.clear();
+ }
+
+ ~AuxillaryAllocas() {
+ if (used)
+ return;
+ llvm::SetVector<llvm::Instruction *> Uses;
+ for (auto *Inst : llvm::reverse(AuxAllocas))
+ CollectUses(Inst, Uses);
+ // Delete uses in the reverse order of insertion.
+ for (auto *I : llvm::reverse(Uses))
+ I->eraseFromParent();
+ }
+
+ private:
+ void CollectUses(llvm::Instruction *I,
+ llvm::SetVector<llvm::Instruction *> &Uses) {
+ if (!I || !Uses.insert(I))
+ return;
+ for (auto *User : I->users())
+ CollectUses(cast<llvm::Instruction>(User), Uses);
+ }
+ };
+ mutable struct AuxillaryAllocas *AuxAllocas;
+
+ AuxillaryAllocas &getAuxillaryAllocas() {
+ if (!AuxAllocas) {
+ AuxAllocas = new struct AuxillaryAllocas();
+ }
+ return *AuxAllocas;
+ }
+
/// The number of fixups required by enclosing scopes (not including
/// this one). If this is the top cleanup scope, all the fixups
/// from this index onwards belong to this scope.
@@ -298,7 +346,7 @@ public:
EHScopeStack::stable_iterator enclosingEH)
: EHScope(EHScope::Cleanup, enclosingEH),
EnclosingNormal(enclosingNormal), NormalBlock(nullptr),
- ActiveFlag(Address::invalid()), ExtInfo(nullptr),
+ ActiveFlag(Address::invalid()), ExtInfo(nullptr), AuxAllocas(nullptr),
FixupDepth(fixupDepth) {
CleanupBits.IsNormalCleanup = isNormal;
CleanupBits.IsEHCleanup = isEH;
@@ -312,8 +360,15 @@ public:
}
void Destroy() {
+ if (AuxAllocas)
+ delete AuxAllocas;
delete ExtInfo;
}
+ void AddAuxAllocas(llvm::SmallVector<llvm::AllocaInst *> Allocas) {
+ for (auto *Alloca : Allocas)
+ getAuxillaryAllocas().Add(Alloca);
+ }
+ void MarkEmitted() { getAuxillaryAllocas().MarkUsed(); }
// Objects of EHCleanupScope are not destructed. Use Destroy().
~EHCleanupScope() = delete;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 267f2e40a7bb..4f4013292b1f 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -19,6 +19,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
+#include "EHScopeStack.h"
#include "PatternInit.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
@@ -2201,6 +2202,24 @@ void CodeGenFunction::pushDestroy(CleanupKind cleanupKind, Address addr,
destroyer, useEHCleanupForArray);
}
+// Pushes a destroy and defers its deactivation until its
+// CleanupDeactivationScope is exited.
+void CodeGenFunction::pushDestroyAndDeferDeactivation(
+ QualType::DestructionKind dtorKind, Address addr, QualType type) {
+ assert(dtorKind && "cannot push destructor for trivial type");
+
+ CleanupKind cleanupKind = getCleanupKind(dtorKind);
+ pushDestroyAndDeferDeactivation(
+ cleanupKind, addr, type, getDestroyer(dtorKind), cleanupKind & EHCleanup);
+}
+
+void CodeGenFunction::pushDestroyAndDeferDeactivation(
+ CleanupKind cleanupKind, Address addr, QualType type, Destroyer *destroyer,
+ bool useEHCleanupForArray) {
+ pushCleanupAndDeferDeactivation<DestroyObject>(
+ cleanupKind, addr, type, destroyer, useEHCleanupForArray);
+}
+
void CodeGenFunction::pushStackRestore(CleanupKind Kind, Address SPMem) {
EHStack.pushCleanup<CallStackRestore>(Kind, SPMem);
}
@@ -2217,16 +2236,19 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
// If we're not in a conditional branch, we don't need to bother generating a
// conditional cleanup.
if (!isInConditionalBranch()) {
- // Push an EH-only cleanup for the object now.
// FIXME: When popping normal cleanups, we need to keep this EH cleanup
// around in case a temporary's destructor throws an exception.
- if (cleanupKind & EHCleanup)
- EHStack.pushCleanup<DestroyObject>(
- static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), addr, type,
- destroyer, useEHCleanupForArray);
+ // Add the cleanup to the EHStack. After the full-expr, this would be
+ // deactivated before being popped from the stack.
+ pushDestroyAndDeferDeactivation(cleanupKind, addr, type, destroyer,
+ useEHCleanupForArray);
+
+ // Since this is lifetime-extended, push it once again to the EHStack after
+ // the full expression.
return pushCleanupAfterFullExprWithActiveFlag<DestroyObject>(
- cleanupKind, Address::invalid(), addr, type, destroyer, useEHCleanupForArray);
+ cleanupKind, Address::invalid(), addr, type, destroyer,
+ useEHCleanupForArray);
}
// Otherwise, we should only destroy the object if it's been initialized.
@@ -2241,13 +2263,12 @@ void CodeGenFunction::pushLifetimeExtendedDestroy(CleanupKind cleanupKind,
Address ActiveFlag = createCleanupActiveFlag();
SavedType SavedAddr = saveValueInCond(addr);
- if (cleanupKind & EHCleanup) {
- EHStack.pushCleanup<ConditionalCleanupType>(
- static_cast<CleanupKind>(cleanupKind & ~NormalCleanup), SavedAddr, type,
- destroyer, useEHCleanupForArray);
- initFullExprCleanupWithFlag(ActiveFlag);
- }
+ pushCleanupAndDeferDeactivation<ConditionalCleanupType>(
+ cleanupKind, SavedAddr, type, destroyer, useEHCleanupForArray);
+ initFullExprCleanupWithFlag(ActiveFlag);
+ // Since this is lifetime-extended, push it once again to the EHStack after
+ // the full expression.
pushCleanupAfterFullExprWithActiveFlag<ConditionalCleanupType>(
cleanupKind, ActiveFlag, SavedAddr, type, destroyer,
useEHCleanupForArray);
@@ -2442,9 +2463,9 @@ namespace {
};
} // end anonymous namespace
-/// pushIrregularPartialArrayCleanup - Push an EH cleanup to destroy
-/// already-constructed elements of the given array. The cleanup
-/// may be popped with DeactivateCleanupBlock or PopCleanupBlock.
+/// pushIrregularPartialArrayCleanup - Push a NormalAndEHCleanup to
+/// destroy already-constructed elements of the given array. The cleanup may be
+/// popped with DeactivateCleanupBlock or PopCleanupBlock.
///
/// \param elementType - the immediate element type of the array;
/// possibly still an array type
@@ -2453,10 +2474,9 @@ void CodeGenFunction::pushIrregularPartialArrayCleanup(llvm::Value *arrayBegin,
QualType elementType,
CharUnits elementAlign,
Destroyer *destroyer) {
- pushFullExprCleanup<IrregularPartialArrayDestroy>(EHCleanup,
- arrayBegin, arrayEndPointer,
- elementType, elementAlign,
- destroyer);
+ pushFullExprCleanup<IrregularPartialArrayDestroy>(
+ NormalAndEHCleanup, arrayBegin, arrayEndPointer, elementType,
+ elementAlign, destroyer);
}
/// pushRegularPartialArrayCleanup - Push an EH cleanup to destroy
diff --git a/clang/lib/CodeGen/CGExpr.cpp b/clang/lib/CodeGen/CGExpr.cpp
index cf696a1c9f56..c85a339f5e3f 100644
--- a/clang/lib/CodeGen/CGExpr.cpp
+++ b/clang/lib/CodeGen/CGExpr.cpp
@@ -115,10 +115,16 @@ RawAddress CodeGenFunction::CreateTempAlloca(llvm::Type *Ty, CharUnits Align,
llvm::AllocaInst *CodeGenFunction::CreateTempAlloca(llvm::Type *Ty,
const Twine &Name,
llvm::Value *ArraySize) {
+ llvm::AllocaInst *Alloca;
if (ArraySize)
- return Builder.CreateAlloca(Ty, ArraySize, Name);
- return new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
- ArraySize, Name, AllocaInsertPt);
+ Alloca = Builder.CreateAlloca(Ty, ArraySize, Name);
+ else
+ Alloca = new llvm::AllocaInst(Ty, CGM.getDataLayout().getAllocaAddrSpace(),
+ ArraySize, Name, AllocaInsertPt);
+ if (Allocas) {
+ Allocas->Add(Alloca);
+ }
+ return Alloca;
}
/// CreateDefaultAlignTempAlloca - This creates an alloca with the
diff --git a/clang/lib/CodeGen/CGExprAgg.cpp b/clang/lib/CodeGen/CGExprAgg.cpp
index 1b9287ea2393..560a9e2c5ead 100644
--- a/clang/lib/CodeGen/CGExprAgg.cpp
+++ b/clang/lib/CodeGen/CGExprAgg.cpp
@@ -15,6 +15,7 @@
#include "CodeGenFunction.h"
#include "CodeGenModule.h"
#include "ConstantEmitter.h"
+#include "EHScopeStack.h"
#include "TargetInfo.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Attr.h"
@@ -24,6 +25,7 @@
#include "llvm/IR/Constants.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/GlobalVariable.h"
+#include "llvm/IR/Instruction.h"
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Intrinsics.h"
using namespace clang;
@@ -558,24 +560,27 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
// For that, we'll need an EH cleanup.
QualType::DestructionKind dtorKind = elementType.isDestructedType();
Address endOfInit = Address::invalid();
- EHScopeStack::stable_iterator cleanup;
- llvm::Instruction *cleanupDominator = nullptr;
- if (CGF.needsEHCleanup(dtorKind)) {
+ CodeGenFunction::CleanupDeactivationScope deactivation(CGF);
+
+ if (dtorKind) {
+ CodeGenFunction::AllocaTrackerRAII allocaTracker(CGF);
// In principle we could tell the cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
+ llvm::Instruction *dominatingIP =
+ Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(CGF.Int8PtrTy));
endOfInit = CGF.CreateTempAlloca(begin->getType(), CGF.getPointerAlign(),
"arrayinit.endOfInit");
- cleanupDominator = Builder.CreateStore(begin, endOfInit);
+ Builder.CreateStore(begin, endOfInit);
CGF.pushIrregularPartialArrayCleanup(begin, endOfInit, elementType,
elementAlign,
CGF.getDestroyer(dtorKind));
- cleanup = CGF.EHStack.stable_begin();
+ cast<EHCleanupScope>(*CGF.EHStack.find(CGF.EHStack.stable_begin()))
+ .AddAuxAllocas(allocaTracker.Take());
- // Otherwise, remember that we didn't need a cleanup.
- } else {
- dtorKind = QualType::DK_none;
+ CGF.DeferredDeactivationCleanupStack.push_back(
+ {CGF.EHStack.stable_begin(), dominatingIP});
}
llvm::Value *one = llvm::ConstantInt::get(CGF.SizeTy, 1);
@@ -671,9 +676,6 @@ void AggExprEmitter::EmitArrayInit(Address DestPtr, llvm::ArrayType *AType,
CGF.EmitBlock(endBB);
}
-
- // Leave the partial-array cleanup if we entered one.
- if (dtorKind) CGF.DeactivateCleanupBlock(cleanup, cleanupDominator);
}
//===----------------------------------------------------------------------===//
@@ -1374,9 +1376,8 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
LValue SlotLV = CGF.MakeAddrLValue(Slot.getAddress(), E->getType());
// We'll need to enter cleanup scopes in case any of the element
- // initializers throws an exception.
- SmallVector<EHScopeStack::stable_iterator, 16> Cleanups;
- llvm::Instruction *CleanupDominator = nullptr;
+ // initializers throws an exception or contains branch out of the expressions.
+ CodeGenFunction::CleanupDeactivationScope scope(CGF);
CXXRecordDecl::field_iterator CurField = E->getLambdaClass()->field_begin();
for (LambdaExpr::const_capture_init_iterator i = E->capture_init_begin(),
@@ -1395,28 +1396,12 @@ AggExprEmitter::VisitLambdaExpr(LambdaExpr *E) {
if (QualType::DestructionKind DtorKind =
CurField->getType().isDestructedType()) {
assert(LV.isSimple());
- if (CGF.needsEHCleanup(DtorKind)) {
- if (!CleanupDominator)
- CleanupDominator = CGF.Builder.CreateAlignedLoad(
- CGF.Int8Ty,
- llvm::Constant::getNullValue(CGF.Int8PtrTy),
- CharUnits::One()); // placeholder
-
- CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), CurField->getType(),
- CGF.getDestroyer(DtorKind), false);
- Cleanups.push_back(CGF.EHStack.stable_begin());
- }
+ if (DtorKind)
+ CGF.pushDestroyAndDeferDeactivation(
+ NormalAndEHCleanup, LV.getAddress(CGF), CurField->getType(),
+ CGF.getDestroyer(DtorKind), false);
}
}
-
- // Deactivate all the partial cleanups in reverse order, which
- // generally means popping them.
- for (unsigned i = Cleanups.size(); i != 0; --i)
- CGF.DeactivateCleanupBlock(Cleanups[i-1], CleanupDominator);
-
- // Destroy the placeholder if we made one.
- if (CleanupDominator)
- CleanupDominator->eraseFromParent();
}
void AggExprEmitter::VisitExprWithCleanups(ExprWithCleanups *E) {
@@ -1705,14 +1690,7 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
// We'll need to enter cleanup scopes in case any of the element
// initializers throws an exception.
SmallVector<EHScopeStack::stable_iterator, 16> cleanups;
- llvm::Instruction *cleanupDominator = nullptr;
- auto addCleanup = [&](const EHScopeStack::stable_iterator &cleanup) {
- cleanups.push_back(cleanup);
- if (!cleanupDominator) // create placeholder once needed
- cleanupDominator = CGF.Builder.CreateAlignedLoad(
- CGF.Int8Ty, llvm::Constant::getNullValue(CGF.Int8PtrTy),
- CharUnits::One());
- };
+ CodeGenFunction::CleanupDeactivationScope DeactivateCleanups(CGF);
unsigned curInitIndex = 0;
@@ -1735,10 +1713,8 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
CGF.EmitAggExpr(InitExprs[curInitIndex++], AggSlot);
if (QualType::DestructionKind dtorKind =
- Base.getType().isDestructedType()) {
- CGF.pushDestroy(dtorKind, V, Base.getType());
- addCleanup(CGF.EHStack.stable_begin());
- }
+ Base.getType().isDestructedType())
+ CGF.pushDestroyAndDeferDeactivation(dtorKind, V, Base.getType());
}
}
@@ -1813,10 +1789,10 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (QualType::DestructionKind dtorKind
= field->getType().isDestructedType()) {
assert(LV.isSimple());
- if (CGF.needsEHCleanup(dtorKind)) {
- CGF.pushDestroy(EHCleanup, LV.getAddress(CGF), field->getType(),
- CGF.getDestroyer(dtorKind), false);
- addCleanup(CGF.EHStack.stable_begin());
+ if (dtorKind) {
+ CGF.pushDestroyAndDeferDeactivation(
+ NormalAndEHCleanup, LV.getAddress(CGF), field->getType(),
+ CGF.getDestroyer(dtorKind), false);
pushedCleanup = true;
}
}
@@ -1829,17 +1805,6 @@ void AggExprEmitter::VisitCXXParenListOrInitListExpr(
if (GEP->use_empty())
GEP->eraseFromParent();
}
-
- // Deactivate all the partial cleanups in reverse order, which
- // generally means popping them.
- assert((cleanupDominator || cleanups.empty()) &&
- "Missing cleanupDominator before deactivating cleanup blocks");
- for (unsigned i = cleanups.size(); i != 0; --i)
- CGF.DeactivateCleanupBlock(cleanups[i-1], cleanupDominator);
-
- // Destroy the placeholder if we made one.
- if (cleanupDominator)
- cleanupDominator->eraseFromParent();
}
void AggExprEmitter::VisitArrayInitLoopExpr(const ArrayInitLoopExpr *E,
diff --git a/clang/lib/CodeGen/CGExprCXX.cpp b/clang/lib/CodeGen/CGExprCXX.cpp
index a4fb673284ce..a88b29b326bb 100644
--- a/clang/lib/CodeGen/CGExprCXX.cpp
+++ b/clang/lib/CodeGen/CGExprCXX.cpp
@@ -1008,8 +1008,8 @@ void CodeGenFunction::EmitNewArrayInitializer(
const Expr *Init = E->getInitializer();
Address EndOfInit = Address::invalid();
QualType::DestructionKind DtorKind = ElementType.isDestructedType();
- EHScopeStack::stable_iterator Cleanup;
- llvm::Instruction *CleanupDominator = nullptr;
+ CleanupDeactivationScope deactivation(*this);
+ bool pushedCleanup = false;
CharUnits ElementSize = getContext().getTypeSizeInChars(ElementType);
CharUnits ElementAlign =
@@ -1105,19 +1105,24 @@ void CodeGenFunction::EmitNewArrayInitializer(
}
// Enter a partial-destruction Cleanup if necessary.
- if (needsEHCleanup(DtorKind)) {
+ if (DtorKind) {
+ AllocaTrackerRAII AllocaTracker(*this);
// In principle we could tell the Cleanup where we are more
// directly, but the control flow can get so varied here that it
// would actually be quite complex. Therefore we go through an
// alloca.
+ llvm::Instruction *DominatingIP =
+ Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
EndOfInit = CreateTempAlloca(BeginPtr.getType(), getPointerAlign(),
"array.init.end");
- CleanupDominator =
- Builder.CreateStore(BeginPtr.emitRawPointer(*this), EndOfInit);
pushIrregularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
EndOfInit, ElementType, ElementAlign,
getDestroyer(DtorKind));
- Cleanup = EHStack.stable_begin();
+ cast<EHCleanupScope>(*EHStack.find(EHStack.stable_begin()))
+ .AddAuxAllocas(AllocaTracker.Take());
+ DeferredDeactivationCleanupStack.push_back(
+ {EHStack.stable_begin(), DominatingIP});
+ pushedCleanup = true;
}
CharUnits StartAlign = CurPtr.getAlignment();
@@ -1164,9 +1169,6 @@ void CodeGenFunction::EmitNewArrayInitializer(
// initialization.
llvm::ConstantInt *ConstNum = dyn_cast<llvm::ConstantInt>(NumElements);
if (ConstNum && ConstNum->getZExtValue() <= InitListElements) {
- // If there was a Cleanup, deactivate it.
- if (CleanupDominator)
- DeactivateCleanupBlock(Cleanup, CleanupDominator);
return;
}
@@ -1281,13 +1283,14 @@ void CodeGenFunction::EmitNewArrayInitializer(
Builder.CreateStore(CurPtr.emitRawPointer(*this), EndOfInit);
// Enter a partial-destruction Cleanup if necessary.
- if (!CleanupDominator && needsEHCleanup(DtorKind)) {
- llvm::Value *BeginPtrRaw = BeginPtr.emitRawPointer(*this);
- llvm::Value *CurPtrRaw = CurPtr.emitRawPointer(*this);
- pushRegularPartialArrayCleanup(BeginPtrRaw, CurPtrRaw, ElementType,
+ if (!pushedCleanup && needsEHCleanup(DtorKind)) {
+ llvm::Instruction *DominatingIP =
+ Builder.CreateFlagLoad(llvm::ConstantInt::getNullValue(Int8PtrTy));
+ pushRegularPartialArrayCleanup(BeginPtr.emitRawPointer(*this),
+ CurPtr.emitRawPointer(*this), ElementType,
ElementAlign, getDestroyer(DtorKind));
- Cleanup = EHStack.stable_begin();
- CleanupDominator = Builder.CreateUnreachable();
+ DeferredDeactivationCleanupStack.push_back(
+ {EHStack.stable_begin(), DominatingIP});
}
// Emit the initializer into this element.
@@ -1295,10 +1298,7 @@ void CodeGenFunction::EmitNewArrayInitializer(
AggValueSlot::DoesNotOverlap);
// Leave the Cleanup if we entered one.
- if (CleanupDominator) {
- DeactivateCleanupBlock(Cleanup, CleanupDominator);
- CleanupDominator->eraseFromParent();
- }
+ deactivation.ForceDeactivate();
// Advance to the next element by adjusting the pointer type as necessary.
llvm::Value *NextPtr = Builder.CreateConstInBoundsGEP1_32(
diff --git a/clang/lib/CodeGen/CGOpenMPRuntime.cpp b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
index 8eb10584699f..2ae11e129c75 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntime.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntime.cpp
@@ -2656,11 +2656,12 @@ void CGOpenMPRuntime::emitForStaticFinish(CodeGenFunction &CGF,
// Call __kmpc_for_static_fini(ident_t *loc, kmp_int32 tid);
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc,
- isOpenMPDistributeDirective(DKind)
+ isOpenMPDistributeDirective(DKind) ||
+ (DKind == OMPD_target_teams_loop)
? OMP_IDENT_WORK_DISTRIBUTE
- : isOpenMPLoopDirective(DKind)
- ? OMP_IDENT_WORK_LOOP
- : OMP_IDENT_WORK_SECTIONS),
+ : isOpenMPLoopDirective(DKind)
+ ? OMP_IDENT_WORK_LOOP
+ : OMP_IDENT_WORK_SECTIONS),
getThreadID(CGF, Loc)};
auto DL = ApplyDebugLocation::CreateDefaultArtificial(CGF, Loc);
if (isOpenMPDistributeDirective(DKind) &&
@@ -8885,7 +8886,8 @@ getNestedDistributeDirective(ASTContext &Ctx, const OMPExecutableDirective &D) {
OpenMPDirectiveKind DKind = NestedDir->getDirectiveKind();
switch (D.getDirectiveKind()) {
case OMPD_target:
- // For now, just treat 'target teams loop' as if it's distributed.
+ // For now, treat 'target' with nested 'teams loop' as if it's
+ // distributed (target teams distribute).
if (isOpenMPDistributeDirective(DKind) || DKind == OMPD_teams_loop)
return NestedDir;
if (DKind == OMPD_teams) {
@@ -9369,7 +9371,8 @@ llvm::Value *CGOpenMPRuntime::emitTargetNumIterationsCall(
SizeEmitter) {
OpenMPDirectiveKind Kind = D.getDirectiveKind();
const OMPExecutableDirective *TD = &D;
- // Get nested teams distribute kind directive, if any.
+ // Get nested teams distribute kind directive, if any. For now, treat
+ // 'target_teams_loop' as if it's really a target_teams_distribute.
if ((!isOpenMPDistributeDirective(Kind) || !isOpenMPTeamsDirective(Kind)) &&
Kind != OMPD_target_teams_loop)
TD = getNestedDistributeDirective(CGM.getContext(), D);
diff --git a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
index 5baac8f0e3e2..59ba03c6b862 100644
--- a/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
+++ b/clang/lib/CodeGen/CGOpenMPRuntimeGPU.cpp
@@ -646,7 +646,6 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
case OMPD_target:
case OMPD_target_teams:
return hasNestedSPMDDirective(Ctx, D);
- case OMPD_target_teams_loop:
case OMPD_target_parallel_loop:
case OMPD_target_parallel:
case OMPD_target_parallel_for:
@@ -658,6 +657,12 @@ static bool supportsSPMDExecutionMode(ASTContext &Ctx,
return true;
case OMPD_target_teams_distribute:
return false;
+ case OMPD_target_teams_loop:
+ // Whether this is true or not depends on how the directive will
+ // eventually be emitted.
+ if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
+ return TTLD->canBeParallelFor();
+ return false;
case OMPD_parallel:
case OMPD_for:
case OMPD_parallel_for:
diff --git a/clang/lib/CodeGen/CGStmtOpenMP.cpp b/clang/lib/CodeGen/CGStmtOpenMP.cpp
index e6d504bcdeca..3bf99366b69c 100644
--- a/clang/lib/CodeGen/CGStmtOpenMP.cpp
+++ b/clang/lib/CodeGen/CGStmtOpenMP.cpp
@@ -24,6 +24,7 @@
#include "clang/AST/StmtVisitor.h"
#include "clang/Basic/OpenMPKinds.h"
#include "clang/Basic/PrettyStackTrace.h"
+#include "clang/Basic/SourceManager.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/BinaryFormat/Dwarf.h"
#include "llvm/Frontend/OpenMP/OMPConstants.h"
@@ -34,11 +35,14 @@
#include "llvm/IR/IntrinsicInst.h"
#include "llvm/IR/Metadata.h"
#include "llvm/Support/AtomicOrdering.h"
+#include "llvm/Support/Debug.h"
#include <optional>
using namespace clang;
using namespace CodeGen;
using namespace llvm::omp;
+#define TTL_CODEGEN_TYPE "target-teams-loop-codegen"
+
static const VarDecl *getBaseDecl(const Expr *Ref);
namespace {
@@ -1432,9 +1436,12 @@ void CodeGenFunction::EmitOMPReductionClauseFinal(
*this, D.getBeginLoc(),
isOpenMPWorksharingDirective(D.getDirectiveKind()));
}
+ bool TeamsLoopCanBeParallel = false;
+ if (auto *TTLD = dyn_cast<OMPTargetTeamsGenericLoopDirective>(&D))
+ TeamsLoopCanBeParallel = TTLD->canBeParallelFor();
bool WithNowait = D.getSingleClause<OMPNowaitClause>() ||
isOpenMPParallelDirective(D.getDirectiveKind()) ||
- ReductionKind == OMPD_simd;
+ TeamsLoopCanBeParallel || ReductionKind == OMPD_simd;
bool SimpleReduction = ReductionKind == OMPD_simd;
// Emit nowait reduction if nowait clause is present or directive is a
// parallel directive (it always has implicit barrier).
@@ -7928,11 +7935,9 @@ void CodeGenFunction::EmitOMPParallelGenericLoopDirective(
void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
const OMPTeamsGenericLoopDirective &S) {
// To be consistent with current behavior of 'target teams loop', emit
- // 'teams loop' as if its constituent constructs are 'distribute,
- // 'parallel, and 'for'.
+ // 'teams loop' as if its constituent constructs are 'teams' and 'distribute'.
auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
- CGF.EmitOMPDistributeLoop(S, emitInnerParallelForWhenCombined,
- S.getDistInc());
+ CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
};
// Emit teams region as a standalone region.
@@ -7946,15 +7951,33 @@ void CodeGenFunction::EmitOMPTeamsGenericLoopDirective(
CodeGenDistribute);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
- emitCommonOMPTeamsDirective(*this, S, OMPD_distribute_parallel_for, CodeGen);
+ emitCommonOMPTeamsDirective(*this, S, OMPD_distribute, CodeGen);
emitPostUpdateForReductionClause(*this, S,
[](CodeGenFunction &) { return nullptr; });
}
-static void
-emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
- const OMPTargetTeamsGenericLoopDirective &S,
- PrePostActionTy &Action) {
+static void emitTargetTeamsLoopCodegenStatus(CodeGenFunction &CGF,
+ std::string StatusMsg,
+ const OMPExecutableDirective &D) {
+#ifndef NDEBUG
+ bool IsDevice = CGF.CGM.getLangOpts().OpenMPIsTargetDevice;
+ if (IsDevice)
+ StatusMsg += ": DEVICE";
+ else
+ StatusMsg += ": HOST";
+ SourceLocation L = D.getBeginLoc();
+ auto &SM = CGF.getContext().getSourceManager();
+ PresumedLoc PLoc = SM.getPresumedLoc(L);
+ const char *FileName = PLoc.isValid() ? PLoc.getFilename() : nullptr;
+ unsigned LineNo =
+ PLoc.isValid() ? PLoc.getLine() : SM.getExpansionLineNumber(L);
+ llvm::dbgs() << StatusMsg << ": " << FileName << ": " << LineNo << "\n";
+#endif
+}
+
+static void emitTargetTeamsGenericLoopRegionAsParallel(
+ CodeGenFunction &CGF, PrePostActionTy &Action,
+ const OMPTargetTeamsGenericLoopDirective &S) {
Action.Enter(CGF);
// Emit 'teams loop' as if its constituent constructs are 'distribute,
// 'parallel, and 'for'.
@@ -7974,19 +7997,50 @@ emitTargetTeamsGenericLoopRegion(CodeGenFunction &CGF,
CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
};
-
+ DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
+ emitTargetTeamsLoopCodegenStatus(
+ CGF, TTL_CODEGEN_TYPE " as parallel for", S));
emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute_parallel_for,
CodeGenTeams);
emitPostUpdateForReductionClause(CGF, S,
[](CodeGenFunction &) { return nullptr; });
}
-/// Emit combined directive 'target teams loop' as if its constituent
-/// constructs are 'target', 'teams', 'distribute', 'parallel', and 'for'.
+static void emitTargetTeamsGenericLoopRegionAsDistribute(
+ CodeGenFunction &CGF, PrePostActionTy &Action,
+ const OMPTargetTeamsGenericLoopDirective &S) {
+ Action.Enter(CGF);
+ // Emit 'teams loop' as if its constituent construct is 'distribute'.
+ auto &&CodeGenDistribute = [&S](CodeGenFunction &CGF, PrePostActionTy &) {
+ CGF.EmitOMPDistributeLoop(S, emitOMPLoopBodyWithStopPoint, S.getInc());
+ };
+
+ // Emit teams region as a standalone region.
+ auto &&CodeGen = [&S, &CodeGenDistribute](CodeGenFunction &CGF,
+ PrePostActionTy &Action) {
+ Action.Enter(CGF);
+ CodeGenFunction::OMPPrivateScope PrivateScope(CGF);
+ CGF.EmitOMPReductionClauseInit(S, PrivateScope);
+ (void)PrivateScope.Privatize();
+ CGF.CGM.getOpenMPRuntime().emitInlinedDirective(
+ CGF, OMPD_distribute, CodeGenDistribute, /*HasCancel=*/false);
+ CGF.EmitOMPReductionClauseFinal(S, /*ReductionKind=*/OMPD_teams);
+ };
+ DEBUG_WITH_TYPE(TTL_CODEGEN_TYPE,
+ emitTargetTeamsLoopCodegenStatus(
+ CGF, TTL_CODEGEN_TYPE " as distribute", S));
+ emitCommonOMPTeamsDirective(CGF, S, OMPD_distribute, CodeGen);
+ emitPostUpdateForReductionClause(CGF, S,
+ [](CodeGenFunction &) { return nullptr; });
+}
+
void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDirective(
const OMPTargetTeamsGenericLoopDirective &S) {
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsGenericLoopRegion(CGF, S, Action);
+ if (S.canBeParallelFor())
+ emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
+ else
+ emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
};
emitCommonOMPTargetDirective(*this, S, CodeGen);
}
@@ -7996,7 +8050,10 @@ void CodeGenFunction::EmitOMPTargetTeamsGenericLoopDeviceFunction(
const OMPTargetTeamsGenericLoopDirective &S) {
// Emit SPMD target parallel loop region as a standalone region.
auto &&CodeGen = [&S](CodeGenFunction &CGF, PrePostActionTy &Action) {
- emitTargetTeamsGenericLoopRegion(CGF, S, Action);
+ if (S.canBeParallelFor())
+ emitTargetTeamsGenericLoopRegionAsParallel(CGF, Action, S);
+ else
+ emitTargetTeamsGenericLoopRegionAsDistribute(CGF, Action, S);
};
llvm::Function *Fn;
llvm::Constant *Addr;
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index 6474d6c8c1d1..a2d746bb8f4f 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -91,6 +91,8 @@ CodeGenFunction::CodeGenFunction(CodeGenModule &cgm, bool suppressNewContext)
CodeGenFunction::~CodeGenFunction() {
assert(LifetimeExtendedCleanupStack.empty() && "failed to emit a cleanup");
+ assert(DeferredDeactivationCleanupStack.empty() &&
+ "missed to deactivate a cleanup");
if (getLangOpts().OpenMP && CurFn)
CGM.getOpenMPRuntime().functionFinished(*this);
@@ -346,6 +348,10 @@ static void EmitIfUsed(CodeGenFunction &CGF, llvm::BasicBlock *BB) {
void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
assert(BreakContinueStack.empty() &&
"mismatched push/pop in break/continue stack!");
+ assert(LifetimeExtendedCleanupStack.empty() &&
+ "mismatched push/pop of cleanups in EHStack!");
+ assert(DeferredDeactivationCleanupStack.empty() &&
+ "mismatched activate/deactivate of cleanups!");
bool OnlySimpleReturnStmts = NumSimpleReturnExprs > 0
&& NumSimpleReturnExprs == NumReturnExprs
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index ff1873325d40..c49e9fd00c8d 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -39,6 +39,7 @@
#include "llvm/ADT/MapVector.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
+#include "llvm/IR/Instructions.h"
#include "llvm/IR/ValueHandle.h"
#include "llvm/Support/Debug.h"
#include "llvm/Transforms/Utils/SanitizerStats.h"
@@ -670,6 +671,51 @@ public:
EHScopeStack EHStack;
llvm::SmallVector<char, 256> LifetimeExtendedCleanupStack;
+
+ // A stack of cleanups which were added to EHStack but have to be deactivated
+ // later before being popped or emitted. These are usually deactivated on
+ // exiting a `CleanupDeactivationScope` scope. For instance, after a
+ // full-expr.
+ //
+ // These are specially useful for correctly emitting cleanups while
+ // encountering branches out of expression (through stmt-expr or coroutine
+ // suspensions).
+ struct DeferredDeactivateCleanup {
+ EHScopeStack::stable_iterator Cleanup;
+ llvm::Instruction *DominatingIP;
+ };
+ llvm::SmallVector<DeferredDeactivateCleanup> DeferredDeactivationCleanupStack;
+
+ // Enters a new scope for capturing cleanups which are deferred to be
+ // deactivated, all of which will be deactivated once the scope is exited.
+ struct CleanupDeactivationScope {
+ CodeGenFunction &CGF;
+ size_t OldDeactivateCleanupStackSize;
+ bool Deactivated;
+ CleanupDeactivationScope(CodeGenFunction &CGF)
+ : CGF(CGF), OldDeactivateCleanupStackSize(
+ CGF.DeferredDeactivationCleanupStack.size()),
+ Deactivated(false) {}
+
+ void ForceDeactivate() {
+ assert(!Deactivated && "Deactivating already deactivated scope");
+ auto &Stack = CGF.DeferredDeactivationCleanupStack;
+ for (size_t I = Stack.size(); I > OldDeactivateCleanupStackSize; I--) {
+ CGF.DeactivateCleanupBlock(Stack[I - 1].Cleanup,
+ Stack[I - 1].DominatingIP);
+ Stack[I - 1].DominatingIP->eraseFromParent();
+ }
+ Stack.resize(OldDeactivateCleanupStackSize);
+ Deactivated = true;
+ }
+
+ ~CleanupDeactivationScope() {
+ if (Deactivated)
+ return;
+ ForceDeactivate();
+ }
+ };
+
llvm::SmallVector<const JumpDest *, 2> SEHTryEpilogueStack;
llvm::Instruction *CurrentFuncletPad = nullptr;
@@ -875,6 +921,19 @@ public:
new (Buffer + sizeof(Header) + sizeof(T)) RawAddress(ActiveFlag);
}
+ // Push a cleanup onto EHStack and deactivate it later. It is usually
+ // deactivated when exiting a `CleanupDeactivationScope` (for example: after a
+ // full expression).
+ template <class T, class... As>
+ void pushCleanupAndDeferDeactivation(CleanupKind Kind, As... A) {
+ // Placeholder dominating IP for this cleanup.
+ llvm::Instruction *DominatingIP =
+ Builder.CreateFlagLoad(llvm::Constant::getNullValue(Int8PtrTy));
+ EHStack.pushCleanup<T>(Kind, A...);
+ DeferredDeactivationCleanupStack.push_back(
+ {EHStack.stable_begin(), DominatingIP});
+ }
+
/// Set up the last cleanup that was pushed as a conditional
/// full-expression cleanup.
void initFullExprCleanup() {
@@ -926,6 +985,7 @@ public:
class RunCleanupsScope {
EHScopeStack::stable_iterator CleanupStackDepth, OldCleanupScopeDepth;
size_t LifetimeExtendedCleanupStackSize;
+ CleanupDeactivationScope DeactivateCleanups;
bool OldDidCallStackSave;
protected:
bool PerformCleanup;
@@ -940,8 +1000,7 @@ public:
public:
/// Enter a new cleanup scope.
explicit RunCleanupsScope(CodeGenFunction &CGF)
- : PerformCleanup(true), CGF(CGF)
- {
+ : DeactivateCleanups(CGF), PerformCleanup(true), CGF(CGF) {
CleanupStackDepth = CGF.EHStack.stable_begin();
LifetimeExtendedCleanupStackSize =
CGF.LifetimeExtendedCleanupStack.size();
@@ -971,6 +1030,7 @@ public:
void ForceCleanup(std::initializer_list<llvm::Value**> ValuesToReload = {}) {
assert(PerformCleanup && "Already forced cleanup");
CGF.DidCallStackSave = OldDidCallStackSave;
+ DeactivateCleanups.ForceDeactivate();
CGF.PopCleanupBlocks(CleanupStackDepth, LifetimeExtendedCleanupStackSize,
ValuesToReload);
PerformCleanup = false;
@@ -2160,6 +2220,11 @@ public:
Address addr, QualType type);
void pushDestroy(CleanupKind kind, Address addr, QualType type,
Destroyer *destroyer, bool useEHCleanupForArray);
+ void pushDestroyAndDeferDeactivation(QualType::DestructionKind dtorKind,
+ Address addr, QualType type);
+ void pushDestroyAndDeferDeactivation(CleanupKind cleanupKind, Address addr,
+ QualType type, Destroyer *destroyer,
+ bool useEHCleanupForArray);
void pushLifetimeExtendedDestroy(CleanupKind kind, Address addr,
QualType type, Destroyer *destroyer,
bool useEHCleanupForArray);
@@ -2698,6 +2763,33 @@ public:
TBAAAccessInfo *TBAAInfo = nullptr);
LValue EmitLoadOfPointerLValue(Address Ptr, const PointerType *PtrTy);
+private:
+ struct AllocaTracker {
+ void Add(llvm::AllocaInst *I) { Allocas.push_back(I); }
+ llvm::SmallVector<llvm::AllocaInst *> Take() { return std::move(Allocas); }
+
+ private:
+ llvm::SmallVector<llvm::AllocaInst *> Allocas;
+ };
+ AllocaTracker *Allocas = nullptr;
+
+public:
+ // Captures all the allocas created during the scope of its RAII object.
+ struct AllocaTrackerRAII {
+ AllocaTrackerRAII(CodeGenFunction &CGF)
+ : CGF(CGF), OldTracker(CGF.Allocas) {
+ CGF.Allocas = &Tracker;
+ }
+ ~AllocaTrackerRAII() { CGF.Allocas = OldTracker; }
+
+ llvm::SmallVector<llvm::AllocaInst *> Take() { return Tracker.Take(); }
+
+ private:
+ CodeGenFunction &CGF;
+ AllocaTracker *OldTracker;
+ AllocaTracker Tracker;
+ };
+
/// CreateTempAlloca - This creates an alloca and inserts it into the entry
/// block if \p ArraySize is nullptr, otherwise inserts it at the current
/// insertion point of the builder. The caller is responsible for setting an
diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp
index 00b3bfcaa0bc..75519be8bba0 100644
--- a/clang/lib/CodeGen/CodeGenModule.cpp
+++ b/clang/lib/CodeGen/CodeGenModule.cpp
@@ -2087,6 +2087,14 @@ void CodeGenModule::SetLLVMFunctionAttributes(GlobalDecl GD,
llvm::AttributeList PAL;
ConstructAttributeList(F->getName(), Info, GD, PAL, CallingConv,
/*AttrOnCallSite=*/false, IsThunk);
+ if (CallingConv == llvm::CallingConv::X86_VectorCall &&
+ getTarget().getTriple().isWindowsArm64EC()) {
+ SourceLocation Loc;
+ if (const Decl *D = GD.getDecl())
+ Loc = D->getLocation();
+
+ Error(Loc, "__vectorcall calling convention is not currently supported");
+ }
F->setAttributes(PAL);
F->setCallingConv(static_cast<llvm::CallingConv::ID>(CallingConv));
}
diff --git a/clang/lib/CodeGen/Targets/X86.cpp b/clang/lib/CodeGen/Targets/X86.cpp
index c831777699f6..f04db56db335 100644
--- a/clang/lib/CodeGen/Targets/X86.cpp
+++ b/clang/lib/CodeGen/Targets/X86.cpp
@@ -2106,8 +2106,11 @@ void X86_64ABIInfo::classify(QualType Ty, uint64_t OffsetBase, Class &Lo,
postMerge(Size, Lo, Hi);
return;
}
+
+ bool IsInMemory =
+ Offset % getContext().getTypeAlign(i->getType().getCanonicalType());
// Note, skip this test for bit-fields, see below.
- if (!BitField && Offset % getContext().getTypeAlign(i->getType())) {
+ if (!BitField && IsInMemory) {
Lo = Memory;
postMerge(Size, Lo, Hi);
return;
diff --git a/clang/lib/Driver/ToolChains/AMDGPU.cpp b/clang/lib/Driver/ToolChains/AMDGPU.cpp
index e122379e860e..4e6362a0f406 100644
--- a/clang/lib/Driver/ToolChains/AMDGPU.cpp
+++ b/clang/lib/Driver/ToolChains/AMDGPU.cpp
@@ -670,6 +670,10 @@ void amdgpu::getAMDGPUTargetFeatures(const Driver &D,
options::OPT_mno_wavefrontsize64, false))
Features.push_back("+wavefrontsize64");
+ if (Args.hasFlag(options::OPT_mamdgpu_precise_memory_op,
+ options::OPT_mno_amdgpu_precise_memory_op, false))
+ Features.push_back("+precise-memory");
+
handleTargetFeaturesGroup(D, Triple, Args, Features,
options::OPT_m_amdgpu_Features_Group);
}
diff --git a/clang/lib/Driver/ToolChains/Flang.cpp b/clang/lib/Driver/ToolChains/Flang.cpp
index 2c83f70eb788..b00068c8098b 100644
--- a/clang/lib/Driver/ToolChains/Flang.cpp
+++ b/clang/lib/Driver/ToolChains/Flang.cpp
@@ -264,7 +264,7 @@ static void addVSDefines(const ToolChain &TC, const ArgList &Args,
CmdArgs.push_back(Args.MakeArgString("-D_MSC_FULL_VER=" + Twine(ver)));
CmdArgs.push_back(Args.MakeArgString("-D_WIN32"));
- llvm::Triple triple = TC.getTriple();
+ const llvm::Triple &triple = TC.getTriple();
if (triple.isAArch64()) {
CmdArgs.push_back("-D_M_ARM64=1");
} else if (triple.isX86() && triple.isArch32Bit()) {
@@ -589,7 +589,7 @@ static void addFloatingPointOptions(const Driver &D, const ArgList &Args,
if (!HonorINFs && !HonorNaNs && AssociativeMath && ReciprocalMath &&
ApproxFunc && !SignedZeros &&
- (FPContract == "fast" || FPContract == "")) {
+ (FPContract == "fast" || FPContract.empty())) {
CmdArgs.push_back("-ffast-math");
return;
}
@@ -679,7 +679,10 @@ void Flang::ConstructJob(Compilation &C, const JobAction &JA,
CmdArgs.push_back(Args.MakeArgString(TripleStr));
if (isa<PreprocessJobAction>(JA)) {
- CmdArgs.push_back("-E");
+ CmdArgs.push_back("-E");
+ if (Args.getLastArg(options::OPT_dM)) {
+ CmdArgs.push_back("-dM");
+ }
} else if (isa<CompileJobAction>(JA) || isa<BackendJobAction>(JA)) {
if (JA.getType() == types::TY_Nothing) {
CmdArgs.push_back("-fsyntax-only");
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
index 9abd4282103b..628f70417866 100644
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -2354,7 +2354,8 @@ private:
// Line.MightBeFunctionDecl can only be true after the parentheses of a
// function declaration have been found. In this case, 'Current' is a
// trailing token of this declaration and thus cannot be a name.
- if (Current.is(Keywords.kw_instanceof)) {
+ if ((Style.isJavaScript() || Style.Language == FormatStyle::LK_Java) &&
+ Current.is(Keywords.kw_instanceof)) {
Current.setType(TT_BinaryOperator);
} else if (isStartOfName(Current) &&
(!Line.MightBeFunctionDecl || Current.NestingLevel != 0)) {
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
index af57b1420c6e..c1f7e2874beb 100644
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -538,16 +538,6 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
if (Style.Language == FormatStyle::LK_Proto) {
ProbablyBracedList = NextTok->isOneOf(tok::comma, tok::r_square);
} else {
- // Skip NextTok over preprocessor lines, otherwise we may not
- // properly diagnose the block as a braced intializer
- // if the comma separator appears after the pp directive.
- while (NextTok->is(tok::hash)) {
- ScopedMacroState MacroState(*Line, Tokens, NextTok);
- do {
- NextTok = Tokens->getNextToken();
- } while (NextTok->isNot(tok::eof));
- }
-
// Using OriginalColumn to distinguish between ObjC methods and
// binary operators is a bit hacky.
bool NextIsObjCMethod = NextTok->isOneOf(tok::plus, tok::minus) &&
@@ -606,6 +596,16 @@ void UnwrappedLineParser::calculateBraceTypes(bool ExpectClassBody) {
NextTok = Tokens->getNextToken();
ProbablyBracedList = NextTok->isNot(tok::l_square);
}
+
+ // Cpp macro definition body that is a nonempty braced list or block:
+ if (IsCpp && Line->InMacroBody && PrevTok != FormatTok &&
+ !FormatTok->Previous && NextTok->is(tok::eof) &&
+ // A statement can end with only `;` (simple statement), a block
+ // closing brace (compound statement), or `:` (label statement).
+ // If PrevTok is a block opening brace, Tok ends an empty block.
+ !PrevTok->isOneOf(tok::semi, BK_Block, tok::colon)) {
+ ProbablyBracedList = true;
+ }
}
if (ProbablyBracedList) {
Tok->setBlockKind(BK_BracedInit);
diff --git a/clang/lib/Headers/intrin.h b/clang/lib/Headers/intrin.h
index e890dcd7feeb..7eb6dceaabfa 100644
--- a/clang/lib/Headers/intrin.h
+++ b/clang/lib/Headers/intrin.h
@@ -26,7 +26,7 @@
#include <armintr.h>
#endif
-#if defined(__aarch64__)
+#if defined(__aarch64__) || defined(__arm64ec__)
#include <arm64intr.h>
#endif
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index ae23cb432c43..d08e675604d1 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -30,6 +30,7 @@
#include "clang/Sema/EnterExpressionEvaluationContext.h"
#include "clang/Sema/ParsedTemplate.h"
#include "clang/Sema/Scope.h"
+#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TypoCorrection.h"
#include "llvm/ADT/SmallVector.h"
#include <optional>
@@ -2490,8 +2491,8 @@ ExprResult Parser::ParseSYCLUniqueStableNameExpression() {
if (T.consumeClose())
return ExprError();
- return Actions.ActOnSYCLUniqueStableNameExpr(OpLoc, T.getOpenLocation(),
- T.getCloseLocation(), Ty.get());
+ return Actions.SYCL().ActOnUniqueStableNameExpr(
+ OpLoc, T.getOpenLocation(), T.getCloseLocation(), Ty.get());
}
/// Parse a sizeof or alignof expression.
diff --git a/clang/lib/Parse/ParseOpenACC.cpp b/clang/lib/Parse/ParseOpenACC.cpp
index f434e1542c80..b487a1968d1e 100644
--- a/clang/lib/Parse/ParseOpenACC.cpp
+++ b/clang/lib/Parse/ParseOpenACC.cpp
@@ -831,16 +831,19 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
ConsumeToken();
- if (getOpenACCDefaultClauseKind(DefKindTok) ==
- OpenACCDefaultClauseKind::Invalid)
+ OpenACCDefaultClauseKind DefKind =
+ getOpenACCDefaultClauseKind(DefKindTok);
+
+ if (DefKind == OpenACCDefaultClauseKind::Invalid)
Diag(DefKindTok, diag::err_acc_invalid_default_clause_kind);
+ else
+ ParsedClause.setDefaultDetails(DefKind);
break;
}
case OpenACCClauseKind::If: {
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
- // An invalid expression can be just about anything, so just give up on
- // this clause list.
+
if (CondExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
@@ -962,8 +965,7 @@ Parser::OpenACCClauseParseResult Parser::ParseOpenACCClauseParams(
case OpenACCClauseKind::Self: {
assert(DirKind != OpenACCDirectiveKind::Update);
ExprResult CondExpr = ParseOpenACCConditionalExpr(*this);
- // An invalid expression can be just about anything, so just give up on
- // this clause list.
+
if (CondExpr.isInvalid()) {
Parens.skipToEnd();
return OpenACCCanContinue();
diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp
index 04eadb5f3b8a..801b03a63dbc 100644
--- a/clang/lib/Sema/Sema.cpp
+++ b/clang/lib/Sema/Sema.cpp
@@ -45,6 +45,7 @@
#include "clang/Sema/SemaHLSL.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenACC.h"
+#include "clang/Sema/SemaSYCL.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "clang/Sema/TypoCorrection.h"
@@ -201,6 +202,7 @@ Sema::Sema(Preprocessor &pp, ASTContext &ctxt, ASTConsumer &consumer,
CurScope(nullptr), Ident_super(nullptr),
HLSLPtr(std::make_unique<SemaHLSL>(*this)),
OpenACCPtr(std::make_unique<SemaOpenACC>(*this)),
+ SYCLPtr(std::make_unique<SemaSYCL>(*this)),
MSPointerToMemberRepresentationMethod(
LangOpts.getMSPointerToMemberRepresentationMethod()),
MSStructPragmaOn(false), VtorDispStack(LangOpts.getVtorDispMode()),
@@ -1903,7 +1905,7 @@ Sema::targetDiag(SourceLocation Loc, unsigned DiagID, const FunctionDecl *FD) {
: CUDADiagIfHostCode(Loc, DiagID);
if (getLangOpts().SYCLIsDevice)
- return SYCLDiagIfDeviceCode(Loc, DiagID);
+ return SYCL().DiagIfDeviceCode(Loc, DiagID);
return SemaDiagnosticBuilder(SemaDiagnosticBuilder::K_Immediate, Loc, DiagID,
FD, *this);
@@ -1919,7 +1921,7 @@ void Sema::checkTypeSupport(QualType Ty, SourceLocation Loc, ValueDecl *D) {
// constant byte size like zero length arrays. So, do a deep check for SYCL.
if (D && LangOpts.SYCLIsDevice) {
llvm::DenseSet<QualType> Visited;
- deepTypeCheckForSYCLDevice(Loc, Visited, D);
+ SYCL().deepTypeCheckForDevice(Loc, Visited, D);
}
Decl *C = cast<Decl>(getCurLexicalContext());
diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp
index b84a779b7189..abfd9a303157 100644
--- a/clang/lib/Sema/SemaChecking.cpp
+++ b/clang/lib/Sema/SemaChecking.cpp
@@ -7938,6 +7938,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
// For variadic functions, we may have more args than parameters.
// For some K&R functions, we may have less args than parameters.
const auto N = std::min<unsigned>(Proto->getNumParams(), Args.size());
+ bool AnyScalableArgsOrRet = Proto->getReturnType()->isSizelessVectorType();
for (unsigned ArgIdx = 0; ArgIdx < N; ++ArgIdx) {
// Args[ArgIdx] can be null in malformed code.
if (const Expr *Arg = Args[ArgIdx]) {
@@ -7951,6 +7952,8 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
checkAIXMemberAlignment((Arg->getExprLoc()), Arg);
QualType ParamTy = Proto->getParamType(ArgIdx);
+ if (ParamTy->isSizelessVectorType())
+ AnyScalableArgsOrRet = true;
QualType ArgTy = Arg->getType();
CheckArgAlignment(Arg->getExprLoc(), FDecl, std::to_string(ArgIdx + 1),
ArgTy, ParamTy);
@@ -7971,6 +7974,23 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
}
}
+ // If the call requires a streaming-mode change and has scalable vector
+ // arguments or return values, then warn the user that the streaming and
+ // non-streaming vector lengths may be different.
+ const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext);
+ if (CallerFD && (!FD || !FD->getBuiltinID()) && AnyScalableArgsOrRet) {
+ bool IsCalleeStreaming =
+ ExtInfo.AArch64SMEAttributes & FunctionType::SME_PStateSMEnabledMask;
+ bool IsCalleeStreamingCompatible =
+ ExtInfo.AArch64SMEAttributes &
+ FunctionType::SME_PStateSMCompatibleMask;
+ ArmStreamingType CallerFnType = getArmStreamingFnType(CallerFD);
+ if (!IsCalleeStreamingCompatible &&
+ (CallerFnType == ArmStreamingCompatible ||
+ ((CallerFnType == ArmStreaming) ^ IsCalleeStreaming)))
+ Diag(Loc, diag::warn_sme_streaming_pass_return_vl_to_non_streaming);
+ }
+
FunctionType::ArmStateValue CalleeArmZAState =
FunctionType::getArmZAState(ExtInfo.AArch64SMEAttributes);
FunctionType::ArmStateValue CalleeArmZT0State =
@@ -7979,7 +7999,7 @@ void Sema::checkCall(NamedDecl *FDecl, const FunctionProtoType *Proto,
CalleeArmZT0State != FunctionType::ARM_None) {
bool CallerHasZAState = false;
bool CallerHasZT0State = false;
- if (const auto *CallerFD = dyn_cast<FunctionDecl>(CurContext)) {
+ if (CallerFD) {
auto *Attr = CallerFD->getAttr<ArmNewAttr>();
if (Attr && Attr->isNewZA())
CallerHasZAState = true;
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index c790dab72dd7..8472aaeb6bad 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -12395,12 +12395,22 @@ bool Sema::CheckFunctionDeclaration(Scope *S, FunctionDecl *NewFD,
}
// Check if the function definition uses any AArch64 SME features without
- // having the '+sme' feature enabled.
+ // having the '+sme' feature enabled and warn user if sme locally streaming
+ // function returns or uses arguments with VL-based types.
if (DeclIsDefn) {
const auto *Attr = NewFD->getAttr<ArmNewAttr>();
bool UsesSM = NewFD->hasAttr<ArmLocallyStreamingAttr>();
bool UsesZA = Attr && Attr->isNewZA();
bool UsesZT0 = Attr && Attr->isNewZT0();
+
+ if (NewFD->hasAttr<ArmLocallyStreamingAttr>()) {
+ if (NewFD->getReturnType()->isSizelessVectorType() ||
+ llvm::any_of(NewFD->parameters(), [](ParmVarDecl *P) {
+ return P->getOriginalType()->isSizelessVectorType();
+ }))
+ Diag(NewFD->getLocation(),
+ diag::warn_sme_locally_streaming_has_vl_args_returns);
+ }
if (const auto *FPT = NewFD->getType()->getAs<FunctionProtoType>()) {
FunctionProtoType::ExtProtoInfo EPI = FPT->getExtProtoInfo();
UsesSM |=
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 45acbf197ea6..4d4ef9b16381 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -3442,11 +3442,10 @@ static bool ShouldLookupResultBeMultiVersionOverload(const LookupResult &R) {
ExprResult Sema::BuildDeclarationNameExpr(const CXXScopeSpec &SS,
LookupResult &R, bool NeedsADL,
- bool AcceptInvalidDecl,
- bool NeedUnresolved) {
+ bool AcceptInvalidDecl) {
// If this is a single, fully-resolved result and we don't need ADL,
// just build an ordinary singleton decl ref.
- if (!NeedUnresolved && !NeedsADL && R.isSingleResult() &&
+ if (!NeedsADL && R.isSingleResult() &&
!R.getAsSingle<FunctionTemplateDecl>() &&
!ShouldLookupResultBeMultiVersionOverload(R))
return BuildDeclarationNameExpr(SS, R.getLookupNameInfo(), R.getFoundDecl(),
@@ -3795,28 +3794,6 @@ ExprResult Sema::BuildPredefinedExpr(SourceLocation Loc,
SL);
}
-ExprResult Sema::BuildSYCLUniqueStableNameExpr(SourceLocation OpLoc,
- SourceLocation LParen,
- SourceLocation RParen,
- TypeSourceInfo *TSI) {
- return SYCLUniqueStableNameExpr::Create(Context, OpLoc, LParen, RParen, TSI);
-}
-
-ExprResult Sema::ActOnSYCLUniqueStableNameExpr(SourceLocation OpLoc,
- SourceLocation LParen,
- SourceLocation RParen,
- ParsedType ParsedTy) {
- TypeSourceInfo *TSI = nullptr;
- QualType Ty = GetTypeFromParser(ParsedTy, &TSI);
-
- if (Ty.isNull())
- return ExprError();
- if (!TSI)
- TSI = Context.getTrivialTypeSourceInfo(Ty, LParen);
-
- return BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
-}
-
ExprResult Sema::ActOnPredefinedExpr(SourceLocation Loc, tok::TokenKind Kind) {
return BuildPredefinedExpr(Loc, getPredefinedExprKind(Kind));
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 80c01b14379c..7b9b8f149d9e 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1415,42 +1415,26 @@ bool Sema::CheckCXXThisCapture(SourceLocation Loc, const bool Explicit,
}
ExprResult Sema::ActOnCXXThis(SourceLocation Loc) {
- // C++20 [expr.prim.this]p1:
- // The keyword this names a pointer to the object for which an
- // implicit object member function is invoked or a non-static
- // data member's initializer is evaluated.
+ /// C++ 9.3.2: In the body of a non-static member function, the keyword this
+ /// is a non-lvalue expression whose value is the address of the object for
+ /// which the function is called.
QualType ThisTy = getCurrentThisType();
- if (CheckCXXThisType(Loc, ThisTy))
- return ExprError();
+ if (ThisTy.isNull()) {
+ DeclContext *DC = getFunctionLevelDeclContext();
- return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
-}
+ if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
+ Method && Method->isExplicitObjectMemberFunction()) {
+ return Diag(Loc, diag::err_invalid_this_use) << 1;
+ }
-bool Sema::CheckCXXThisType(SourceLocation Loc, QualType Type) {
- if (!Type.isNull())
- return false;
+ if (isLambdaCallWithExplicitObjectParameter(CurContext))
+ return Diag(Loc, diag::err_invalid_this_use) << 1;
- // C++20 [expr.prim.this]p3:
- // If a declaration declares a member function or member function template
- // of a class X, the expression this is a prvalue of type
- // "pointer to cv-qualifier-seq X" wherever X is the current class between
- // the optional cv-qualifier-seq and the end of the function-definition,
- // member-declarator, or declarator. It shall not appear within the
- // declaration of either a static member function or an explicit object
- // member function of the current class (although its type and value
- // category are defined within such member functions as they are within
- // an implicit object member function).
- DeclContext *DC = getFunctionLevelDeclContext();
- if (const auto *Method = dyn_cast<CXXMethodDecl>(DC);
- Method && Method->isExplicitObjectMemberFunction()) {
- Diag(Loc, diag::err_invalid_this_use) << 1;
- } else if (isLambdaCallWithExplicitObjectParameter(CurContext)) {
- Diag(Loc, diag::err_invalid_this_use) << 1;
- } else {
- Diag(Loc, diag::err_invalid_this_use) << 0;
+ return Diag(Loc, diag::err_invalid_this_use) << 0;
}
- return true;
+
+ return BuildCXXThisExpr(Loc, ThisTy, /*IsImplicit=*/false);
}
Expr *Sema::BuildCXXThisExpr(SourceLocation Loc, QualType Type,
@@ -5895,7 +5879,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
return false;
if (Self.RequireCompleteType(
- KeyLoc, RhsT, diag::err_incomplete_type_used_in_type_trait_expr))
+ Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
return false;
return BaseInterface->isSuperClassOf(DerivedInterface);
@@ -5918,8 +5903,9 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
// If Base and Derived are class types and are different types
// (ignoring possible cv-qualifiers) then Derived shall be a
// complete type.
- if (Self.RequireCompleteType(KeyLoc, RhsT,
- diag::err_incomplete_type_used_in_type_trait_expr))
+ if (Self.RequireCompleteType(
+ Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
return false;
return cast<CXXRecordDecl>(rhsRecord->getDecl())
@@ -5971,7 +5957,8 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
return LhsT->isVoidType();
// A function definition requires a complete, non-abstract return type.
- if (!Self.isCompleteType(KeyLoc, RhsT) || Self.isAbstractType(KeyLoc, RhsT))
+ if (!Self.isCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT) ||
+ Self.isAbstractType(Rhs->getTypeLoc().getBeginLoc(), RhsT))
return false;
// Compute the result of add_rvalue_reference.
@@ -6021,12 +6008,14 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
// For both, T and U shall be complete types, (possibly cv-qualified)
// void, or arrays of unknown bound.
if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType() &&
- Self.RequireCompleteType(KeyLoc, LhsT,
- diag::err_incomplete_type_used_in_type_trait_expr))
+ Self.RequireCompleteType(
+ Lhs->getTypeLoc().getBeginLoc(), LhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
return false;
if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType() &&
- Self.RequireCompleteType(KeyLoc, RhsT,
- diag::err_incomplete_type_used_in_type_trait_expr))
+ Self.RequireCompleteType(
+ Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type_used_in_type_trait_expr))
return false;
// cv void is never assignable.
@@ -6081,12 +6070,17 @@ static bool EvaluateBinaryTypeTrait(Sema &Self, TypeTrait BTT, const TypeSourceI
}
case BTT_IsLayoutCompatible: {
if (!LhsT->isVoidType() && !LhsT->isIncompleteArrayType())
- Self.RequireCompleteType(KeyLoc, LhsT, diag::err_incomplete_type);
+ Self.RequireCompleteType(Lhs->getTypeLoc().getBeginLoc(), LhsT,
+ diag::err_incomplete_type);
if (!RhsT->isVoidType() && !RhsT->isIncompleteArrayType())
- Self.RequireCompleteType(KeyLoc, RhsT, diag::err_incomplete_type);
+ Self.RequireCompleteType(Rhs->getTypeLoc().getBeginLoc(), RhsT,
+ diag::err_incomplete_type);
- if (LhsT->isVariableArrayType() || RhsT->isVariableArrayType())
- Self.Diag(KeyLoc, diag::err_vla_unsupported)
+ if (LhsT->isVariableArrayType())
+ Self.Diag(Lhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
+ << 1 << tok::kw___is_layout_compatible;
+ if (RhsT->isVariableArrayType())
+ Self.Diag(Rhs->getTypeLoc().getBeginLoc(), diag::err_vla_unsupported)
<< 1 << tok::kw___is_layout_compatible;
return Self.IsLayoutCompatible(LhsT, RhsT);
}
diff --git a/clang/lib/Sema/SemaExprMember.cpp b/clang/lib/Sema/SemaExprMember.cpp
index 8cd2288d279c..32998ae60eaf 100644
--- a/clang/lib/Sema/SemaExprMember.cpp
+++ b/clang/lib/Sema/SemaExprMember.cpp
@@ -61,10 +61,6 @@ enum IMAKind {
/// The reference is a contextually-permitted abstract member reference.
IMA_Abstract,
- /// Whether the context is static is dependent on the enclosing template (i.e.
- /// in a dependent class scope explicit specialization).
- IMA_Dependent,
-
/// The reference may be to an unresolved using declaration and the
/// context is not an instance method.
IMA_Unresolved_StaticOrExplicitContext,
@@ -95,18 +91,10 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
DeclContext *DC = SemaRef.getFunctionLevelDeclContext();
- bool couldInstantiateToStatic = false;
- bool isStaticOrExplicitContext = SemaRef.CXXThisTypeOverride.isNull();
-
- if (auto *MD = dyn_cast<CXXMethodDecl>(DC)) {
- if (MD->isImplicitObjectMemberFunction()) {
- isStaticOrExplicitContext = false;
- // A dependent class scope function template explicit specialization
- // that is neither declared 'static' nor with an explicit object
- // parameter could instantiate to a static or non-static member function.
- couldInstantiateToStatic = MD->getDependentSpecializationInfo();
- }
- }
+ bool isStaticOrExplicitContext =
+ SemaRef.CXXThisTypeOverride.isNull() &&
+ (!isa<CXXMethodDecl>(DC) || cast<CXXMethodDecl>(DC)->isStatic() ||
+ cast<CXXMethodDecl>(DC)->isExplicitObjectMemberFunction());
if (R.isUnresolvableResult())
return isStaticOrExplicitContext ? IMA_Unresolved_StaticOrExplicitContext
@@ -135,9 +123,6 @@ static IMAKind ClassifyImplicitMemberAccess(Sema &SemaRef,
if (Classes.empty())
return IMA_Static;
- if (couldInstantiateToStatic)
- return IMA_Dependent;
-
// C++11 [expr.prim.general]p12:
// An id-expression that denotes a non-static data member or non-static
// member function of a class can only be used:
@@ -283,30 +268,27 @@ ExprResult Sema::BuildPossibleImplicitMemberExpr(
const CXXScopeSpec &SS, SourceLocation TemplateKWLoc, LookupResult &R,
const TemplateArgumentListInfo *TemplateArgs, const Scope *S,
UnresolvedLookupExpr *AsULE) {
- switch (IMAKind Classification = ClassifyImplicitMemberAccess(*this, R)) {
+ switch (ClassifyImplicitMemberAccess(*this, R)) {
case IMA_Instance:
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, true, S);
+
case IMA_Mixed:
case IMA_Mixed_Unrelated:
case IMA_Unresolved:
- return BuildImplicitMemberExpr(
- SS, TemplateKWLoc, R, TemplateArgs,
- /*IsKnownInstance=*/Classification == IMA_Instance, S);
+ return BuildImplicitMemberExpr(SS, TemplateKWLoc, R, TemplateArgs, false,
+ S);
+
case IMA_Field_Uneval_Context:
Diag(R.getNameLoc(), diag::warn_cxx98_compat_non_static_member_use)
<< R.getLookupNameInfo().getName();
[[fallthrough]];
case IMA_Static:
case IMA_Abstract:
- case IMA_Dependent:
case IMA_Mixed_StaticOrExplicitContext:
case IMA_Unresolved_StaticOrExplicitContext:
if (TemplateArgs || TemplateKWLoc.isValid())
- return BuildTemplateIdExpr(SS, TemplateKWLoc, R, /*RequiresADL=*/false,
- TemplateArgs);
- return AsULE ? AsULE
- : BuildDeclarationNameExpr(
- SS, R, /*NeedsADL=*/false, /*AcceptInvalidDecl=*/false,
- /*NeedUnresolved=*/Classification == IMA_Dependent);
+ return BuildTemplateIdExpr(SS, TemplateKWLoc, R, false, TemplateArgs);
+ return AsULE ? AsULE : BuildDeclarationNameExpr(SS, R, false);
case IMA_Error_StaticOrExplicitContext:
case IMA_Error_Unrelated:
diff --git a/clang/lib/Sema/SemaOpenACC.cpp b/clang/lib/Sema/SemaOpenACC.cpp
index 2ba1e49b5739..a6f4453e525d 100644
--- a/clang/lib/Sema/SemaOpenACC.cpp
+++ b/clang/lib/Sema/SemaOpenACC.cpp
@@ -39,11 +39,27 @@ bool diagnoseConstructAppertainment(SemaOpenACC &S, OpenACCDirectiveKind K,
bool doesClauseApplyToDirective(OpenACCDirectiveKind DirectiveKind,
OpenACCClauseKind ClauseKind) {
- // FIXME: For each clause as we implement them, we can add the
- // 'legalization' list here.
-
- // Do nothing so we can go to the 'unimplemented' diagnostic instead.
- return true;
+ switch (ClauseKind) {
+ // FIXME: For each clause as we implement them, we can add the
+ // 'legalization' list here.
+ case OpenACCClauseKind::Default:
+ switch (DirectiveKind) {
+ case OpenACCDirectiveKind::Parallel:
+ case OpenACCDirectiveKind::Serial:
+ case OpenACCDirectiveKind::Kernels:
+ case OpenACCDirectiveKind::ParallelLoop:
+ case OpenACCDirectiveKind::SerialLoop:
+ case OpenACCDirectiveKind::KernelsLoop:
+ case OpenACCDirectiveKind::Data:
+ return true;
+ default:
+ return false;
+ }
+ default:
+ // Do nothing so we can go to the 'unimplemented' diagnostic instead.
+ return true;
+ }
+ llvm_unreachable("Invalid clause kind");
}
} // namespace
@@ -63,8 +79,43 @@ SemaOpenACC::ActOnClause(ArrayRef<const OpenACCClause *> ExistingClauses,
return nullptr;
}
- // TODO OpenACC: Switch over the clauses we implement here and 'create'
- // them.
+ switch (Clause.getClauseKind()) {
+ case OpenACCClauseKind::Default: {
+ // Restrictions only properly implemented on 'compute' constructs, and
+ // 'compute' constructs are the only construct that can do anything with
+ // this yet, so skip/treat as unimplemented in this case.
+ if (Clause.getDirectiveKind() != OpenACCDirectiveKind::Parallel &&
+ Clause.getDirectiveKind() != OpenACCDirectiveKind::Serial &&
+ Clause.getDirectiveKind() != OpenACCDirectiveKind::Kernels)
+ break;
+
+ // Don't add an invalid clause to the AST.
+ if (Clause.getDefaultClauseKind() == OpenACCDefaultClauseKind::Invalid)
+ return nullptr;
+
+ // OpenACC 3.3, Section 2.5.4:
+ // At most one 'default' clause may appear, and it must have a value of
+ // either 'none' or 'present'.
+ // Second half of the sentence is diagnosed during parsing.
+ auto Itr = llvm::find_if(ExistingClauses, [](const OpenACCClause *C) {
+ return C->getClauseKind() == OpenACCClauseKind::Default;
+ });
+
+ if (Itr != ExistingClauses.end()) {
+ Diag(Clause.getBeginLoc(),
+ diag::err_acc_duplicate_clause_disallowed)
+ << Clause.getDirectiveKind() << Clause.getClauseKind();
+ Diag((*Itr)->getBeginLoc(), diag::note_acc_previous_clause_here);
+ return nullptr;
+ }
+
+ return OpenACCDefaultClause::Create(
+ getASTContext(), Clause.getDefaultClauseKind(), Clause.getBeginLoc(),
+ Clause.getLParenLoc(), Clause.getEndLoc());
+ }
+ default:
+ break;
+ }
Diag(Clause.getBeginLoc(), diag::warn_acc_clause_unimplemented)
<< Clause.getClauseKind();
diff --git a/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp
index 0ba54a3a9cae..c814535ad6bd 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -4478,6 +4478,8 @@ void Sema::ActOnOpenMPRegionStart(OpenMPDirectiveKind DKind, Scope *CurScope) {
Params);
break;
}
+ // For 'target teams loop', collect all captured regions so codegen can
+ // later decide the best IR to emit given the associated loop-nest.
case OMPD_target_teams_loop:
case OMPD_target_teams_distribute_parallel_for:
case OMPD_target_teams_distribute_parallel_for_simd: {
@@ -6135,6 +6137,79 @@ processImplicitMapsWithDefaultMappers(Sema &S, DSAStackTy *Stack,
}
}
+namespace {
+/// A 'teams loop' with a nested 'loop bind(parallel)' or generic function
+/// call in the associated loop-nest cannot be a 'parallel for'.
+class TeamsLoopChecker final : public ConstStmtVisitor<TeamsLoopChecker> {
+ Sema &SemaRef;
+
+public:
+ bool teamsLoopCanBeParallelFor() const { return TeamsLoopCanBeParallelFor; }
+
+ // Is there a nested OpenMP loop bind(parallel)
+ void VisitOMPExecutableDirective(const OMPExecutableDirective *D) {
+ if (D->getDirectiveKind() == llvm::omp::Directive::OMPD_loop) {
+ if (const auto *C = D->getSingleClause<OMPBindClause>())
+ if (C->getBindKind() == OMPC_BIND_parallel) {
+ TeamsLoopCanBeParallelFor = false;
+ // No need to continue visiting any more
+ return;
+ }
+ }
+ for (const Stmt *Child : D->children())
+ if (Child)
+ Visit(Child);
+ }
+
+ void VisitCallExpr(const CallExpr *C) {
+ // Function calls inhibit parallel loop translation of 'target teams loop'
+ // unless the assume-no-nested-parallelism flag has been specified.
+ // OpenMP API runtime library calls do not inhibit parallel loop
+ // translation, regardless of the assume-no-nested-parallelism.
+ if (C) {
+ bool IsOpenMPAPI = false;
+ auto *FD = dyn_cast_or_null<FunctionDecl>(C->getCalleeDecl());
+ if (FD) {
+ std::string Name = FD->getNameInfo().getAsString();
+ IsOpenMPAPI = Name.find("omp_") == 0;
+ }
+ TeamsLoopCanBeParallelFor =
+ IsOpenMPAPI || SemaRef.getLangOpts().OpenMPNoNestedParallelism;
+ if (!TeamsLoopCanBeParallelFor)
+ return;
+ }
+ for (const Stmt *Child : C->children())
+ if (Child)
+ Visit(Child);
+ }
+
+ void VisitCapturedStmt(const CapturedStmt *S) {
+ if (!S)
+ return;
+ Visit(S->getCapturedDecl()->getBody());
+ }
+
+ void VisitStmt(const Stmt *S) {
+ if (!S)
+ return;
+ for (const Stmt *Child : S->children())
+ if (Child)
+ Visit(Child);
+ }
+ explicit TeamsLoopChecker(Sema &SemaRef)
+ : SemaRef(SemaRef), TeamsLoopCanBeParallelFor(true) {}
+
+private:
+ bool TeamsLoopCanBeParallelFor;
+};
+} // namespace
+
+static bool teamsLoopCanBeParallelFor(Stmt *AStmt, Sema &SemaRef) {
+ TeamsLoopChecker Checker(SemaRef);
+ Checker.Visit(AStmt);
+ return Checker.teamsLoopCanBeParallelFor();
+}
+
bool Sema::mapLoopConstruct(llvm::SmallVector<OMPClause *> &ClausesWithoutBind,
ArrayRef<OMPClause *> Clauses,
OpenMPBindClauseKind &BindKind,
@@ -10895,7 +10970,8 @@ StmtResult Sema::ActOnOpenMPTargetTeamsGenericLoopDirective(
setFunctionHasBranchProtectedScope();
return OMPTargetTeamsGenericLoopDirective::Create(
- Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B);
+ Context, StartLoc, EndLoc, NestedLoopCount, Clauses, AStmt, B,
+ teamsLoopCanBeParallelFor(AStmt, *this));
}
StmtResult Sema::ActOnOpenMPParallelGenericLoopDirective(
@@ -15645,6 +15721,12 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
if (NameModifier == OMPD_unknown || NameModifier == OMPD_parallel)
CaptureRegion = OMPD_target;
break;
+ case OMPD_teams_loop:
+ case OMPD_target_teams_loop:
+ // For [target] teams loop, assume capture region is 'teams' so it's
+ // available for codegen later to use if/when necessary.
+ CaptureRegion = OMPD_teams;
+ break;
case OMPD_target_teams_distribute_parallel_for_simd:
if (OpenMPVersion >= 50 &&
(NameModifier == OMPD_unknown || NameModifier == OMPD_simd)) {
@@ -15652,7 +15734,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
break;
}
[[fallthrough]];
- case OMPD_target_teams_loop:
case OMPD_target_teams_distribute_parallel_for:
// If this clause applies to the nested 'parallel' region, capture within
// the 'teams' region, otherwise do not capture.
@@ -15775,7 +15856,6 @@ static OpenMPDirectiveKind getOpenMPCaptureRegionForClause(
case OMPD_declare_target:
case OMPD_end_declare_target:
case OMPD_loop:
- case OMPD_teams_loop:
case OMPD_teams:
case OMPD_tile:
case OMPD_unroll:
diff --git a/clang/lib/Sema/SemaSYCL.cpp b/clang/lib/Sema/SemaSYCL.cpp
index 18ebaa13346a..18f6d8f03047 100644
--- a/clang/lib/Sema/SemaSYCL.cpp
+++ b/clang/lib/Sema/SemaSYCL.cpp
@@ -8,6 +8,7 @@
// This implements Semantic Analysis for SYCL constructs.
//===----------------------------------------------------------------------===//
+#include "clang/Sema/SemaSYCL.h"
#include "clang/AST/Mangle.h"
#include "clang/Sema/Sema.h"
#include "clang/Sema/SemaDiagnostic.h"
@@ -18,28 +19,30 @@ using namespace clang;
// SYCL device specific diagnostics implementation
// -----------------------------------------------------------------------------
-Sema::SemaDiagnosticBuilder Sema::SYCLDiagIfDeviceCode(SourceLocation Loc,
+SemaSYCL::SemaSYCL(Sema &S) : SemaBase(S) {}
+
+Sema::SemaDiagnosticBuilder SemaSYCL::DiagIfDeviceCode(SourceLocation Loc,
unsigned DiagID) {
assert(getLangOpts().SYCLIsDevice &&
"Should only be called during SYCL compilation");
- FunctionDecl *FD = dyn_cast<FunctionDecl>(getCurLexicalContext());
+ FunctionDecl *FD = dyn_cast<FunctionDecl>(SemaRef.getCurLexicalContext());
SemaDiagnosticBuilder::Kind DiagKind = [this, FD] {
if (!FD)
return SemaDiagnosticBuilder::K_Nop;
- if (getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
+ if (SemaRef.getEmissionStatus(FD) == Sema::FunctionEmissionStatus::Emitted)
return SemaDiagnosticBuilder::K_ImmediateWithCallStack;
return SemaDiagnosticBuilder::K_Deferred;
}();
- return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, *this);
+ return SemaDiagnosticBuilder(DiagKind, Loc, DiagID, FD, SemaRef);
}
-static bool isZeroSizedArray(Sema &SemaRef, QualType Ty) {
- if (const auto *CAT = SemaRef.getASTContext().getAsConstantArrayType(Ty))
+static bool isZeroSizedArray(SemaSYCL &S, QualType Ty) {
+ if (const auto *CAT = S.getASTContext().getAsConstantArrayType(Ty))
return CAT->isZeroSize();
return false;
}
-void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
+void SemaSYCL::deepTypeCheckForDevice(SourceLocation UsedAt,
llvm::DenseSet<QualType> Visited,
ValueDecl *DeclToCheck) {
assert(getLangOpts().SYCLIsDevice &&
@@ -51,18 +54,18 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
auto Check = [&](QualType TypeToCheck, const ValueDecl *D) {
bool ErrorFound = false;
if (isZeroSizedArray(*this, TypeToCheck)) {
- SYCLDiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
+ DiagIfDeviceCode(UsedAt, diag::err_typecheck_zero_array_size) << 1;
ErrorFound = true;
}
// Checks for other types can also be done here.
if (ErrorFound) {
if (NeedToEmitNotes) {
if (auto *FD = dyn_cast<FieldDecl>(D))
- SYCLDiagIfDeviceCode(FD->getLocation(),
- diag::note_illegal_field_declared_here)
+ DiagIfDeviceCode(FD->getLocation(),
+ diag::note_illegal_field_declared_here)
<< FD->getType()->isPointerType() << FD->getType();
else
- SYCLDiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
+ DiagIfDeviceCode(D->getLocation(), diag::note_declared_at);
}
}
@@ -93,8 +96,8 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
auto EmitHistory = [&]() {
// The first element is always nullptr.
for (uint64_t Index = 1; Index < History.size(); ++Index) {
- SYCLDiagIfDeviceCode(History[Index]->getLocation(),
- diag::note_within_field_of_type)
+ DiagIfDeviceCode(History[Index]->getLocation(),
+ diag::note_within_field_of_type)
<< History[Index]->getType();
}
};
@@ -130,3 +133,26 @@ void Sema::deepTypeCheckForSYCLDevice(SourceLocation UsedAt,
}
} while (!StackForRecursion.empty());
}
+
+ExprResult SemaSYCL::BuildUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ TypeSourceInfo *TSI) {
+ return SYCLUniqueStableNameExpr::Create(getASTContext(), OpLoc, LParen,
+ RParen, TSI);
+}
+
+ExprResult SemaSYCL::ActOnUniqueStableNameExpr(SourceLocation OpLoc,
+ SourceLocation LParen,
+ SourceLocation RParen,
+ ParsedType ParsedTy) {
+ TypeSourceInfo *TSI = nullptr;
+ QualType Ty = SemaRef.GetTypeFromParser(ParsedTy, &TSI);
+
+ if (Ty.isNull())
+ return ExprError();
+ if (!TSI)
+ TSI = getASTContext().getTrivialTypeSourceInfo(Ty, LParen);
+
+ return BuildUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
+}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 8248b10814fe..127a432367b9 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5093,14 +5093,6 @@ void Sema::InstantiateFunctionDefinition(SourceLocation PointOfInstantiation,
EnterExpressionEvaluationContext EvalContext(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
- Qualifiers ThisTypeQuals;
- CXXRecordDecl *ThisContext = nullptr;
- if (CXXMethodDecl *Method = dyn_cast<CXXMethodDecl>(Function)) {
- ThisContext = Method->getParent();
- ThisTypeQuals = Method->getMethodQualifiers();
- }
- CXXThisScopeRAII ThisScope(*this, ThisContext, ThisTypeQuals);
-
// Introduce a new scope where local variable instantiations will be
// recorded, unless we're actually a member function within a local
// class, in which case we need to merge our results with the parent
diff --git a/clang/lib/Sema/SemaTemplateVariadic.cpp b/clang/lib/Sema/SemaTemplateVariadic.cpp
index 903fbfd18e77..4909414c0c78 100644
--- a/clang/lib/Sema/SemaTemplateVariadic.cpp
+++ b/clang/lib/Sema/SemaTemplateVariadic.cpp
@@ -1243,6 +1243,17 @@ std::optional<unsigned> Sema::getFullyPackExpandedSize(TemplateArgument Arg) {
// expanded this pack expansion into the enclosing pack if we could.
if (Elem.isPackExpansion())
return std::nullopt;
+ // Don't guess the size of unexpanded packs. The pack within a template
+ // argument may have yet to be of a PackExpansion type before we see the
+ // ellipsis in the annotation stage.
+ //
+ // This doesn't mean we would invalidate the optimization: Arg can be an
+ // unexpanded pack regardless of Elem's dependence. For instance,
+ // A TemplateArgument that contains either a SubstTemplateTypeParmPackType
+ // or SubstNonTypeTemplateParmPackExpr is always considered Unexpanded, but
+ // the underlying TemplateArgument thereof may not.
+ if (Elem.containsUnexpandedParameterPack())
+ return std::nullopt;
}
return Pack.pack_size();
}
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 13d7b00430d5..33a9356e82f4 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -40,6 +40,7 @@
#include "clang/Sema/SemaDiagnostic.h"
#include "clang/Sema/SemaInternal.h"
#include "clang/Sema/SemaOpenACC.h"
+#include "clang/Sema/SemaSYCL.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/Support/ErrorHandling.h"
#include <algorithm>
@@ -2632,7 +2633,8 @@ public:
SourceLocation LParen,
SourceLocation RParen,
TypeSourceInfo *TSI) {
- return getSema().BuildSYCLUniqueStableNameExpr(OpLoc, LParen, RParen, TSI);
+ return getSema().SYCL().BuildUniqueStableNameExpr(OpLoc, LParen, RParen,
+ TSI);
}
/// Build a new predefined expression.
@@ -3307,13 +3309,12 @@ public:
/// Build a new C++ "this" expression.
///
- /// By default, performs semantic analysis to build a new "this" expression.
- /// Subclasses may override this routine to provide different behavior.
+ /// By default, builds a new "this" expression without performing any
+ /// semantic analysis. Subclasses may override this routine to provide
+ /// different behavior.
ExprResult RebuildCXXThisExpr(SourceLocation ThisLoc,
QualType ThisType,
bool isImplicit) {
- if (getSema().CheckCXXThisType(ThisLoc, ThisType))
- return ExprError();
return getSema().BuildCXXThisExpr(ThisLoc, ThisType, isImplicit);
}
@@ -4034,6 +4035,11 @@ private:
llvm::SmallVector<OpenACCClause *>
TransformOpenACCClauseList(OpenACCDirectiveKind DirKind,
ArrayRef<const OpenACCClause *> OldClauses);
+
+ OpenACCClause *
+ TransformOpenACCClause(ArrayRef<const OpenACCClause *> ExistingClauses,
+ OpenACCDirectiveKind DirKind,
+ const OpenACCClause *OldClause);
};
template <typename Derived>
@@ -11075,12 +11081,43 @@ OMPClause *TreeTransform<Derived>::TransformOMPXBareClause(OMPXBareClause *C) {
// OpenACC transformation
//===----------------------------------------------------------------------===//
template <typename Derived>
+OpenACCClause *TreeTransform<Derived>::TransformOpenACCClause(
+ ArrayRef<const OpenACCClause *> ExistingClauses,
+ OpenACCDirectiveKind DirKind, const OpenACCClause *OldClause) {
+
+ SemaOpenACC::OpenACCParsedClause ParsedClause(
+ DirKind, OldClause->getClauseKind(), OldClause->getBeginLoc());
+ ParsedClause.setEndLoc(OldClause->getEndLoc());
+
+ if (const auto *WithParms = dyn_cast<OpenACCClauseWithParams>(OldClause))
+ ParsedClause.setLParenLoc(WithParms->getLParenLoc());
+
+ switch (OldClause->getClauseKind()) {
+ case OpenACCClauseKind::Default:
+ // There is nothing to do here as nothing dependent can appear in this
+ // clause. So just set the values so Sema can set the right value.
+ ParsedClause.setDefaultDetails(
+ cast<OpenACCDefaultClause>(OldClause)->getDefaultClauseKind());
+ break;
+ default:
+ assert(false && "Unhandled OpenACC clause in TreeTransform");
+ return nullptr;
+ }
+
+ return getSema().OpenACC().ActOnClause(ExistingClauses, ParsedClause);
+}
+
+template <typename Derived>
llvm::SmallVector<OpenACCClause *>
TreeTransform<Derived>::TransformOpenACCClauseList(
OpenACCDirectiveKind DirKind, ArrayRef<const OpenACCClause *> OldClauses) {
- // TODO OpenACC: Ensure we loop through the list and transform the individual
- // clauses.
- return {};
+ llvm::SmallVector<OpenACCClause *> TransformedClauses;
+ for (const auto *Clause : OldClauses) {
+ if (OpenACCClause *TransformedClause = getDerived().TransformOpenACCClause(
+ TransformedClauses, DirKind, Clause))
+ TransformedClauses.push_back(TransformedClause);
+ }
+ return TransformedClauses;
}
template <typename Derived>
diff --git a/clang/lib/Serialization/ASTReader.cpp b/clang/lib/Serialization/ASTReader.cpp
index fa5bb9f2d543..0ca7f6600eee 100644
--- a/clang/lib/Serialization/ASTReader.cpp
+++ b/clang/lib/Serialization/ASTReader.cpp
@@ -6626,8 +6626,6 @@ void ASTReader::ReadPragmaDiagnosticMappings(DiagnosticsEngine &Diag) {
"Invalid data, missing pragma diagnostic states");
FileID FID = ReadFileID(F, Record, Idx);
assert(FID.isValid() && "invalid FileID for transition");
- // FIXME: Remove this once we don't need the side-effects.
- (void)SourceMgr.getSLocEntryOrNull(FID);
unsigned Transitions = Record[Idx++];
// Note that we don't need to set up Parent/ParentOffset here, because
@@ -11756,14 +11754,16 @@ void ASTRecordReader::readOMPChildren(OMPChildren *Data) {
OpenACCClause *ASTRecordReader::readOpenACCClause() {
OpenACCClauseKind ClauseKind = readEnum<OpenACCClauseKind>();
- // TODO OpenACC: We don't have these used anywhere, but eventually we should
- // be constructing the Clauses with them, so these attributes can go away at
- // that point.
- [[maybe_unused]] SourceLocation BeginLoc = readSourceLocation();
- [[maybe_unused]] SourceLocation EndLoc = readSourceLocation();
+ SourceLocation BeginLoc = readSourceLocation();
+ SourceLocation EndLoc = readSourceLocation();
switch (ClauseKind) {
- case OpenACCClauseKind::Default:
+ case OpenACCClauseKind::Default: {
+ SourceLocation LParenLoc = readSourceLocation();
+ OpenACCDefaultClauseKind DCK = readEnum<OpenACCDefaultClauseKind>();
+ return OpenACCDefaultClause::Create(getContext(), DCK, BeginLoc, LParenLoc,
+ EndLoc);
+ }
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
diff --git a/clang/lib/Serialization/ASTReaderStmt.cpp b/clang/lib/Serialization/ASTReaderStmt.cpp
index 3ddb15b10f48..ca0460800898 100644
--- a/clang/lib/Serialization/ASTReaderStmt.cpp
+++ b/clang/lib/Serialization/ASTReaderStmt.cpp
@@ -2769,6 +2769,7 @@ void ASTStmtReader::VisitOMPTeamsGenericLoopDirective(
void ASTStmtReader::VisitOMPTargetTeamsGenericLoopDirective(
OMPTargetTeamsGenericLoopDirective *D) {
VisitOMPLoopDirective(D);
+ D->setCanBeParallelFor(Record.readBool());
}
void ASTStmtReader::VisitOMPParallelGenericLoopDirective(
diff --git a/clang/lib/Serialization/ASTWriter.cpp b/clang/lib/Serialization/ASTWriter.cpp
index baf03f69d730..d2afe378bb0c 100644
--- a/clang/lib/Serialization/ASTWriter.cpp
+++ b/clang/lib/Serialization/ASTWriter.cpp
@@ -163,8 +163,13 @@ static TypeCode getTypeCodeForTypeClass(Type::TypeClass id) {
namespace {
-std::set<const FileEntry *> GetAffectingModuleMaps(const Preprocessor &PP,
- Module *RootModule) {
+std::optional<std::set<const FileEntry *>>
+GetAffectingModuleMaps(const Preprocessor &PP, Module *RootModule) {
+ // Without implicit module map search, there's no good reason to know about
+ // any module maps that are not affecting.
+ if (!PP.getHeaderSearchInfo().getHeaderSearchOpts().ImplicitModuleMaps)
+ return std::nullopt;
+
SmallVector<const Module *> ModulesToProcess{RootModule};
const HeaderSearch &HS = PP.getHeaderSearchInfo();
@@ -4735,8 +4740,16 @@ void ASTWriter::computeNonAffectingInputFiles() {
if (!Cache->OrigEntry)
continue;
- if (!isModuleMap(File.getFileCharacteristic()) ||
- llvm::is_contained(AffectingModuleMaps, *Cache->OrigEntry))
+ // Don't prune anything other than module maps.
+ if (!isModuleMap(File.getFileCharacteristic()))
+ continue;
+
+ // Don't prune module maps if all are guaranteed to be affecting.
+ if (!AffectingModuleMaps)
+ continue;
+
+ // Don't prune module maps that are affecting.
+ if (llvm::is_contained(*AffectingModuleMaps, *Cache->OrigEntry))
continue;
IsSLocAffecting[I] = false;
@@ -7406,7 +7419,12 @@ void ASTRecordWriter::writeOpenACCClause(const OpenACCClause *C) {
writeSourceLocation(C->getEndLoc());
switch (C->getClauseKind()) {
- case OpenACCClauseKind::Default:
+ case OpenACCClauseKind::Default: {
+ const auto *DC = cast<OpenACCDefaultClause>(C);
+ writeSourceLocation(DC->getLParenLoc());
+ writeEnum(DC->getDefaultClauseKind());
+ return;
+ }
case OpenACCClauseKind::Finalize:
case OpenACCClauseKind::IfPresent:
case OpenACCClauseKind::Seq:
diff --git a/clang/lib/Serialization/ASTWriterStmt.cpp b/clang/lib/Serialization/ASTWriterStmt.cpp
index ddee5db2b69e..e3816181e2b2 100644
--- a/clang/lib/Serialization/ASTWriterStmt.cpp
+++ b/clang/lib/Serialization/ASTWriterStmt.cpp
@@ -2821,6 +2821,7 @@ void ASTStmtWriter::VisitOMPTeamsGenericLoopDirective(
void ASTStmtWriter::VisitOMPTargetTeamsGenericLoopDirective(
OMPTargetTeamsGenericLoopDirective *D) {
VisitOMPLoopDirective(D);
+ Record.writeBool(D->canBeParallelFor());
Code = serialization::STMT_OMP_TARGET_TEAMS_GENERIC_LOOP_DIRECTIVE;
}
diff --git a/clang/test/APINotes/instancetype.m b/clang/test/APINotes/instancetype.m
index 30339e5386f6..e3c13188ae9f 100644
--- a/clang/test/APINotes/instancetype.m
+++ b/clang/test/APINotes/instancetype.m
@@ -1,3 +1,4 @@
+// RUN: rm -rf %t
// RUN: %clang_cc1 -fmodules -fimplicit-module-maps -fmodules-cache-path=%t/ModulesCache -fapinotes-modules -fsyntax-only -I %S/Inputs/Headers -verify %s
@import InstancetypeModule;
diff --git a/clang/test/AST/Interp/builtin-functions.cpp b/clang/test/AST/Interp/builtin-functions.cpp
index 2e9d1a831dcf..a7adc92d3714 100644
--- a/clang/test/AST/Interp/builtin-functions.cpp
+++ b/clang/test/AST/Interp/builtin-functions.cpp
@@ -482,6 +482,9 @@ void test_noexcept(int *i) {
#undef TEST_TYPE
} // end namespace test_launder
+
+/// FIXME: The commented out tests here use a IntAP value and fail.
+/// This currently means we will leak the IntAP value since nothing cleans it up.
namespace clz {
char clz1[__builtin_clz(1) == BITSIZE(int) - 1 ? 1 : -1];
char clz2[__builtin_clz(7) == BITSIZE(int) - 3 ? 1 : -1];
@@ -492,6 +495,63 @@ namespace clz {
char clz7[__builtin_clzs(0x1) == BITSIZE(short) - 1 ? 1 : -1];
char clz8[__builtin_clzs(0xf) == BITSIZE(short) - 4 ? 1 : -1];
char clz9[__builtin_clzs(0xfff) == BITSIZE(short) - 12 ? 1 : -1];
+
+ int clz10 = __builtin_clzg((unsigned char)0);
+ char clz11[__builtin_clzg((unsigned char)0, 42) == 42 ? 1 : -1];
+ char clz12[__builtin_clzg((unsigned char)0x1) == BITSIZE(char) - 1 ? 1 : -1];
+ char clz13[__builtin_clzg((unsigned char)0x1, 42) == BITSIZE(char) - 1 ? 1 : -1];
+ char clz14[__builtin_clzg((unsigned char)0xf) == BITSIZE(char) - 4 ? 1 : -1];
+ char clz15[__builtin_clzg((unsigned char)0xf, 42) == BITSIZE(char) - 4 ? 1 : -1];
+ char clz16[__builtin_clzg((unsigned char)(1 << (BITSIZE(char) - 1))) == 0 ? 1 : -1];
+ char clz17[__builtin_clzg((unsigned char)(1 << (BITSIZE(char) - 1)), 42) == 0 ? 1 : -1];
+ int clz18 = __builtin_clzg((unsigned short)0);
+ char clz19[__builtin_clzg((unsigned short)0, 42) == 42 ? 1 : -1];
+ char clz20[__builtin_clzg((unsigned short)0x1) == BITSIZE(short) - 1 ? 1 : -1];
+ char clz21[__builtin_clzg((unsigned short)0x1, 42) == BITSIZE(short) - 1 ? 1 : -1];
+ char clz22[__builtin_clzg((unsigned short)0xf) == BITSIZE(short) - 4 ? 1 : -1];
+ char clz23[__builtin_clzg((unsigned short)0xf, 42) == BITSIZE(short) - 4 ? 1 : -1];
+ char clz24[__builtin_clzg((unsigned short)(1 << (BITSIZE(short) - 1))) == 0 ? 1 : -1];
+ char clz25[__builtin_clzg((unsigned short)(1 << (BITSIZE(short) - 1)), 42) == 0 ? 1 : -1];
+ int clz26 = __builtin_clzg(0U);
+ char clz27[__builtin_clzg(0U, 42) == 42 ? 1 : -1];
+ char clz28[__builtin_clzg(0x1U) == BITSIZE(int) - 1 ? 1 : -1];
+ char clz29[__builtin_clzg(0x1U, 42) == BITSIZE(int) - 1 ? 1 : -1];
+ char clz30[__builtin_clzg(0xfU) == BITSIZE(int) - 4 ? 1 : -1];
+ char clz31[__builtin_clzg(0xfU, 42) == BITSIZE(int) - 4 ? 1 : -1];
+ char clz32[__builtin_clzg(1U << (BITSIZE(int) - 1)) == 0 ? 1 : -1];
+ char clz33[__builtin_clzg(1U << (BITSIZE(int) - 1), 42) == 0 ? 1 : -1];
+ int clz34 = __builtin_clzg(0UL);
+ char clz35[__builtin_clzg(0UL, 42) == 42 ? 1 : -1];
+ char clz36[__builtin_clzg(0x1UL) == BITSIZE(long) - 1 ? 1 : -1];
+ char clz37[__builtin_clzg(0x1UL, 42) == BITSIZE(long) - 1 ? 1 : -1];
+ char clz38[__builtin_clzg(0xfUL) == BITSIZE(long) - 4 ? 1 : -1];
+ char clz39[__builtin_clzg(0xfUL, 42) == BITSIZE(long) - 4 ? 1 : -1];
+ char clz40[__builtin_clzg(1UL << (BITSIZE(long) - 1)) == 0 ? 1 : -1];
+ char clz41[__builtin_clzg(1UL << (BITSIZE(long) - 1), 42) == 0 ? 1 : -1];
+ int clz42 = __builtin_clzg(0ULL);
+ char clz43[__builtin_clzg(0ULL, 42) == 42 ? 1 : -1];
+ char clz44[__builtin_clzg(0x1ULL) == BITSIZE(long long) - 1 ? 1 : -1];
+ char clz45[__builtin_clzg(0x1ULL, 42) == BITSIZE(long long) - 1 ? 1 : -1];
+ char clz46[__builtin_clzg(0xfULL) == BITSIZE(long long) - 4 ? 1 : -1];
+ char clz47[__builtin_clzg(0xfULL, 42) == BITSIZE(long long) - 4 ? 1 : -1];
+ char clz48[__builtin_clzg(1ULL << (BITSIZE(long long) - 1)) == 0 ? 1 : -1];
+ char clz49[__builtin_clzg(1ULL << (BITSIZE(long long) - 1), 42) == 0 ? 1 : -1];
+#ifdef __SIZEOF_INT128__
+ // int clz50 = __builtin_clzg((unsigned __int128)0);
+ char clz51[__builtin_clzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
+ char clz52[__builtin_clzg((unsigned __int128)0x1) == BITSIZE(__int128) - 1 ? 1 : -1];
+ char clz53[__builtin_clzg((unsigned __int128)0x1, 42) == BITSIZE(__int128) - 1 ? 1 : -1];
+ char clz54[__builtin_clzg((unsigned __int128)0xf) == BITSIZE(__int128) - 4 ? 1 : -1];
+ char clz55[__builtin_clzg((unsigned __int128)0xf, 42) == BITSIZE(__int128) - 4 ? 1 : -1];
+#endif
+#ifndef __AVR__
+ // int clz58 = __builtin_clzg((unsigned _BitInt(128))0);
+ char clz59[__builtin_clzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
+ char clz60[__builtin_clzg((unsigned _BitInt(128))0x1) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+ char clz61[__builtin_clzg((unsigned _BitInt(128))0x1, 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+ char clz62[__builtin_clzg((unsigned _BitInt(128))0xf) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
+ char clz63[__builtin_clzg((unsigned _BitInt(128))0xf, 42) == BITSIZE(_BitInt(128)) - 4 ? 1 : -1];
+#endif
}
namespace ctz {
@@ -502,6 +562,66 @@ namespace ctz {
char ctz5[__builtin_ctzl(0x10L) == 4 ? 1 : -1];
char ctz6[__builtin_ctzll(0x100LL) == 8 ? 1 : -1];
char ctz7[__builtin_ctzs(1 << (BITSIZE(short) - 1)) == BITSIZE(short) - 1 ? 1 : -1];
+ int ctz8 = __builtin_ctzg((unsigned char)0);
+ char ctz9[__builtin_ctzg((unsigned char)0, 42) == 42 ? 1 : -1];
+ char ctz10[__builtin_ctzg((unsigned char)0x1) == 0 ? 1 : -1];
+ char ctz11[__builtin_ctzg((unsigned char)0x1, 42) == 0 ? 1 : -1];
+ char ctz12[__builtin_ctzg((unsigned char)0x10) == 4 ? 1 : -1];
+ char ctz13[__builtin_ctzg((unsigned char)0x10, 42) == 4 ? 1 : -1];
+ char ctz14[__builtin_ctzg((unsigned char)(1 << (BITSIZE(char) - 1))) == BITSIZE(char) - 1 ? 1 : -1];
+ char ctz15[__builtin_ctzg((unsigned char)(1 << (BITSIZE(char) - 1)), 42) == BITSIZE(char) - 1 ? 1 : -1];
+ int ctz16 = __builtin_ctzg((unsigned short)0);
+ char ctz17[__builtin_ctzg((unsigned short)0, 42) == 42 ? 1 : -1];
+ char ctz18[__builtin_ctzg((unsigned short)0x1) == 0 ? 1 : -1];
+ char ctz19[__builtin_ctzg((unsigned short)0x1, 42) == 0 ? 1 : -1];
+ char ctz20[__builtin_ctzg((unsigned short)0x10) == 4 ? 1 : -1];
+ char ctz21[__builtin_ctzg((unsigned short)0x10, 42) == 4 ? 1 : -1];
+ char ctz22[__builtin_ctzg((unsigned short)(1 << (BITSIZE(short) - 1))) == BITSIZE(short) - 1 ? 1 : -1];
+ char ctz23[__builtin_ctzg((unsigned short)(1 << (BITSIZE(short) - 1)), 42) == BITSIZE(short) - 1 ? 1 : -1];
+ int ctz24 = __builtin_ctzg(0U);
+ char ctz25[__builtin_ctzg(0U, 42) == 42 ? 1 : -1];
+ char ctz26[__builtin_ctzg(0x1U) == 0 ? 1 : -1];
+ char ctz27[__builtin_ctzg(0x1U, 42) == 0 ? 1 : -1];
+ char ctz28[__builtin_ctzg(0x10U) == 4 ? 1 : -1];
+ char ctz29[__builtin_ctzg(0x10U, 42) == 4 ? 1 : -1];
+ char ctz30[__builtin_ctzg(1U << (BITSIZE(int) - 1)) == BITSIZE(int) - 1 ? 1 : -1];
+ char ctz31[__builtin_ctzg(1U << (BITSIZE(int) - 1), 42) == BITSIZE(int) - 1 ? 1 : -1];
+ int ctz32 = __builtin_ctzg(0UL);
+ char ctz33[__builtin_ctzg(0UL, 42) == 42 ? 1 : -1];
+ char ctz34[__builtin_ctzg(0x1UL) == 0 ? 1 : -1];
+ char ctz35[__builtin_ctzg(0x1UL, 42) == 0 ? 1 : -1];
+ char ctz36[__builtin_ctzg(0x10UL) == 4 ? 1 : -1];
+ char ctz37[__builtin_ctzg(0x10UL, 42) == 4 ? 1 : -1];
+ char ctz38[__builtin_ctzg(1UL << (BITSIZE(long) - 1)) == BITSIZE(long) - 1 ? 1 : -1];
+ char ctz39[__builtin_ctzg(1UL << (BITSIZE(long) - 1), 42) == BITSIZE(long) - 1 ? 1 : -1];
+ int ctz40 = __builtin_ctzg(0ULL);
+ char ctz41[__builtin_ctzg(0ULL, 42) == 42 ? 1 : -1];
+ char ctz42[__builtin_ctzg(0x1ULL) == 0 ? 1 : -1];
+ char ctz43[__builtin_ctzg(0x1ULL, 42) == 0 ? 1 : -1];
+ char ctz44[__builtin_ctzg(0x10ULL) == 4 ? 1 : -1];
+ char ctz45[__builtin_ctzg(0x10ULL, 42) == 4 ? 1 : -1];
+ char ctz46[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1)) == BITSIZE(long long) - 1 ? 1 : -1];
+ char ctz47[__builtin_ctzg(1ULL << (BITSIZE(long long) - 1), 42) == BITSIZE(long long) - 1 ? 1 : -1];
+#ifdef __SIZEOF_INT128__
+ // int ctz48 = __builtin_ctzg((unsigned __int128)0);
+ char ctz49[__builtin_ctzg((unsigned __int128)0, 42) == 42 ? 1 : -1];
+ char ctz50[__builtin_ctzg((unsigned __int128)0x1) == 0 ? 1 : -1];
+ char ctz51[__builtin_ctzg((unsigned __int128)0x1, 42) == 0 ? 1 : -1];
+ char ctz52[__builtin_ctzg((unsigned __int128)0x10) == 4 ? 1 : -1];
+ char ctz53[__builtin_ctzg((unsigned __int128)0x10, 42) == 4 ? 1 : -1];
+ char ctz54[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1)) == BITSIZE(__int128) - 1 ? 1 : -1];
+ char ctz55[__builtin_ctzg((unsigned __int128)1 << (BITSIZE(__int128) - 1), 42) == BITSIZE(__int128) - 1 ? 1 : -1];
+#endif
+#ifndef __AVR__
+ // int ctz56 = __builtin_ctzg((unsigned _BitInt(128))0);
+ char ctz57[__builtin_ctzg((unsigned _BitInt(128))0, 42) == 42 ? 1 : -1];
+ char ctz58[__builtin_ctzg((unsigned _BitInt(128))0x1) == 0 ? 1 : -1];
+ char ctz59[__builtin_ctzg((unsigned _BitInt(128))0x1, 42) == 0 ? 1 : -1];
+ char ctz60[__builtin_ctzg((unsigned _BitInt(128))0x10) == 4 ? 1 : -1];
+ char ctz61[__builtin_ctzg((unsigned _BitInt(128))0x10, 42) == 4 ? 1 : -1];
+ char ctz62[__builtin_ctzg((unsigned _BitInt(128))1 << (BITSIZE(_BitInt(128)) - 1)) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+ char ctz63[__builtin_ctzg((unsigned _BitInt(128))1 << (BITSIZE(_BitInt(128)) - 1), 42) == BITSIZE(_BitInt(128)) - 1 ? 1 : -1];
+#endif
}
namespace bswap {
diff --git a/clang/test/AST/Interp/c.c b/clang/test/AST/Interp/c.c
index 10e23839f2ba..cdecd3e83a99 100644
--- a/clang/test/AST/Interp/c.c
+++ b/clang/test/AST/Interp/c.c
@@ -209,3 +209,21 @@ const struct StrA * const sb = &sa;
const struct StrA sc = *sb;
_Static_assert(sc.a == 12, ""); // pedantic-ref-warning {{GNU extension}} \
// pedantic-expected-warning {{GNU extension}}
+
+_Static_assert(((void*)0 + 1) != (void*)0, ""); // pedantic-expected-warning {{arithmetic on a pointer to void is a GNU extension}} \
+ // pedantic-expected-warning {{not an integer constant expression}} \
+ // pedantic-expected-note {{cannot perform pointer arithmetic on null pointer}} \
+ // pedantic-ref-warning {{arithmetic on a pointer to void is a GNU extension}} \
+ // pedantic-ref-warning {{not an integer constant expression}} \
+ // pedantic-ref-note {{cannot perform pointer arithmetic on null pointer}}
+
+typedef __INTPTR_TYPE__ intptr_t;
+int array[(intptr_t)(int*)1]; // ref-warning {{variable length array folded to constant array}} \
+ // pedantic-ref-warning {{variable length array folded to constant array}} \
+ // expected-warning {{variable length array folded to constant array}} \
+ // pedantic-expected-warning {{variable length array folded to constant array}}
+
+int castViaInt[*(int*)(unsigned long)"test"]; // ref-error {{variable length array}} \
+ // pedantic-ref-error {{variable length array}} \
+ // expected-error {{variable length array}} \
+ // pedantic-expected-error {{variable length array}}
diff --git a/clang/test/AST/Interp/const-eval.c b/clang/test/AST/Interp/const-eval.c
new file mode 100644
index 000000000000..72c0833a0f63
--- /dev/null
+++ b/clang/test/AST/Interp/const-eval.c
@@ -0,0 +1,192 @@
+// RUN: %clang_cc1 -fsyntax-only -verify=both,ref -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast
+// RUN: %clang_cc1 -fsyntax-only -verify=both,expected -triple x86_64-linux %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -fexperimental-new-constant-interpreter -DNEW_INTERP
+// RUN: %clang_cc1 -fsyntax-only -verify=both,ref -triple powerpc64-ibm-aix-xcoff %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast
+// RUN: %clang_cc1 -fsyntax-only -verify=both,expected -triple powerpc64-ibm-aix-xcoff %s -Wno-tautological-pointer-compare -Wno-pointer-to-int-cast -fexperimental-new-constant-interpreter -DNEW_INTERP
+
+/// This is a version of test/Sema/const-eval.c with the
+/// tests commented out that the new constant expression interpreter does
+/// not support yet. They are all marked with the NEW_INTERP define:
+///
+/// - builtin_constant_p
+/// - unions
+
+
+#define EVAL_EXPR(testno, expr) enum { test##testno = (expr) }; struct check_positive##testno { int a[test##testno]; };
+int x;
+EVAL_EXPR(1, (_Bool)&x)
+EVAL_EXPR(2, (int)(1.0+(double)4))
+EVAL_EXPR(3, (int)(1.0+(float)4.0))
+EVAL_EXPR(4, (_Bool)(1 ? (void*)&x : 0))
+EVAL_EXPR(5, (_Bool)(int[]){0})
+struct y {int x,y;};
+EVAL_EXPR(6, (int)(1+(struct y*)0))
+_Static_assert((long)&((struct y*)0)->y > 0, "");
+EVAL_EXPR(7, (int)&((struct y*)0)->y)
+EVAL_EXPR(8, (_Bool)"asdf")
+EVAL_EXPR(9, !!&x)
+EVAL_EXPR(10, ((void)1, 12))
+void g0(void);
+EVAL_EXPR(11, (g0(), 12)) // both-error {{not an integer constant expression}}
+EVAL_EXPR(12, 1.0&&2.0)
+EVAL_EXPR(13, x || 3.0) // both-error {{not an integer constant expression}}
+
+unsigned int l_19 = 1;
+EVAL_EXPR(14, (1 ^ l_19) && 1); // both-error {{not an integer constant expression}}
+
+void f(void)
+{
+ int a;
+ EVAL_EXPR(15, (_Bool)&a);
+}
+
+_Complex float g16 = (1.0f + 1.0fi);
+
+// ?: in constant expressions.
+int g17[(3?:1) - 2];
+
+EVAL_EXPR(18, ((int)((void*)10 + 10)) == 20 ? 1 : -1);
+
+struct s {
+ int a[(int)-1.0f]; // both-error {{array size is negative}}
+};
+
+EVAL_EXPR(19, ((int)&*(char*)10 == 10 ? 1 : -1));
+
+#ifndef NEW_INTERP
+EVAL_EXPR(20, __builtin_constant_p(*((int*) 10)));
+#endif
+
+EVAL_EXPR(21, (__imag__ 2i) == 2 ? 1 : -1);
+
+EVAL_EXPR(22, (__real__ (2i+3)) == 3 ? 1 : -1);
+
+int g23[(int)(1.0 / 1.0)] = { 1 }; // both-warning {{folded to constant array}}
+int g24[(int)(1.0 / 1.0)] = { 1 , 2 }; // both-warning {{folded to constant array}} \
+ // both-warning {{excess elements in array initializer}}
+int g25[(int)(1.0 + 1.0)], g26 = sizeof(g25); // both-warning {{folded to constant array}}
+
+EVAL_EXPR(26, (_Complex double)0 ? -1 : 1)
+EVAL_EXPR(27, (_Complex int)0 ? -1 : 1)
+EVAL_EXPR(28, (_Complex double)1 ? 1 : -1)
+EVAL_EXPR(29, (_Complex int)1 ? 1 : -1)
+
+// PR4027
+struct a { int x, y; };
+static struct a V2 = (struct a)(struct a){ 1, 2};
+static const struct a V1 = (struct a){ 1, 2};
+
+EVAL_EXPR(30, (int)(_Complex float)((1<<30)-1) == (1<<30) ? 1 : -1)
+EVAL_EXPR(31, (int*)0 == (int*)0 ? 1 : -1)
+EVAL_EXPR(32, (int*)0 != (int*)0 ? -1 : 1)
+EVAL_EXPR(33, (void*)0 - (void*)0 == 0 ? 1 : -1)
+
+void foo(void) {}
+EVAL_EXPR(34, (foo == (void *)0) ? -1 : 1)
+
+// No PR. Mismatched bitwidths lead to a crash on second evaluation.
+const _Bool constbool = 0;
+EVAL_EXPR(35, constbool)
+EVAL_EXPR(36, constbool)
+
+EVAL_EXPR(37, ((void)1,2.0) == 2.0 ? 1 : -1)
+EVAL_EXPR(38, __builtin_expect(1,1) == 1 ? 1 : -1)
+
+// PR7884
+EVAL_EXPR(39, __real__(1.f) == 1 ? 1 : -1)
+EVAL_EXPR(40, __imag__(1.f) == 0 ? 1 : -1)
+
+// From gcc testsuite
+EVAL_EXPR(41, (int)(1+(_Complex unsigned)2))
+
+void rdar8875946(void) {
+ double _Complex P;
+ float _Complex P2 = 3.3f + P;
+}
+
+double d = (d = 0.0); // both-error {{not a compile-time constant}}
+double d2 = ++d; // both-error {{not a compile-time constant}}
+
+int n = 2;
+int intLvalue[*(int*)((long)&n ?: 1)] = { 1, 2 }; // both-error {{variable length array}}
+
+union u { int a; char b[4]; };
+char c = ((union u)(123456)).b[0]; // both-error {{not a compile-time constant}}
+
+#ifndef NEW_INTERP
+extern const int weak_int __attribute__((weak));
+const int weak_int = 42;
+int weak_int_test = weak_int; // both-error {{not a compile-time constant}}
+#endif
+
+int literalVsNull1 = "foo" == 0;
+int literalVsNull2 = 0 == "foo";
+
+// PR11385.
+int castViaInt[*(int*)(unsigned long)"test"]; // both-error {{variable length array}}
+
+// PR11391.
+#ifndef NEW_INTERP
+struct PR11391 { _Complex float f; } pr11391;
+EVAL_EXPR(42, __builtin_constant_p(pr11391.f = 1))
+#endif
+
+// PR12043
+float varfloat;
+const float constfloat = 0;
+EVAL_EXPR(43, varfloat && constfloat) // both-error {{not an integer constant expression}}
+EVAL_EXPR(45, ((char*)-1) + 1 == 0 ? 1 : -1)
+EVAL_EXPR(46, ((char*)-1) + 1 < (char*) -1 ? 1 : -1)
+EVAL_EXPR(47, &x < &x + 1 ? 1 : -1)
+EVAL_EXPR(48, &x != &x - 1 ? 1 : -1)
+EVAL_EXPR(49, &x < &x - 100 ? 1 : -1) // ref-error {{not an integer constant expression}}
+
+/// FIXME: Rejecting this is correct, BUT when converting the innermost pointer
+/// to an integer, we do not preserve the information where it came from. So when we later
+/// create a pointer from it, it also doesn't have that information, which means
+/// hasSameBase() for those two pointers will return false. And in those cases, we emit
+/// the diagnostic:
+/// comparison between '&Test50' and '&(631578)' has unspecified value
+extern struct Test50S Test50;
+EVAL_EXPR(50, &Test50 < (struct Test50S*)((unsigned long)&Test50 + 10)) // both-error {{not an integer constant expression}} \
+ // expected-note {{comparison between}}
+
+EVAL_EXPR(51, 0 != (float)1e99)
+
+// PR21945
+void PR21945(void) { int i = (({}), 0l); }
+
+void PR24622(void);
+struct PR24622 {} pr24622;
+EVAL_EXPR(52, &pr24622 == (void *)&PR24622);
+
+// We evaluate these by providing 2s' complement semantics in constant
+// expressions, like we do for integers.
+void *PR28739a = (__int128)(unsigned long)-1 + &PR28739a; // both-warning {{the pointer incremented by 18446744073709551615 refers past the last possible element for an array in 64-bit address space containing 64-bit (8-byte) elements (max possible 2305843009213693952 elements)}}
+
+void *PR28739b = &PR28739b + (__int128)(unsigned long)-1; // both-warning {{refers past the last possible element}}
+__int128 PR28739c = (&PR28739c + (__int128)(unsigned long)-1) - &PR28739c; // both-warning {{refers past the last possible element}}
+void *PR28739d = &(&PR28739d)[(__int128)(unsigned long)-1]; // both-warning {{refers past the last possible element}}
+
+struct PR35214_X {
+ int k;
+ int arr[];
+};
+int PR35214_x;
+int PR35214_y = ((struct PR35214_X *)&PR35214_x)->arr[1]; // both-error {{not a compile-time constant}}
+#ifndef NEW_INTERP
+int *PR35214_z = &((struct PR35214_X *)&PR35214_x)->arr[1]; // ok, &PR35214_x + 2
+#endif
+
+/// From const-eval-64.c
+EVAL_EXPR(53, ((char*)-1LL) + 1 == 0 ? 1 : -1)
+EVAL_EXPR(54, ((char*)-1LL) + 1 < (char*) -1 ? 1 : -1)
+
+/// === Additions ===
+#if __SIZEOF_INT__ == 4
+typedef __INTPTR_TYPE__ intptr_t;
+const intptr_t A = (intptr_t)(((int*) 0) + 1);
+const intptr_t B = (intptr_t)(((char*)0) + 3);
+_Static_assert(A > B, "");
+#else
+#error :(
+#endif
diff --git a/clang/test/AST/Interp/functions.cpp b/clang/test/AST/Interp/functions.cpp
index 67fd9036d81e..4fb3c816000a 100644
--- a/clang/test/AST/Interp/functions.cpp
+++ b/clang/test/AST/Interp/functions.cpp
@@ -185,6 +185,21 @@ namespace FunctionReturnType {
constexpr int (*invalidFnPtr)() = m;
static_assert(invalidFnPtr() == 5, ""); // both-error {{not an integral constant expression}} \
// both-note {{non-constexpr function 'm'}}
+
+
+namespace ToBool {
+ void mismatched(int x) {}
+ typedef void (*callback_t)(int);
+ void foo() {
+ callback_t callback = (callback_t)mismatched; // warns
+ /// Casts a function pointer to a boolean and then back to a function pointer.
+ /// This is extracted from test/Sema/callingconv-cast.c
+ callback = (callback_t)!mismatched; // both-warning {{address of function 'mismatched' will always evaluate to 'true'}} \
+ // both-note {{prefix with the address-of operator to silence this warning}}
+ }
+}
+
+
}
namespace Comparison {
diff --git a/clang/test/AST/Interp/vectors.cpp b/clang/test/AST/Interp/vectors.cpp
new file mode 100644
index 000000000000..8afef3c897bf
--- /dev/null
+++ b/clang/test/AST/Interp/vectors.cpp
@@ -0,0 +1,22 @@
+// RUN: %clang_cc1 -fexperimental-new-constant-interpreter -verify=expected,both %s
+// RUN: %clang_cc1 -verify=ref,both %s
+
+// both-no-diagnostics
+
+typedef int __attribute__((vector_size(16))) VI4;
+constexpr VI4 A = {1,2,3,4};
+
+/// From constant-expression-cxx11.cpp
+namespace Vector {
+ typedef int __attribute__((vector_size(16))) VI4;
+ constexpr VI4 f(int n) {
+ return VI4 { n * 3, n + 4, n - 5, n / 6 };
+ }
+ constexpr auto v1 = f(10);
+
+ typedef double __attribute__((vector_size(32))) VD4;
+ constexpr VD4 g(int n) {
+ return (VD4) { n / 2.0, n + 1.5, n - 5.4, n * 0.9 };
+ }
+ constexpr auto v2 = g(4);
+}
diff --git a/clang/test/CodeGen/X86/x86_64-arguments.c b/clang/test/CodeGen/X86/x86_64-arguments.c
index cf5636cfd518..82845f0a2b31 100644
--- a/clang/test/CodeGen/X86/x86_64-arguments.c
+++ b/clang/test/CodeGen/X86/x86_64-arguments.c
@@ -533,6 +533,24 @@ typedef float t66 __attribute__((__vector_size__(128), __aligned__(128)));
void f66(t66 a0) {
}
+typedef long long t67 __attribute__((aligned (4)));
+struct s67 {
+ int a;
+ t67 b;
+};
+// CHECK-LABEL: define{{.*}} void @f67(ptr noundef byval(%struct.s67) align 8 %x)
+void f67(struct s67 x) {
+}
+
+typedef double t68 __attribute__((aligned (4)));
+struct s68 {
+ int a;
+ t68 b;
+};
+// CHECK-LABEL: define{{.*}} void @f68(ptr noundef byval(%struct.s68) align 8 %x)
+void f68(struct s68 x) {
+}
+
/// The synthesized __va_list_tag does not have file/line fields.
// CHECK: = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "__va_list_tag",
// CHECK-NOT: file:
diff --git a/clang/test/CodeGenCXX/arm64ec-vectorcall.cpp b/clang/test/CodeGenCXX/arm64ec-vectorcall.cpp
new file mode 100644
index 000000000000..73d2d6383591
--- /dev/null
+++ b/clang/test/CodeGenCXX/arm64ec-vectorcall.cpp
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple arm64ec-windows-msvc -emit-llvm -o - %s -verify
+
+// ARM64EC doesn't support generating __vectorcall calls... but __vectorcall
+// function types need to be distinct from __cdecl function types to support
+// compiling the STL. Make sure we only diagnose constructs that actually
+// require generating code.
+void __vectorcall f1();
+void f2(void __vectorcall p()) {}
+void f2(void p()) {}
+void __vectorcall (*f3)();
+void __vectorcall f4(); // expected-error {{__vectorcall}}
+void __vectorcall f5() { // expected-error {{__vectorcall}}
+ f4(); // expected-error{{__vectorcall}}
+}
diff --git a/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp b/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
new file mode 100644
index 000000000000..ffde1bd6a724
--- /dev/null
+++ b/clang/test/CodeGenCXX/control-flow-in-stmt-expr.cpp
@@ -0,0 +1,364 @@
+// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+struct Printy {
+ Printy(const char *name) : name(name) {}
+ ~Printy() {}
+ const char *name;
+};
+
+int foo() { return 2; }
+
+struct Printies {
+ Printy a;
+ Printy b;
+ Printy c;
+};
+
+void ParenInit() {
+ // CHECK-LABEL: define dso_local void @_Z9ParenInitv()
+ // CHECK: [[CLEANUP_DEST:%.+]] = alloca i32, align 4
+ Printies ps(Printy("a"),
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ ({
+ if (foo()) return;
+ // CHECK: if.then:
+ // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
+ // CHECK-NEXT: br label %cleanup
+ Printy("b");
+ // CHECK: if.end:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ }),
+ ({
+ if (foo()) return;
+ // CHECK: if.then{{.*}}:
+ // CHECK-NEXT: store i32 1, ptr [[CLEANUP_DEST]], align 4
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: br label %cleanup
+ Printy("c");
+ // CHECK: if.end{{.*}}:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
+ // CHECK-NEXT: br label %return
+ }));
+ // CHECK: cleanup:
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: br label %return
+}
+
+void break_in_stmt_expr() {
+ // Verify that the "break" in "if.then".calls dtor before jumping to "for.end".
+
+ // CHECK-LABEL: define dso_local void @_Z18break_in_stmt_exprv()
+ Printies p{Printy("a"),
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ ({
+ for (;;) {
+ Printies ps{
+ Printy("b"),
+ // CHECK: for.cond:
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ ({
+ if (foo()) {
+ break;
+ // CHECK: if.then:
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: br label %for.end
+ }
+ Printy("c");
+ // CHECK: if.end:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ }),
+ Printy("d")};
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
+ // CHECK-NEXT: br label %for.cond
+ }
+ Printy("e");
+ // CHECK: for.end:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ }),
+ Printy("f")};
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
+}
+
+void goto_in_stmt_expr() {
+ // Verify that:
+ // - correct branch fixups for deactivated normal cleanups are generated correctly.
+
+ // CHECK-LABEL: define dso_local void @_Z17goto_in_stmt_exprv()
+ // CHECK: [[CLEANUP_DEST_SLOT:%cleanup.dest.slot.*]] = alloca i32, align 4
+ {
+ Printies p1{Printy("a"), // CHECK: call void @_ZN6PrintyC1EPKc
+ ({
+ {
+ Printies p2{Printy("b"),
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ ({
+ if (foo() == 1) {
+ goto in;
+ // CHECK: if.then:
+ // CHECK-NEXT: store i32 2, ptr [[CLEANUP_DEST_SLOT]], align 4
+ // CHECK-NEXT: br label %[[CLEANUP1:.+]]
+ }
+ if (foo() == 2) {
+ goto out;
+ // CHECK: if.then{{.*}}:
+ // CHECK-NEXT: store i32 3, ptr [[CLEANUP_DEST_SLOT]], align 4
+ // CHECK-NEXT: br label %[[CLEANUP1]]
+ }
+ Printy("c");
+ // CHECK: if.end{{.*}}:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ }),
+ Printy("d")};
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
+ // CHECK-NEXT: br label %in
+
+ }
+ in:
+ Printy("e");
+ // CHECK: in: ; preds = %if.end{{.*}}, %[[CLEANUP1]]
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ }),
+ Printy("f")};
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZN8PrintiesD1Ev
+ // CHECK-NEXT: br label %out
+ }
+out:
+ return;
+ // CHECK: out:
+ // CHECK-NEXT: ret void
+
+ // CHECK: [[CLEANUP1]]: ; preds = %if.then{{.*}}, %if.then
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: %cleanup.dest = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
+ // CHECK-NEXT: switch i32 %cleanup.dest, label %[[CLEANUP2:.+]] [
+ // CHECK-NEXT: i32 2, label %in
+ // CHECK-NEXT: ]
+
+ // CHECK: [[CLEANUP2]]: ; preds = %[[CLEANUP1]]
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: %cleanup.dest{{.*}} = load i32, ptr [[CLEANUP_DEST_SLOT]], align 4
+ // CHECK-NEXT: switch i32 %cleanup.dest{{.*}}, label %unreachable [
+ // CHECK-NEXT: i32 3, label %out
+ // CHECK-NEXT: ]
+}
+
+void ArrayInit() {
+ // Printy arr[4] = {ctorA, ctorB, stmt-exprC, stmt-exprD};
+ // Verify that:
+ // - We do the necessary stores for array cleanups (endOfInit and last constructed element).
+ // - We update the array init element correctly for ctorA, ctorB and stmt-exprC.
+ // - stmt-exprC and stmt-exprD share the array body dtor code (see %cleanup).
+
+ // CHECK-LABEL: define dso_local void @_Z9ArrayInitv()
+ // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
+ // CHECK: %cleanup.dest.slot = alloca i32, align 4
+ // CHECK: %arrayinit.begin = getelementptr inbounds [4 x %struct.Printy], ptr %arr, i64 0, i64 0
+ // CHECK: store ptr %arrayinit.begin, ptr %arrayinit.endOfInit, align 8
+ Printy arr[4] = {
+ Printy("a"),
+ // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arrayinit.begin, ptr noundef @.str)
+ // CHECK: [[ARRAYINIT_ELEMENT1:%.+]] = getelementptr inbounds %struct.Printy, ptr %arrayinit.begin, i64 1
+ // CHECK: store ptr [[ARRAYINIT_ELEMENT1]], ptr %arrayinit.endOfInit, align 8
+ Printy("b"),
+ // CHECK: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) [[ARRAYINIT_ELEMENT1]], ptr noundef @.str.1)
+ // CHECK: [[ARRAYINIT_ELEMENT2:%.+]] = getelementptr inbounds %struct.Printy, ptr [[ARRAYINIT_ELEMENT1]], i64 1
+ // CHECK: store ptr [[ARRAYINIT_ELEMENT2]], ptr %arrayinit.endOfInit, align 8
+ ({
+ // CHECK: br i1 {{.*}}, label %if.then, label %if.end
+ if (foo()) {
+ return;
+ // CHECK: if.then:
+ // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
+ // CHECK-NEXT: br label %cleanup
+ }
+ // CHECK: if.end:
+ Printy("c");
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: %arrayinit.element2 = getelementptr inbounds %struct.Printy, ptr %arrayinit.element1, i64 1
+ // CHECK-NEXT: store ptr %arrayinit.element2, ptr %arrayinit.endOfInit, align 8
+ }),
+ ({
+ // CHECK: br i1 {{%.+}} label %[[IF_THEN2:.+]], label %[[IF_END2:.+]]
+ if (foo()) {
+ return;
+ // CHECK: [[IF_THEN2]]:
+ // CHECK-NEXT: store i32 1, ptr %cleanup.dest.slot, align 4
+ // CHECK-NEXT: br label %cleanup
+ }
+ // CHECK: [[IF_END2]]:
+ Printy("d");
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: %array.begin = getelementptr inbounds [4 x %struct.Printy], ptr %arr, i32 0, i32 0
+ // CHECK-NEXT: %0 = getelementptr inbounds %struct.Printy, ptr %array.begin, i64 4
+ // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY1:.+]]
+ }),
+ };
+
+ // CHECK: [[ARRAY_DESTROY_BODY1]]:
+ // CHECK-NEXT: %arraydestroy.elementPast{{.*}} = phi ptr [ %0, %[[IF_END2]] ], [ %arraydestroy.element{{.*}}, %[[ARRAY_DESTROY_BODY1]] ]
+ // CHECK-NEXT: %arraydestroy.element{{.*}} = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast{{.*}}, i64 -1
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: %arraydestroy.done{{.*}} = icmp eq ptr %arraydestroy.element{{.*}}, %array.begin
+ // CHECK-NEXT: br i1 %arraydestroy.done{{.*}}, label %[[ARRAY_DESTROY_DONE1:.+]], label %[[ARRAY_DESTROY_BODY1]]
+
+ // CHECK: [[ARRAY_DESTROY_DONE1]]:
+ // CHECK-NEXT: ret void
+
+ // CHECK: cleanup:
+ // CHECK-NEXT: %1 = load ptr, ptr %arrayinit.endOfInit, align 8
+ // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr %arrayinit.begin, %1
+ // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2:.+]]
+
+ // CHECK: [[ARRAY_DESTROY_BODY2]]:
+ // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %1, %cleanup ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY2]] ]
+ // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
+ // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %arrayinit.begin
+ // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE2]], label %[[ARRAY_DESTROY_BODY2]]
+
+ // CHECK: [[ARRAY_DESTROY_DONE2]]:
+ // CHECK-NEXT: br label %[[ARRAY_DESTROY_DONE1]]
+}
+
+void ArraySubobjects() {
+ struct S {
+ Printy arr1[2];
+ Printy arr2[2];
+ Printy p;
+ };
+ // CHECK-LABEL: define dso_local void @_Z15ArraySubobjectsv()
+ // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
+ S s{{Printy("a"), Printy("b")},
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ {Printy("a"),
+ // CHECK: [[ARRAYINIT_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.Printy]
+ // CHECK: store ptr [[ARRAYINIT_BEGIN]], ptr %arrayinit.endOfInit, align 8
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK: [[ARRAYINIT_ELEMENT:%.+]] = getelementptr inbounds %struct.Printy
+ // CHECK: store ptr [[ARRAYINIT_ELEMENT]], ptr %arrayinit.endOfInit, align 8
+ ({
+ if (foo()) {
+ return;
+ // CHECK: if.then:
+ // CHECK-NEXT: [[V0:%.+]] = load ptr, ptr %arrayinit.endOfInit, align 8
+ // CHECK-NEXT: %arraydestroy.isempty = icmp eq ptr [[ARRAYINIT_BEGIN]], [[V0]]
+ // CHECK-NEXT: br i1 %arraydestroy.isempty, label %[[ARRAY_DESTROY_DONE:.+]], label %[[ARRAY_DESTROY_BODY:.+]]
+ }
+ Printy("b");
+ })
+ },
+ Printy("c")
+ // CHECK: if.end:
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK-NEXT: call void @_ZZ15ArraySubobjectsvEN1SD1Ev
+ // CHECK-NEXT: br label %return
+ };
+ // CHECK: return:
+ // CHECK-NEXT: ret void
+
+ // CHECK: [[ARRAY_DESTROY_BODY]]:
+ // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %0, %if.then ], [ %arraydestroy.element, %[[ARRAY_DESTROY_BODY]] ]
+ // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
+ // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, [[ARRAYINIT_BEGIN]]
+ // CHECK-NEXT: br i1 %arraydestroy.done, label %[[ARRAY_DESTROY_DONE]], label %[[ARRAY_DESTROY_BODY]]
+
+ // CHECK: [[ARRAY_DESTROY_DONE]]
+ // CHECK-NEXT: [[ARRAY_BEGIN:%.+]] = getelementptr inbounds [2 x %struct.Printy], ptr %arr1, i32 0, i32 0
+ // CHECK-NEXT: [[V1:%.+]] = getelementptr inbounds %struct.Printy, ptr [[ARRAY_BEGIN]], i64 2
+ // CHECK-NEXT: br label %[[ARRAY_DESTROY_BODY2:.+]]
+
+ // CHECK: [[ARRAY_DESTROY_BODY2]]:
+ // CHECK-NEXT: %arraydestroy.elementPast5 = phi ptr [ %1, %[[ARRAY_DESTROY_DONE]] ], [ %arraydestroy.element6, %[[ARRAY_DESTROY_BODY2]] ]
+ // CHECK-NEXT: %arraydestroy.element6 = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast5, i64 -1
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element6)
+ // CHECK-NEXT: %arraydestroy.done7 = icmp eq ptr %arraydestroy.element6, [[ARRAY_BEGIN]]
+ // CHECK-NEXT: br i1 %arraydestroy.done7, label %[[ARRAY_DESTROY_DONE2:.+]], label %[[ARRAY_DESTROY_BODY2]]
+
+
+ // CHECK: [[ARRAY_DESTROY_DONE2]]:
+ // CHECK-NEXT: br label %return
+}
+
+void LambdaInit() {
+ // CHECK-LABEL: define dso_local void @_Z10LambdaInitv()
+ auto S = [a = Printy("a"), b = ({
+ if (foo()) {
+ return;
+ // CHECK: if.then:
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: br label %return
+ }
+ Printy("b");
+ })]() { return a; };
+}
+
+void LifetimeExtended() {
+ // CHECK-LABEL: define dso_local void @_Z16LifetimeExtendedv
+ struct PrintyRefBind {
+ const Printy &a;
+ const Printy &b;
+ };
+ PrintyRefBind ps = {Printy("a"), ({
+ if (foo()) {
+ return;
+ // CHECK: if.then:
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev
+ // CHECK-NEXT: br label %return
+ }
+ Printy("b");
+ })};
+}
+
+void NewArrayInit() {
+ // CHECK-LABEL: define dso_local void @_Z12NewArrayInitv()
+ // CHECK: %array.init.end = alloca ptr, align 8
+ // CHECK: store ptr %0, ptr %array.init.end, align 8
+ Printy *array = new Printy[3]{
+ "a",
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK: store ptr %array.exp.next, ptr %array.init.end, align 8
+ "b",
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ // CHECK: store ptr %array.exp.next1, ptr %array.init.end, align 8
+ ({
+ if (foo()) {
+ return;
+ // CHECK: if.then:
+ // CHECK: br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body
+ }
+ "b";
+ // CHECK: if.end:
+ // CHECK: call void @_ZN6PrintyC1EPKc
+ })};
+ // CHECK: arraydestroy.body:
+ // CHECK-NEXT: %arraydestroy.elementPast = phi ptr [ %{{.*}}, %if.then ], [ %arraydestroy.element, %arraydestroy.body ]
+ // CHECK-NEXT: %arraydestroy.element = getelementptr inbounds %struct.Printy, ptr %arraydestroy.elementPast, i64 -1
+ // CHECK-NEXT: call void @_ZN6PrintyD1Ev(ptr noundef nonnull align 8 dereferenceable(8) %arraydestroy.element)
+ // CHECK-NEXT: %arraydestroy.done = icmp eq ptr %arraydestroy.element, %0
+ // CHECK-NEXT: br i1 %arraydestroy.done, label %arraydestroy.done{{.*}}, label %arraydestroy.body
+
+ // CHECK: arraydestroy.done{{.*}}: ; preds = %arraydestroy.body, %if.then
+ // CHECK-NEXT: br label %return
+}
+
+void ArrayInitWithContinue() {
+ // CHECK-LABEL: @_Z21ArrayInitWithContinuev
+ // Verify that we start to emit the array destructor.
+ // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
+ for (int i = 0; i < 1; ++i) {
+ Printy arr[2] = {"a", ({
+ if (foo()) {
+ continue;
+ }
+ "b";
+ })};
+ }
+}
diff --git a/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp
new file mode 100644
index 000000000000..06cc2069dbe9
--- /dev/null
+++ b/clang/test/CodeGenCoroutines/coro-suspend-cleanups.cpp
@@ -0,0 +1,93 @@
+// RUN: %clang_cc1 --std=c++20 -triple x86_64-linux-gnu -emit-llvm %s -o - | FileCheck %s
+
+#include "Inputs/coroutine.h"
+
+struct Printy {
+ Printy(const char *name) : name(name) {}
+ ~Printy() {}
+ const char *name;
+};
+
+struct coroutine {
+ struct promise_type;
+ std::coroutine_handle<promise_type> handle;
+ ~coroutine() {
+ if (handle) handle.destroy();
+ }
+};
+
+struct coroutine::promise_type {
+ coroutine get_return_object() {
+ return {std::coroutine_handle<promise_type>::from_promise(*this)};
+ }
+ std::suspend_never initial_suspend() noexcept { return {}; }
+ std::suspend_always final_suspend() noexcept { return {}; }
+ void return_void() {}
+ void unhandled_exception() {}
+};
+
+struct Awaiter : std::suspend_always {
+ Printy await_resume() { return {"awaited"}; }
+};
+
+int foo() { return 2; }
+
+coroutine ArrayInitCoro() {
+ // Verify that:
+ // - We do the necessary stores for array cleanups.
+ // - Array cleanups are called by await.cleanup.
+ // - We activate the cleanup after the first element and deactivate it in await.ready (see cleanup.isactive).
+
+ // CHECK-LABEL: define dso_local void @_Z13ArrayInitCorov
+ // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
+ // CHECK: %cleanup.isactive = alloca i1, align 1
+ Printy arr[2] = {
+ Printy("a"),
+ // CHECK: %arrayinit.begin = getelementptr inbounds [2 x %struct.Printy], ptr %arr.reload.addr, i64 0, i64 0
+ // CHECK-NEXT: %arrayinit.begin.spill.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 10
+ // CHECK-NEXT: store ptr %arrayinit.begin, ptr %arrayinit.begin.spill.addr, align 8
+ // CHECK-NEXT: store i1 true, ptr %cleanup.isactive.reload.addr, align 1
+ // CHECK-NEXT: store ptr %arrayinit.begin, ptr %arrayinit.endOfInit.reload.addr, align 8
+ // CHECK-NEXT: call void @_ZN6PrintyC1EPKc(ptr noundef nonnull align 8 dereferenceable(8) %arrayinit.begin, ptr noundef @.str)
+ // CHECK-NEXT: %arrayinit.element = getelementptr inbounds %struct.Printy, ptr %arrayinit.begin, i64 1
+ // CHECK-NEXT: %arrayinit.element.spill.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 11
+ // CHECK-NEXT: store ptr %arrayinit.element, ptr %arrayinit.element.spill.addr, align 8
+ // CHECK-NEXT: store ptr %arrayinit.element, ptr %arrayinit.endOfInit.reload.addr, align 8
+ co_await Awaiter{}
+ // CHECK-NEXT: @_ZNSt14suspend_always11await_readyEv
+ // CHECK-NEXT: br i1 %{{.+}}, label %await.ready, label %CoroSave30
+ };
+ // CHECK: await.cleanup: ; preds = %AfterCoroSuspend{{.*}}
+ // CHECK-NEXT: br label %cleanup{{.*}}.from.await.cleanup
+
+ // CHECK: cleanup{{.*}}.from.await.cleanup: ; preds = %await.cleanup
+ // CHECK: br label %cleanup{{.*}}
+
+ // CHECK: await.ready:
+ // CHECK-NEXT: %arrayinit.element.reload.addr = getelementptr inbounds %_Z13ArrayInitCorov.Frame, ptr %0, i32 0, i32 11
+ // CHECK-NEXT: %arrayinit.element.reload = load ptr, ptr %arrayinit.element.reload.addr, align 8
+ // CHECK-NEXT: call void @_ZN7Awaiter12await_resumeEv
+ // CHECK-NEXT: store i1 false, ptr %cleanup.isactive.reload.addr, align 1
+ // CHECK-NEXT: br label %cleanup{{.*}}.from.await.ready
+
+ // CHECK: cleanup{{.*}}: ; preds = %cleanup{{.*}}.from.await.ready, %cleanup{{.*}}.from.await.cleanup
+ // CHECK: %cleanup.is_active = load i1, ptr %cleanup.isactive.reload.addr, align 1
+ // CHECK-NEXT: br i1 %cleanup.is_active, label %cleanup.action, label %cleanup.done
+
+ // CHECK: cleanup.action:
+ // CHECK: %arraydestroy.isempty = icmp eq ptr %arrayinit.begin.reload{{.*}}, %{{.*}}
+ // CHECK-NEXT: br i1 %arraydestroy.isempty, label %arraydestroy.done{{.*}}, label %arraydestroy.body.from.cleanup.action
+ // Ignore rest of the array cleanup.
+}
+
+coroutine ArrayInitWithCoReturn() {
+ // CHECK-LABEL: define dso_local void @_Z21ArrayInitWithCoReturnv
+ // Verify that we start to emit the array destructor.
+ // CHECK: %arrayinit.endOfInit = alloca ptr, align 8
+ Printy arr[2] = {"a", ({
+ if (foo()) {
+ co_return;
+ }
+ "b";
+ })};
+}
diff --git a/clang/test/Driver/amdgpu-features.c b/clang/test/Driver/amdgpu-features.c
index a516bc6b7ff2..864744db203e 100644
--- a/clang/test/Driver/amdgpu-features.c
+++ b/clang/test/Driver/amdgpu-features.c
@@ -32,3 +32,9 @@
// RUN: %clang -### -target amdgcn -mcpu=gfx1010 -mno-cumode %s 2>&1 | FileCheck --check-prefix=NO-CUMODE %s
// NO-CUMODE: "-target-feature" "-cumode"
+
+// RUN: %clang -### -target amdgcn -mcpu=gfx1010 -mamdgpu-precise-memory-op %s 2>&1 | FileCheck --check-prefix=PREC-MEM %s
+// PREC-MEM: "-target-feature" "+precise-memory"
+
+// RUN: %clang -### -target amdgcn -mcpu=gfx1010 -mno-amdgpu-precise-memory-op %s 2>&1 | FileCheck --check-prefix=NO-PREC-MEM %s
+// NO-PREC-MEM-NOT: {{".*precise-memory"}}
diff --git a/clang/test/Driver/linker-wrapper-libs.c b/clang/test/Driver/linker-wrapper-libs.c
index 9a78200d7d3c..119e30685718 100644
--- a/clang/test/Driver/linker-wrapper-libs.c
+++ b/clang/test/Driver/linker-wrapper-libs.c
@@ -44,6 +44,8 @@ int bar() { return weak; }
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld %t.o %t.a -o a.out 2>&1 \
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
+// RUN: --linker-path=/usr/bin/ld %t.a %t.o -o a.out 2>&1 \
// RUN: | FileCheck %s --check-prefix=LIBRARY-RESOLVES
// LIBRARY-RESOLVES: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa -mcpu=gfx1030 {{.*}}.o {{.*}}.o
@@ -66,6 +68,8 @@ int bar() { return weak; }
// RUN: %clang -cc1 %s -triple x86_64-unknown-linux-gnu -emit-obj -o %t.o -fembed-offload-object=%t.out
// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
// RUN: --linker-path=/usr/bin/ld %t.o %t.a -o a.out 2>&1 \
+// RUN: clang-linker-wrapper --host-triple=x86_64-unknown-linux-gnu --dry-run \
+// RUN: --linker-path=/usr/bin/ld %t.a %t.o -o a.out 2>&1 \
// RUN: | FileCheck %s --check-prefix=LIBRARY-GLOBAL
// LIBRARY-GLOBAL: clang{{.*}} -o {{.*}}.img --target=amdgcn-amd-amdhsa -mcpu=gfx1030 {{.*}}.o {{.*}}.o
diff --git a/clang/test/Driver/lld-repro.c b/clang/test/Driver/lld-repro.c
index 9457dd334b5b..61904c0e6df3 100644
--- a/clang/test/Driver/lld-repro.c
+++ b/clang/test/Driver/lld-repro.c
@@ -4,12 +4,12 @@
// RUN: echo "-nostartfiles -nostdlib -fuse-ld=lld -gen-reproducer=error -fcrash-diagnostics-dir=%t" \
// RUN: | sed -e 's/\\/\\\\/g' > %t.rsp
-// RUN: not %clang %s @%t.rsp -fcrash-diagnostics=all 2>&1 \
+// RUN: not %clang %s @%t.rsp -fcrash-diagnostics=all -o /dev/null 2>&1 \
// RUN: | FileCheck %s
// Test that the reproducer can still be created even when the input source cannot be preprocessed
// again, like when reading from stdin.
-// RUN: not %clang -x c - @%t.rsp -fcrash-diagnostics=all 2>&1 < %s \
+// RUN: not %clang -x c - @%t.rsp -fcrash-diagnostics=all -o /dev/null 2>&1 < %s \
// RUN: | FileCheck %s
// check that we still get lld's output
@@ -20,9 +20,9 @@
// CHECK-NEXT: note: diagnostic msg:
// CHECK: ********************
-// RUN: not %clang %s @%t.rsp -fcrash-diagnostics=compiler 2>&1 \
+// RUN: not %clang %s @%t.rsp -fcrash-diagnostics=compiler -o /dev/null 2>&1 \
// RUN: | FileCheck %s --check-prefix=NO-LINKER
-// RUN: not %clang %s @%t.rsp 2>&1 \
+// RUN: not %clang %s @%t.rsp -o /dev/null 2>&1 \
// RUN: | FileCheck %s --check-prefix=NO-LINKER
// NO-LINKER-NOT: Preprocessed source(s) and associated run script(s) are located at:
diff --git a/clang/test/Modules/home-is-cwd-search-paths.c b/clang/test/Modules/home-is-cwd-search-paths.c
new file mode 100644
index 000000000000..0b8954e691bc
--- /dev/null
+++ b/clang/test/Modules/home-is-cwd-search-paths.c
@@ -0,0 +1,34 @@
+// This test demonstrates how -fmodule-map-file-home-is-cwd with -fmodules-embed-all-files
+// extend the importer search paths by relying on the side effects of pragma diagnostic
+// mappings deserialization.
+
+// RUN: rm -rf %t
+// RUN: split-file %s %t
+
+//--- dir1/a.modulemap
+module a { header "a.h" }
+//--- dir1/a.h
+#include "search.h"
+// The first compilation is configured such that -I search does contain the search.h header.
+//--- dir1/search/search.h
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wparentheses"
+#pragma clang diagnostic pop
+// RUN: cd %t/dir1 && %clang_cc1 -fmodules -I search \
+// RUN: -emit-module -fmodule-name=a a.modulemap -o %t/a.pcm \
+// RUN: -fmodules-embed-all-files -fmodule-map-file-home-is-cwd
+
+//--- dir2/b.modulemap
+module b { header "b.h" }
+//--- dir2/b.h
+#include "search.h" // expected-error{{'search.h' file not found}}
+// The second compilation is configured such that -I search is an empty directory.
+// However, since b.pcm simply embeds the headers as "search/search.h", this compilation
+// ends up seeing it too. This relies solely on ASTReader::ReadPragmaDiagnosticMappings()
+// eagerly reading the corresponding INPUT_FILE record before header search happens.
+// Removing the eager deserialization makes this header invisible and so does removing
+// the pragma directives.
+// RUN: mkdir %t/dir2/search
+// RUN: cd %t/dir2 && %clang_cc1 -fmodules -I search \
+// RUN: -emit-module -fmodule-name=b b.modulemap -o %t/b.pcm \
+// RUN: -fmodule-file=%t/a.pcm -verify
diff --git a/clang/test/OpenMP/nvptx_target_teams_generic_loop_codegen.cpp b/clang/test/OpenMP/nvptx_target_teams_generic_loop_codegen.cpp
index 5226b7498e4c..c89c6eb65706 100644
--- a/clang/test/OpenMP/nvptx_target_teams_generic_loop_codegen.cpp
+++ b/clang/test/OpenMP/nvptx_target_teams_generic_loop_codegen.cpp
@@ -320,23 +320,31 @@ int bar(int n){
//
//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33
-// CHECK1-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR4:[0-9]+]] {
+// CHECK1-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR4:[0-9]+]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
// CHECK1-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 8
// CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_kernel_environment, ptr [[DYN_PTR]])
// CHECK1-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
// CHECK1-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
// CHECK1: user_code.entry:
// CHECK1-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]])
+// CHECK1-NEXT: [[TMP3:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK1-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] to i1
+// CHECK1-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK1-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4
// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP_]], align 4
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]]) #[[ATTR2]]
+// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]], i64 [[TMP4]]) #[[ATTR2]]
// CHECK1-NEXT: call void @__kmpc_target_deinit()
// CHECK1-NEXT: ret void
// CHECK1: worker.exit:
@@ -344,11 +352,12 @@ int bar(int n){
//
//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR1]] {
+// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
@@ -360,6 +369,7 @@ int bar(int n){
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
// CHECK1-NEXT: store i32 9, ptr [[DOTOMP_COMB_UB]], align 4
@@ -1566,23 +1576,31 @@ int bar(int n){
//
//
// CHECK2-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33
-// CHECK2-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR4:[0-9]+]] {
+// CHECK2-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR4:[0-9]+]] {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK2-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
// CHECK2-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4
// CHECK2-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
// CHECK2-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK2-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 8
// CHECK2-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_kernel_environment, ptr [[DYN_PTR]])
// CHECK2-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
// CHECK2-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
// CHECK2: user_code.entry:
// CHECK2-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]])
+// CHECK2-NEXT: [[TMP3:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK2-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] to i1
+// CHECK2-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK2-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK2-NEXT: [[TMP4:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED]], align 8
// CHECK2-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4
// CHECK2-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP_]], align 4
-// CHECK2-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]]) #[[ATTR2]]
+// CHECK2-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]], i64 [[TMP4]]) #[[ATTR2]]
// CHECK2-NEXT: call void @__kmpc_target_deinit()
// CHECK2-NEXT: ret void
// CHECK2: worker.exit:
@@ -1590,11 +1608,12 @@ int bar(int n){
//
//
// CHECK2-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined
-// CHECK2-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR1]] {
+// CHECK2-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1]] {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK2-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK2-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
// CHECK2-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[TMP:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
@@ -1606,6 +1625,7 @@ int bar(int n){
// CHECK2-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK2-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK2-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// CHECK2-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 8
// CHECK2-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
// CHECK2-NEXT: store i32 9, ptr [[DOTOMP_COMB_UB]], align 4
@@ -2801,23 +2821,31 @@ int bar(int n){
//
//
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33
-// CHECK3-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR4:[0-9]+]] {
+// CHECK3-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR4:[0-9]+]] {
// CHECK3-NEXT: entry:
// CHECK3-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4
// CHECK3-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 4
+// CHECK3-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i32, align 4
+// CHECK3-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4
// CHECK3-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4
// CHECK3-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 4
+// CHECK3-NEXT: store i32 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 4
// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 4
// CHECK3-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_kernel_environment, ptr [[DYN_PTR]])
// CHECK3-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
// CHECK3-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
// CHECK3: user_code.entry:
// CHECK3-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB1]])
+// CHECK3-NEXT: [[TMP3:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK3-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP3]] to i1
+// CHECK3-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK3-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED]], align 4
// CHECK3-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4
// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP_]], align 4
-// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]]) #[[ATTR2]]
+// CHECK3-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], ptr [[TMP0]], i32 [[TMP4]]) #[[ATTR2]]
// CHECK3-NEXT: call void @__kmpc_target_deinit()
// CHECK3-NEXT: ret void
// CHECK3: worker.exit:
@@ -2825,11 +2853,12 @@ int bar(int n){
//
//
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9ftemplateIiET_i_l33_omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]]) #[[ATTR1]] {
+// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[B:%.*]], i32 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1]] {
// CHECK3-NEXT: entry:
// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
// CHECK3-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 4
+// CHECK3-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
@@ -2841,6 +2870,7 @@ int bar(int n){
// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
// CHECK3-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 4
+// CHECK3-NEXT: store i32 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 4
// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[B_ADDR]], align 4
// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
// CHECK3-NEXT: store i32 9, ptr [[DOTOMP_COMB_UB]], align 4
diff --git a/clang/test/OpenMP/nvptx_target_teams_generic_loop_generic_mode_codegen.cpp b/clang/test/OpenMP/nvptx_target_teams_generic_loop_generic_mode_codegen.cpp
index ca2670f0cd64..f0effa760dcd 100644
--- a/clang/test/OpenMP/nvptx_target_teams_generic_loop_generic_mode_codegen.cpp
+++ b/clang/test/OpenMP/nvptx_target_teams_generic_loop_generic_mode_codegen.cpp
@@ -30,17 +30,20 @@ int main(int argc, char **argv) {
#endif
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24
-// CHECK1-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK1-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[ARGC_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[ARGC_CASTED:%.*]] = alloca i64, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
// CHECK1-NEXT: store i64 [[ARGC]], ptr [[ARGC_ADDR]], align 8
// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK1-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_kernel_environment, ptr [[DYN_PTR]])
// CHECK1-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
@@ -50,9 +53,14 @@ int main(int argc, char **argv) {
// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
// CHECK1-NEXT: store i32 [[TMP3]], ptr [[ARGC_CASTED]], align 4
// CHECK1-NEXT: [[TMP4:%.*]] = load i64, ptr [[ARGC_CASTED]], align 8
+// CHECK1-NEXT: [[TMP5:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK1-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP5]] to i1
+// CHECK1-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK1-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK1-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4
// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP_]], align 4
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], i64 [[TMP4]], ptr [[TMP0]]) #[[ATTR2:[0-9]+]]
+// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], i64 [[TMP4]], ptr [[TMP0]], i64 [[TMP6]]) #[[ATTR2:[0-9]+]]
// CHECK1-NEXT: call void @__kmpc_target_deinit()
// CHECK1-NEXT: ret void
// CHECK1: worker.exit:
@@ -60,56 +68,55 @@ int main(int argc, char **argv) {
//
//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR1:[0-9]+]] {
+// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1:[0-9]+]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[ARGC_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR_2:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[ARGC_CASTED:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [4 x ptr], align 8
+// CHECK1-NEXT: [[I4:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK1-NEXT: store i64 [[ARGC]], ptr [[ARGC_ADDR]], align 8
// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP2]], 0
// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK1-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK1-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK1-NEXT: [[SUB3:%.*]] = sub nsw i32 [[DIV]], 1
+// CHECK1-NEXT: store i32 [[SUB3]], ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK1-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
// CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP3]]
// CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
// CHECK1: omp.precond.then:
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_COMB_UB]], align 4
// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
// CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK1-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 91, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 [[NVPTX_NUM_THREADS]])
+// CHECK1-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
+// CHECK1-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP7]], [[TMP8]]
+// CHECK1-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
// CHECK1: cond.true:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK1-NEXT: br label [[COND_END:%.*]]
// CHECK1: cond.false:
// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
@@ -122,177 +129,54 @@ int main(int argc, char **argv) {
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP13]], 1
-// CHECK1-NEXT: [[CMP5:%.*]] = icmp slt i32 [[TMP12]], [[ADD]]
-// CHECK1-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP15:%.*]] = zext i32 [[TMP14]] to i64
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = zext i32 [[TMP16]] to i64
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK1-NEXT: store i32 [[TMP18]], ptr [[ARGC_CASTED]], align 4
-// CHECK1-NEXT: [[TMP19:%.*]] = load i64, ptr [[ARGC_CASTED]], align 8
-// CHECK1-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 0
-// CHECK1-NEXT: [[TMP21:%.*]] = inttoptr i64 [[TMP15]] to ptr
-// CHECK1-NEXT: store ptr [[TMP21]], ptr [[TMP20]], align 8
-// CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 1
-// CHECK1-NEXT: [[TMP23:%.*]] = inttoptr i64 [[TMP17]] to ptr
-// CHECK1-NEXT: store ptr [[TMP23]], ptr [[TMP22]], align 8
-// CHECK1-NEXT: [[TMP24:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 2
-// CHECK1-NEXT: [[TMP25:%.*]] = inttoptr i64 [[TMP19]] to ptr
-// CHECK1-NEXT: store ptr [[TMP25]], ptr [[TMP24]], align 8
-// CHECK1-NEXT: [[TMP26:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i64 0, i64 3
-// CHECK1-NEXT: store ptr [[TMP0]], ptr [[TMP26]], align 8
-// CHECK1-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
-// CHECK1-NEXT: call void @__kmpc_parallel_51(ptr @[[GLOB1]], i32 [[TMP28]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS]], i64 4)
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP29]], [[TMP30]]
-// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP32:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP31]], [[TMP32]]
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP33:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP34:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP33]], [[TMP34]]
-// CHECK1-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP35:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP36:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: [[CMP9:%.*]] = icmp sgt i32 [[TMP35]], [[TMP36]]
-// CHECK1-NEXT: br i1 [[CMP9]], label [[COND_TRUE10:%.*]], label [[COND_FALSE11:%.*]]
-// CHECK1: cond.true10:
-// CHECK1-NEXT: [[TMP37:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: br label [[COND_END12:%.*]]
-// CHECK1: cond.false11:
-// CHECK1-NEXT: [[TMP38:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END12]]
-// CHECK1: cond.end12:
-// CHECK1-NEXT: [[COND13:%.*]] = phi i32 [ [[TMP37]], [[COND_TRUE10]] ], [ [[TMP38]], [[COND_FALSE11]] ]
-// CHECK1-NEXT: store i32 [[COND13]], ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP39:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP39]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP40:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP41:%.*]] = load i32, ptr [[TMP40]], align 4
-// CHECK1-NEXT: call void @__kmpc_distribute_static_fini(ptr @[[GLOB2]], i32 [[TMP41]])
-// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK1: omp.precond.end:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined_omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[ARGC_ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I4:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[ARGC]], ptr [[ARGC_ADDR]], align 8
-// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK1-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP2]], 0
-// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK1-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK1-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP3]]
-// CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK1: omp.precond.then:
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP5:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP5]] to i32
-// CHECK1-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV3:%.*]] = trunc i64 [[TMP6]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV3]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB3:[0-9]+]], i32 [[TMP8]], i32 33, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP9]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[CONV5:%.*]] = sext i32 [[TMP10]] to i64
-// CHECK1-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CMP6:%.*]] = icmp ule i64 [[CONV5]], [[TMP11]]
+// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// CHECK1-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP12]], [[TMP13]]
// CHECK1-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP12]], 1
+// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP14]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
-// CHECK1-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[I4]]) #[[ATTR5:[0-9]+]]
-// CHECK1-NEXT: [[CALL7:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[TMP0]]) #[[ATTR5]]
+// CHECK1-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[I4]]) #[[ATTR4:[0-9]+]]
+// CHECK1-NEXT: [[CALL7:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[TMP0]]) #[[ATTR4]]
// CHECK1-NEXT: [[ADD8:%.*]] = add nsw i32 [[CALL]], [[CALL7]]
-// CHECK1-NEXT: [[CALL9:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[ARGC_ADDR]]) #[[ATTR5]]
+// CHECK1-NEXT: [[CALL9:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[ARGC_ADDR]]) #[[ATTR4]]
// CHECK1-NEXT: [[ADD10:%.*]] = add nsw i32 [[ADD8]], [[CALL9]]
// CHECK1-NEXT: store i32 [[ADD10]], ptr [[TMP0]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP13]], [[TMP14]]
+// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP15]], 1
// CHECK1-NEXT: store i32 [[ADD11]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB3]], i32 [[TMP16]])
+// CHECK1-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
+// CHECK1-NEXT: call void @__kmpc_distribute_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
// CHECK1: omp.precond.end:
// CHECK1-NEXT: ret void
//
//
// CHECK2-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24
-// CHECK2-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i32 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR0:[0-9]+]] {
+// CHECK2-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i32 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i32 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR0:[0-9]+]] {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4
// CHECK2-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[ARGC_CASTED:%.*]] = alloca i32, align 4
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4
// CHECK2-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4
// CHECK2-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4
// CHECK2-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
+// CHECK2-NEXT: store i32 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 4
// CHECK2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
// CHECK2-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_kernel_environment, ptr [[DYN_PTR]])
// CHECK2-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
@@ -302,9 +186,14 @@ int main(int argc, char **argv) {
// CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
// CHECK2-NEXT: store i32 [[TMP3]], ptr [[ARGC_CASTED]], align 4
// CHECK2-NEXT: [[TMP4:%.*]] = load i32, ptr [[ARGC_CASTED]], align 4
+// CHECK2-NEXT: [[TMP5:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK2-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP5]] to i1
+// CHECK2-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK2-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK2-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__CASTED]], align 4
// CHECK2-NEXT: store i32 0, ptr [[DOTZERO_ADDR]], align 4
// CHECK2-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP_]], align 4
-// CHECK2-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], i32 [[TMP4]], ptr [[TMP0]]) #[[ATTR2:[0-9]+]]
+// CHECK2-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined(ptr [[DOTTHREADID_TEMP_]], ptr [[DOTZERO_ADDR]], i32 [[TMP4]], ptr [[TMP0]], i32 [[TMP6]]) #[[ATTR2:[0-9]+]]
// CHECK2-NEXT: call void @__kmpc_target_deinit()
// CHECK2-NEXT: ret void
// CHECK2: worker.exit:
@@ -312,56 +201,55 @@ int main(int argc, char **argv) {
//
//
// CHECK2-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined
-// CHECK2-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR1:[0-9]+]] {
+// CHECK2-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i32 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1:[0-9]+]] {
// CHECK2-NEXT: entry:
// CHECK2-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
// CHECK2-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
// CHECK2-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
+// CHECK2-NEXT: [[DOTCAPTURE_EXPR_2:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK2-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[ARGC_CASTED:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [4 x ptr], align 4
+// CHECK2-NEXT: [[I4:%.*]] = alloca i32, align 4
// CHECK2-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
// CHECK2-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
// CHECK2-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4
// CHECK2-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
+// CHECK2-NEXT: store i32 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 4
// CHECK2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
// CHECK2-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK2-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK2-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
// CHECK2-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP2]], 0
// CHECK2-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK2-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK2-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK2-NEXT: [[SUB3:%.*]] = sub nsw i32 [[DIV]], 1
+// CHECK2-NEXT: store i32 [[SUB3]], ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK2-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
// CHECK2-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP3]]
// CHECK2-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
// CHECK2: omp.precond.then:
// CHECK2-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK2-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK2-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK2-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_COMB_UB]], align 4
// CHECK2-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
// CHECK2-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK2-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
// CHECK2-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
// CHECK2-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK2-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 91, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 [[NVPTX_NUM_THREADS]])
+// CHECK2-NEXT: call void @__kmpc_distribute_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
// CHECK2-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP7]], [[TMP8]]
-// CHECK2-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// CHECK2-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
+// CHECK2-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP7]], [[TMP8]]
+// CHECK2-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
// CHECK2: cond.true:
-// CHECK2-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
+// CHECK2-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_2]], align 4
// CHECK2-NEXT: br label [[COND_END:%.*]]
// CHECK2: cond.false:
// CHECK2-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
@@ -374,155 +262,34 @@ int main(int argc, char **argv) {
// CHECK2-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
// CHECK2: omp.inner.for.cond:
// CHECK2-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP13]], 1
-// CHECK2-NEXT: [[CMP5:%.*]] = icmp slt i32 [[TMP12]], [[ADD]]
-// CHECK2-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK2: omp.inner.for.body:
-// CHECK2-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK2-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP16:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK2-NEXT: store i32 [[TMP16]], ptr [[ARGC_CASTED]], align 4
-// CHECK2-NEXT: [[TMP17:%.*]] = load i32, ptr [[ARGC_CASTED]], align 4
-// CHECK2-NEXT: [[TMP18:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i32 0, i32 0
-// CHECK2-NEXT: [[TMP19:%.*]] = inttoptr i32 [[TMP14]] to ptr
-// CHECK2-NEXT: store ptr [[TMP19]], ptr [[TMP18]], align 4
-// CHECK2-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i32 0, i32 1
-// CHECK2-NEXT: [[TMP21:%.*]] = inttoptr i32 [[TMP15]] to ptr
-// CHECK2-NEXT: store ptr [[TMP21]], ptr [[TMP20]], align 4
-// CHECK2-NEXT: [[TMP22:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i32 0, i32 2
-// CHECK2-NEXT: [[TMP23:%.*]] = inttoptr i32 [[TMP17]] to ptr
-// CHECK2-NEXT: store ptr [[TMP23]], ptr [[TMP22]], align 4
-// CHECK2-NEXT: [[TMP24:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS]], i32 0, i32 3
-// CHECK2-NEXT: store ptr [[TMP0]], ptr [[TMP24]], align 4
-// CHECK2-NEXT: [[TMP25:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK2-NEXT: [[TMP26:%.*]] = load i32, ptr [[TMP25]], align 4
-// CHECK2-NEXT: call void @__kmpc_parallel_51(ptr @[[GLOB1]], i32 [[TMP26]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS]], i32 4)
-// CHECK2-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK2: omp.inner.for.inc:
-// CHECK2-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK2-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP27]], [[TMP28]]
-// CHECK2-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK2-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK2-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP29]], [[TMP30]]
-// CHECK2-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK2-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP32:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK2-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP31]], [[TMP32]]
-// CHECK2-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP33:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP34:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: [[CMP9:%.*]] = icmp sgt i32 [[TMP33]], [[TMP34]]
-// CHECK2-NEXT: br i1 [[CMP9]], label [[COND_TRUE10:%.*]], label [[COND_FALSE11:%.*]]
-// CHECK2: cond.true10:
-// CHECK2-NEXT: [[TMP35:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: br label [[COND_END12:%.*]]
-// CHECK2: cond.false11:
-// CHECK2-NEXT: [[TMP36:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: br label [[COND_END12]]
-// CHECK2: cond.end12:
-// CHECK2-NEXT: [[COND13:%.*]] = phi i32 [ [[TMP35]], [[COND_TRUE10]] ], [ [[TMP36]], [[COND_FALSE11]] ]
-// CHECK2-NEXT: store i32 [[COND13]], ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK2-NEXT: [[TMP37:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK2-NEXT: store i32 [[TMP37]], ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK2: omp.inner.for.end:
-// CHECK2-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK2: omp.loop.exit:
-// CHECK2-NEXT: [[TMP38:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK2-NEXT: [[TMP39:%.*]] = load i32, ptr [[TMP38]], align 4
-// CHECK2-NEXT: call void @__kmpc_distribute_static_fini(ptr @[[GLOB2]], i32 [[TMP39]])
-// CHECK2-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK2: omp.precond.end:
-// CHECK2-NEXT: ret void
-//
-//
-// CHECK2-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l24_omp_outlined_omp_outlined
-// CHECK2-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], i32 noundef [[ARGC:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR1]] {
-// CHECK2-NEXT: entry:
-// CHECK2-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK2-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK2-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[ARGC_ADDR:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK2-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK2-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK2-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK2-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK2-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK2-NEXT: store i32 [[ARGC]], ptr [[ARGC_ADDR]], align 4
-// CHECK2-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK2-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK2-NEXT: [[TMP1:%.*]] = load i32, ptr [[ARGC_ADDR]], align 4
-// CHECK2-NEXT: store i32 [[TMP1]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK2-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK2-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP2]], 0
-// CHECK2-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK2-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK2-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK2-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK2-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP3]]
-// CHECK2-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK2: omp.precond.then:
-// CHECK2-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK2-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK2-NEXT: store i32 [[TMP4]], ptr [[DOTOMP_UB]], align 4
-// CHECK2-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK2-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK2-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_LB]], align 4
-// CHECK2-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4
-// CHECK2-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK2-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK2-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK2-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK2-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB3:[0-9]+]], i32 [[TMP8]], i32 33, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK2-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK2-NEXT: store i32 [[TMP9]], ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK2: omp.inner.for.cond:
-// CHECK2-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK2-NEXT: [[CMP4:%.*]] = icmp ule i32 [[TMP10]], [[TMP11]]
-// CHECK2-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// CHECK2-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// CHECK2-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP12]], [[TMP13]]
+// CHECK2-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK2: omp.inner.for.body:
-// CHECK2-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP12]], 1
+// CHECK2-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK2-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP14]], 1
// CHECK2-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK2-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
-// CHECK2-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[I3]]) #[[ATTR5:[0-9]+]]
-// CHECK2-NEXT: [[CALL5:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[TMP0]]) #[[ATTR5]]
-// CHECK2-NEXT: [[ADD6:%.*]] = add nsw i32 [[CALL]], [[CALL5]]
-// CHECK2-NEXT: [[CALL7:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[ARGC_ADDR]]) #[[ATTR5]]
-// CHECK2-NEXT: [[ADD8:%.*]] = add nsw i32 [[ADD6]], [[CALL7]]
-// CHECK2-NEXT: store i32 [[ADD8]], ptr [[TMP0]], align 4
+// CHECK2-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
+// CHECK2-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[I4]]) #[[ATTR4:[0-9]+]]
+// CHECK2-NEXT: [[CALL7:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[TMP0]]) #[[ATTR4]]
+// CHECK2-NEXT: [[ADD8:%.*]] = add nsw i32 [[CALL]], [[CALL7]]
+// CHECK2-NEXT: [[CALL9:%.*]] = call noundef i32 @_Z3fooPi(ptr noundef [[ARGC_ADDR]]) #[[ATTR4]]
+// CHECK2-NEXT: [[ADD10:%.*]] = add nsw i32 [[ADD8]], [[CALL9]]
+// CHECK2-NEXT: store i32 [[ADD10]], ptr [[TMP0]], align 4
// CHECK2-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK2: omp.body.continue:
// CHECK2-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK2: omp.inner.for.inc:
-// CHECK2-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK2-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK2-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP13]], [[TMP14]]
-// CHECK2-NEXT: store i32 [[ADD9]], ptr [[DOTOMP_IV]], align 4
+// CHECK2-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK2-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK2-NEXT: store i32 [[ADD11]], ptr [[DOTOMP_IV]], align 4
// CHECK2-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK2: omp.inner.for.end:
// CHECK2-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK2: omp.loop.exit:
-// CHECK2-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK2-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK2-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB3]], i32 [[TMP16]])
+// CHECK2-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK2-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
+// CHECK2-NEXT: call void @__kmpc_distribute_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
// CHECK2-NEXT: br label [[OMP_PRECOND_END]]
// CHECK2: omp.precond.end:
// CHECK2-NEXT: ret void
diff --git a/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp b/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp
index 22cf534bf0ba..3f752ac663f4 100644
--- a/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp
+++ b/clang/test/OpenMP/target_teams_generic_loop_codegen.cpp
@@ -28,1118 +28,6 @@ int foo() {
return 0;
}
#endif
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@_Z3foov
-// IR-PCH-HOST-SAME: () #[[ATTR0:[0-9]+]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[I:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[SUM:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-PCH-HOST-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[TMP0:%.*]] = load i32, ptr [[J]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP0]], ptr [[J_CASTED]], align 4
-// IR-PCH-HOST-NEXT: [[TMP1:%.*]] = load i64, ptr [[J_CASTED]], align 8
-// IR-PCH-HOST-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22(i64 [[TMP1]], ptr [[SUM]]) #[[ATTR2:[0-9]+]]
-// IR-PCH-HOST-NEXT: ret i32 0
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22
-// IR-PCH-HOST-SAME: (i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1:[0-9]+]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: store i64 [[J]], ptr [[J_ADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP1:%.*]] = load i32, ptr [[J_ADDR]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP1]], ptr [[J_CASTED]], align 4
-// IR-PCH-HOST-NEXT: [[TMP2:%.*]] = load i64, ptr [[J_CASTED]], align 8
-// IR-PCH-HOST-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4:[0-9]+]], i32 2, ptr @.omp_outlined., i64 [[TMP2]], ptr [[TMP0]])
-// IR-PCH-HOST-NEXT: ret void
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@.omp_outlined.
-// IR-PCH-HOST-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[SUM1:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-PCH-HOST-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[_TMP2:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J3:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[I:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J4:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// IR-PCH-HOST-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store i64 [[J]], ptr [[J_ADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM1]], i32 0, i32 0, i32 0
-// IR-PCH-HOST-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP1]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// IR-PCH-HOST: omp.arrayinit.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP1]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// IR-PCH-HOST: omp.arrayinit.done:
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
-// IR-PCH-HOST-NEXT: store i32 99, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-HOST-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// IR-PCH-HOST-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP3]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// IR-PCH-HOST-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// IR-PCH-HOST-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// IR-PCH-HOST: cond.true:
-// IR-PCH-HOST-NEXT: br label [[COND_END:%.*]]
-// IR-PCH-HOST: cond.false:
-// IR-PCH-HOST-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: br label [[COND_END]]
-// IR-PCH-HOST: cond.end:
-// IR-PCH-HOST-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// IR-PCH-HOST-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// IR-PCH-HOST: omp.inner.for.cond:
-// IR-PCH-HOST-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// IR-PCH-HOST-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// IR-PCH-HOST-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// IR-PCH-HOST: omp.inner.for.body:
-// IR-PCH-HOST-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// IR-PCH-HOST-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// IR-PCH-HOST-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-HOST-NEXT: [[TMP12:%.*]] = zext i32 [[TMP11]] to i64
-// IR-PCH-HOST-NEXT: [[TMP13:%.*]] = load i32, ptr [[J3]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP13]], ptr [[J_CASTED]], align 4
-// IR-PCH-HOST-NEXT: [[TMP14:%.*]] = load i64, ptr [[J_CASTED]], align 8
-// IR-PCH-HOST-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 4, ptr @.omp_outlined..1, i64 [[TMP10]], i64 [[TMP12]], i64 [[TMP14]], ptr [[SUM1]])
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// IR-PCH-HOST: omp.inner.for.inc:
-// IR-PCH-HOST-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// IR-PCH-HOST-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// IR-PCH-HOST-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP15]], [[TMP16]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_COND]]
-// IR-PCH-HOST: omp.inner.for.end:
-// IR-PCH-HOST-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// IR-PCH-HOST: omp.loop.exit:
-// IR-PCH-HOST-NEXT: [[TMP17:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP18:%.*]] = load i32, ptr [[TMP17]], align 4
-// IR-PCH-HOST-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2:[0-9]+]], i32 [[TMP18]])
-// IR-PCH-HOST-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-HOST-NEXT: [[TMP20:%.*]] = icmp ne i32 [[TMP19]], 0
-// IR-PCH-HOST-NEXT: br i1 [[TMP20]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// IR-PCH-HOST: .omp.lastprivate.then:
-// IR-PCH-HOST-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-PCH-HOST-NEXT: [[TMP21:%.*]] = load i32, ptr [[J3]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP21]], ptr [[J_ADDR]], align 4
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// IR-PCH-HOST: .omp.lastprivate.done:
-// IR-PCH-HOST-NEXT: [[TMP22:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: store ptr [[SUM1]], ptr [[TMP22]], align 8
-// IR-PCH-HOST-NEXT: [[TMP23:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
-// IR-PCH-HOST-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3:[0-9]+]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @.omp.reduction.reduction_func.2, ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: switch i32 [[TMP25]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// IR-PCH-HOST-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// IR-PCH-HOST-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// IR-PCH-HOST-NEXT: ]
-// IR-PCH-HOST: .omp.reduction.case1:
-// IR-PCH-HOST-NEXT: [[TMP26:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP0]], [[TMP26]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE10:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST6:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT8:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-PCH-HOST-NEXT: [[TMP28:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP27]], [[TMP28]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD7]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT8]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE9:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT8]], [[TMP26]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE9]], label [[OMP_ARRAYCPY_DONE10]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH-HOST: omp.arraycpy.done10:
-// IR-PCH-HOST-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH-HOST: .omp.reduction.case2:
-// IR-PCH-HOST-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY11:%.*]] = icmp eq ptr [[TMP0]], [[TMP29]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY11]], label [[OMP_ARRAYCPY_DONE18:%.*]], label [[OMP_ARRAYCPY_BODY12:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body12:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST13:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT16:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST14:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT15:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-PCH-HOST-NEXT: [[TMP30:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], align 4
-// IR-PCH-HOST-NEXT: [[TMP31:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 [[TMP30]] monotonic, align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT15]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT16]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP29]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY12]]
-// IR-PCH-HOST: omp.arraycpy.done18:
-// IR-PCH-HOST-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH-HOST: .omp.reduction.default:
-// IR-PCH-HOST-NEXT: ret void
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@.omp_outlined..1
-// IR-PCH-HOST-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-HOST-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J3:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[SUM4:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-PCH-HOST-NEXT: [[I:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[J5:%.*]] = alloca i32, align 4
-// IR-PCH-HOST-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// IR-PCH-HOST-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-PCH-HOST-NEXT: store i64 [[J]], ptr [[J_ADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR]], align 8
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// IR-PCH-HOST-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-HOST-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// IR-PCH-HOST-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP2]] to i32
-// IR-PCH-HOST-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// IR-PCH-HOST-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-HOST-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i32 0, i32 0, i32 0
-// IR-PCH-HOST-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP3]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// IR-PCH-HOST: omp.arrayinit.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// IR-PCH-HOST-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP3]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// IR-PCH-HOST: omp.arrayinit.done:
-// IR-PCH-HOST-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-// IR-PCH-HOST-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP5]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// IR-PCH-HOST-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-HOST-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP6]], 99
-// IR-PCH-HOST-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// IR-PCH-HOST: cond.true:
-// IR-PCH-HOST-NEXT: br label [[COND_END:%.*]]
-// IR-PCH-HOST: cond.false:
-// IR-PCH-HOST-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-HOST-NEXT: br label [[COND_END]]
-// IR-PCH-HOST: cond.end:
-// IR-PCH-HOST-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP7]], [[COND_FALSE]] ]
-// IR-PCH-HOST-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// IR-PCH-HOST-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP8]], ptr [[DOTOMP_IV]], align 4
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// IR-PCH-HOST: omp.inner.for.cond:
-// IR-PCH-HOST-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3:![0-9]+]]
-// IR-PCH-HOST-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP9]], [[TMP10]]
-// IR-PCH-HOST-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// IR-PCH-HOST: omp.inner.for.body:
-// IR-PCH-HOST-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP11]], 10
-// IR-PCH-HOST-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
-// IR-PCH-HOST-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD]], ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[DIV7:%.*]] = sdiv i32 [[TMP13]], 10
-// IR-PCH-HOST-NEXT: [[MUL8:%.*]] = mul nsw i32 [[DIV7]], 10
-// IR-PCH-HOST-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP12]], [[MUL8]]
-// IR-PCH-HOST-NEXT: [[MUL9:%.*]] = mul nsw i32 [[SUB]], 1
-// IR-PCH-HOST-NEXT: [[ADD10:%.*]] = add nsw i32 0, [[MUL9]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD10]], ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[TMP14:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[TMP15:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP15]] to i64
-// IR-PCH-HOST-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i64 0, i64 [[IDXPROM]]
-// IR-PCH-HOST-NEXT: [[TMP16:%.*]] = load i32, ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP16]] to i64
-// IR-PCH-HOST-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM11]]
-// IR-PCH-HOST-NEXT: [[TMP17:%.*]] = load i32, ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP17]], [[TMP14]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD13]], ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// IR-PCH-HOST: omp.body.continue:
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// IR-PCH-HOST: omp.inner.for.inc:
-// IR-PCH-HOST-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP18]], 1
-// IR-PCH-HOST-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-HOST-NEXT: br label [[OMP_INNER_FOR_COND]], !llvm.loop [[LOOP4:![0-9]+]]
-// IR-PCH-HOST: omp.inner.for.end:
-// IR-PCH-HOST-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// IR-PCH-HOST: omp.loop.exit:
-// IR-PCH-HOST-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
-// IR-PCH-HOST-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP20]])
-// IR-PCH-HOST-NEXT: [[TMP21:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: store ptr [[SUM4]], ptr [[TMP21]], align 8
-// IR-PCH-HOST-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// IR-PCH-HOST-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: switch i32 [[TMP24]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// IR-PCH-HOST-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// IR-PCH-HOST-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// IR-PCH-HOST-NEXT: ]
-// IR-PCH-HOST: .omp.reduction.case1:
-// IR-PCH-HOST-NEXT: [[TMP25:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP0]], [[TMP25]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE19:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST15:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT17:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[TMP26:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-PCH-HOST-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP26]], [[TMP27]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD16]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT17]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP25]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH-HOST: omp.arraycpy.done19:
-// IR-PCH-HOST-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH-HOST: .omp.reduction.case2:
-// IR-PCH-HOST-NEXT: [[TMP28:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY20:%.*]] = icmp eq ptr [[TMP0]], [[TMP28]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY20]], label [[OMP_ARRAYCPY_DONE27:%.*]], label [[OMP_ARRAYCPY_BODY21:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body21:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST22:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT25:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST23:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT24:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-PCH-HOST-NEXT: [[TMP29:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], align 4
-// IR-PCH-HOST-NEXT: [[TMP30:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 [[TMP29]] monotonic, align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT24]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT25]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE26:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT24]], [[TMP28]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_DONE27]], label [[OMP_ARRAYCPY_BODY21]]
-// IR-PCH-HOST: omp.arraycpy.done27:
-// IR-PCH-HOST-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH-HOST: .omp.reduction.default:
-// IR-PCH-HOST-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-HOST-NEXT: [[TMP32:%.*]] = icmp ne i32 [[TMP31]], 0
-// IR-PCH-HOST-NEXT: br i1 [[TMP32]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// IR-PCH-HOST: .omp.lastprivate.then:
-// IR-PCH-HOST-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-PCH-HOST-NEXT: [[TMP33:%.*]] = load i32, ptr [[J3]], align 4
-// IR-PCH-HOST-NEXT: store i32 [[TMP33]], ptr [[J_ADDR]], align 4
-// IR-PCH-HOST-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// IR-PCH-HOST: .omp.lastprivate.done:
-// IR-PCH-HOST-NEXT: ret void
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func
-// IR-PCH-HOST-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// IR-PCH-HOST-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// IR-PCH-HOST-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// IR-PCH-HOST-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// IR-PCH-HOST-NEXT: [[TMP8:%.*]] = getelementptr i32, ptr [[TMP7]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP7]], [[TMP8]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE2:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[TMP5]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[TMP7]], [[ENTRY]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[TMP9:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[TMP10:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP8]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYCPY_DONE2]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH-HOST: omp.arraycpy.done2:
-// IR-PCH-HOST-NEXT: ret void
-// IR-PCH-HOST-LABEL: define {{[^@]+}}@.omp.reduction.reduction_func.2
-// IR-PCH-HOST-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
-// IR-PCH-HOST-NEXT: entry:
-// IR-PCH-HOST-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// IR-PCH-HOST-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// IR-PCH-HOST-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// IR-PCH-HOST-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// IR-PCH-HOST-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// IR-PCH-HOST-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// IR-PCH-HOST-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// IR-PCH-HOST-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// IR-PCH-HOST-NEXT: [[TMP8:%.*]] = getelementptr i32, ptr [[TMP7]], i64 100
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP7]], [[TMP8]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE2:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH-HOST: omp.arraycpy.body:
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[TMP5]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[TMP7]], [[ENTRY]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-HOST-NEXT: [[TMP9:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[TMP10:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// IR-PCH-HOST-NEXT: store i32 [[ADD]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-HOST-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP8]]
-// IR-PCH-HOST-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYCPY_DONE2]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH-HOST: omp.arraycpy.done2:
-// IR-PCH-HOST-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l23
-// CHECK-SAME: (i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR0:[0-9]+]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_ADDR]] to ptr
-// CHECK-NEXT: [[SUM_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM_ADDR]] to ptr
-// CHECK-NEXT: [[J_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_CASTED]] to ptr
-// CHECK-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
-// CHECK-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
-// CHECK-NEXT: store i64 [[J]], ptr [[J_ADDR_ASCAST]], align 8
-// CHECK-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP1:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @[[GLOB1:[0-9]+]] to ptr), i8 2, i1 false)
-// CHECK-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP1]], -1
-// CHECK-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
-// CHECK: user_code.entry:
-// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr))
-// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[J_ADDR_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP3]], ptr [[J_CASTED_ASCAST]], align 4
-// CHECK-NEXT: [[TMP4:%.*]] = load i64, ptr [[J_CASTED_ASCAST]], align 8
-// CHECK-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP2]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
-// CHECK-NEXT: call void @__omp_outlined__(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP4]], ptr [[TMP0]]) #[[ATTR2:[0-9]+]]
-// CHECK-NEXT: call void @__kmpc_target_deinit(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i8 2)
-// CHECK-NEXT: ret void
-// CHECK: worker.exit:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@__omp_outlined__
-// CHECK-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1:[0-9]+]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[SUM1:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[_TMP2:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J3:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J4:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [4 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
-// CHECK-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
-// CHECK-NEXT: [[J_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_ADDR]] to ptr
-// CHECK-NEXT: [[SUM_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM_ADDR]] to ptr
-// CHECK-NEXT: [[SUM1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM1]] to ptr
-// CHECK-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
-// CHECK-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
-// CHECK-NEXT: [[TMP2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP2]] to ptr
-// CHECK-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
-// CHECK-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
-// CHECK-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
-// CHECK-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
-// CHECK-NEXT: [[J3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J3]] to ptr
-// CHECK-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
-// CHECK-NEXT: [[J4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J4]] to ptr
-// CHECK-NEXT: [[J_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_CASTED]] to ptr
-// CHECK-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr
-// CHECK-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store i64 [[J]], ptr [[J_ADDR_ASCAST]], align 8
-// CHECK-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM1_ASCAST]], i32 0, i32 0, i32 0
-// CHECK-NEXT: [[TMP1:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// CHECK-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP1]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// CHECK: omp.arrayinit.body:
-// CHECK-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// CHECK-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// CHECK-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP1]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// CHECK: omp.arrayinit.done:
-// CHECK-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 99, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
-// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
-// CHECK-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
-// CHECK-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK-NEXT: call void @__kmpc_distribute_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB2:[0-9]+]] to ptr), i32 [[TMP3]], i32 91, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 [[NVPTX_NUM_THREADS]])
-// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK: cond.true:
-// CHECK-NEXT: br label [[COND_END:%.*]]
-// CHECK: cond.false:
-// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: br label [[COND_END]]
-// CHECK: cond.end:
-// CHECK-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK: omp.inner.for.cond:
-// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: [[CMP5:%.*]] = icmp slt i32 [[TMP7]], 100
-// CHECK-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK: omp.inner.for.body:
-// CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[J3_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP12]], ptr [[J_CASTED_ASCAST]], align 4
-// CHECK-NEXT: [[TMP13:%.*]] = load i64, ptr [[J_CASTED_ASCAST]], align 8
-// CHECK-NEXT: [[TMP14:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[TMP15:%.*]] = inttoptr i64 [[TMP9]] to ptr
-// CHECK-NEXT: store ptr [[TMP15]], ptr [[TMP14]], align 8
-// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 1
-// CHECK-NEXT: [[TMP17:%.*]] = inttoptr i64 [[TMP11]] to ptr
-// CHECK-NEXT: store ptr [[TMP17]], ptr [[TMP16]], align 8
-// CHECK-NEXT: [[TMP18:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 2
-// CHECK-NEXT: [[TMP19:%.*]] = inttoptr i64 [[TMP13]] to ptr
-// CHECK-NEXT: store ptr [[TMP19]], ptr [[TMP18]], align 8
-// CHECK-NEXT: [[TMP20:%.*]] = getelementptr inbounds [4 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 3
-// CHECK-NEXT: store ptr [[SUM1_ASCAST]], ptr [[TMP20]], align 8
-// CHECK-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK-NEXT: call void @__kmpc_parallel_51(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP22]], i32 1, i32 -1, i32 -1, ptr @__omp_outlined__.1, ptr null, ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 4)
-// CHECK-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK: omp.inner.for.inc:
-// CHECK-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: [[TMP24:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
-// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP23]], [[TMP24]]
-// CHECK-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
-// CHECK-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP25]], [[TMP26]]
-// CHECK-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
-// CHECK-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP27]], [[TMP28]]
-// CHECK-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[CMP8:%.*]] = icmp sgt i32 [[TMP29]], 99
-// CHECK-NEXT: br i1 [[CMP8]], label [[COND_TRUE9:%.*]], label [[COND_FALSE10:%.*]]
-// CHECK: cond.true9:
-// CHECK-NEXT: br label [[COND_END11:%.*]]
-// CHECK: cond.false10:
-// CHECK-NEXT: [[TMP30:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: br label [[COND_END11]]
-// CHECK: cond.end11:
-// CHECK-NEXT: [[COND12:%.*]] = phi i32 [ 99, [[COND_TRUE9]] ], [ [[TMP30]], [[COND_FALSE10]] ]
-// CHECK-NEXT: store i32 [[COND12]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP31]], ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK: omp.inner.for.end:
-// CHECK-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK: omp.loop.exit:
-// CHECK-NEXT: [[TMP32:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP33:%.*]] = load i32, ptr [[TMP32]], align 4
-// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3:[0-9]+]] to ptr), i32 [[TMP33]])
-// CHECK-NEXT: [[TMP34:%.*]] = load i32, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
-// CHECK-NEXT: [[TMP35:%.*]] = icmp ne i32 [[TMP34]], 0
-// CHECK-NEXT: br i1 [[TMP35]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// CHECK: .omp.lastprivate.then:
-// CHECK-NEXT: store i32 10, ptr [[J3_ASCAST]], align 4
-// CHECK-NEXT: [[TMP36:%.*]] = load i32, ptr [[J3_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP36]], ptr [[J_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// CHECK: .omp.lastprivate.done:
-// CHECK-NEXT: [[TMP37:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP38:%.*]] = load i32, ptr [[TMP37]], align 4
-// CHECK-NEXT: [[TMP39:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: store ptr [[SUM1_ASCAST]], ptr [[TMP39]], align 8
-// CHECK-NEXT: [[TMP40:%.*]] = load ptr, ptr addrspace(1) @"_openmp_teams_reductions_buffer_$_$ptr", align 8
-// CHECK-NEXT: [[TMP41:%.*]] = call i32 @__kmpc_nvptx_teams_reduce_nowait_v2(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP38]], ptr [[TMP40]], i32 1024, ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], ptr @_omp_reduction_shuffle_and_reduce_func.3, ptr @_omp_reduction_inter_warp_copy_func.4, ptr @_omp_reduction_list_to_global_copy_func, ptr @_omp_reduction_list_to_global_reduce_func, ptr @_omp_reduction_global_to_list_copy_func, ptr @_omp_reduction_global_to_list_reduce_func)
-// CHECK-NEXT: [[TMP42:%.*]] = icmp eq i32 [[TMP41]], 1
-// CHECK-NEXT: br i1 [[TMP42]], label [[DOTOMP_REDUCTION_THEN:%.*]], label [[DOTOMP_REDUCTION_DONE:%.*]]
-// CHECK: .omp.reduction.then:
-// CHECK-NEXT: [[TMP43:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// CHECK-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP0]], [[TMP43]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE17:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// CHECK: omp.arraycpy.body:
-// CHECK-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM1_ASCAST]], [[DOTOMP_REDUCTION_THEN]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// CHECK-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST13:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_THEN]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT15:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// CHECK-NEXT: [[TMP44:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST13]], align 4
-// CHECK-NEXT: [[TMP45:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// CHECK-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP44]], [[TMP45]]
-// CHECK-NEXT: store i32 [[ADD14]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST13]], align 4
-// CHECK-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT15]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST13]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_DONE16:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP43]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_DONE16]], label [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_BODY]]
-// CHECK: omp.arraycpy.done17:
-// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DONE]]
-// CHECK: .omp.reduction.done:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@__omp_outlined__.1
-// CHECK-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[J_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
-// CHECK-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[_TMP1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J3:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[SUM4:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5)
-// CHECK-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[J5:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
-// CHECK-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
-// CHECK-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr
-// CHECK-NEXT: [[DOTPREVIOUS_UB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_UB__ADDR]] to ptr
-// CHECK-NEXT: [[J_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J_ADDR]] to ptr
-// CHECK-NEXT: [[SUM_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM_ADDR]] to ptr
-// CHECK-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
-// CHECK-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
-// CHECK-NEXT: [[TMP1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP1]] to ptr
-// CHECK-NEXT: [[DOTOMP_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_LB]] to ptr
-// CHECK-NEXT: [[DOTOMP_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_UB]] to ptr
-// CHECK-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
-// CHECK-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
-// CHECK-NEXT: [[J3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J3]] to ptr
-// CHECK-NEXT: [[SUM4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[SUM4]] to ptr
-// CHECK-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
-// CHECK-NEXT: [[J5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J5]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr
-// CHECK-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
-// CHECK-NEXT: store i64 [[J]], ptr [[J_ADDR_ASCAST]], align 8
-// CHECK-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SUM_ADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 0, ptr [[DOTOMP_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 99, ptr [[DOTOMP_UB_ASCAST]], align 4
-// CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB_ASCAST]], align 4
-// CHECK-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
-// CHECK-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
-// CHECK-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4_ASCAST]], i32 0, i32 0, i32 0
-// CHECK-NEXT: [[TMP3:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// CHECK-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP3]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// CHECK: omp.arrayinit.body:
-// CHECK-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// CHECK-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// CHECK-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP3]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// CHECK: omp.arrayinit.done:
-// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP4]], align 4
-// CHECK-NEXT: call void @__kmpc_for_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP5]], i32 33, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_LB_ASCAST]], ptr [[DOTOMP_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 1)
-// CHECK-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV_ASCAST]], align 4
-// CHECK-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK: omp.inner.for.cond:
-// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7:![0-9]+]]
-// CHECK-NEXT: [[CONV6:%.*]] = sext i32 [[TMP7]] to i64
-// CHECK-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[CMP:%.*]] = icmp ule i64 [[CONV6]], [[TMP8]]
-// CHECK-NEXT: br i1 [[CMP]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK: omp.inner.for.body:
-// CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP9]], 10
-// CHECK-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
-// CHECK-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK-NEXT: store i32 [[ADD]], ptr [[I_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[DIV7:%.*]] = sdiv i32 [[TMP11]], 10
-// CHECK-NEXT: [[MUL8:%.*]] = mul nsw i32 [[DIV7]], 10
-// CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP10]], [[MUL8]]
-// CHECK-NEXT: [[MUL9:%.*]] = mul nsw i32 [[SUB]], 1
-// CHECK-NEXT: [[ADD10:%.*]] = add nsw i32 0, [[MUL9]]
-// CHECK-NEXT: store i32 [[ADD10]], ptr [[J3_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[TMP12:%.*]] = load i32, ptr [[I_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[I_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP13]] to i64
-// CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4_ASCAST]], i64 0, i64 [[IDXPROM]]
-// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[J3_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP14]] to i64
-// CHECK-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM11]]
-// CHECK-NEXT: [[TMP15:%.*]] = load i32, ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP15]], [[TMP12]]
-// CHECK-NEXT: store i32 [[ADD13]], ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// CHECK: omp.body.continue:
-// CHECK-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK: omp.inner.for.inc:
-// CHECK-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV_ASCAST]], align 4, !llvm.access.group [[ACC_GRP7]]
-// CHECK-NEXT: br label [[OMP_INNER_FOR_COND]], !llvm.loop [[LOOP8:![0-9]+]]
-// CHECK: omp.inner.for.end:
-// CHECK-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK: omp.loop.exit:
-// CHECK-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
-// CHECK-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP19]])
-// CHECK-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK-NEXT: [[TMP22:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: store ptr [[SUM4_ASCAST]], ptr [[TMP22]], align 8
-// CHECK-NEXT: [[TMP23:%.*]] = call i32 @__kmpc_nvptx_parallel_reduce_nowait_v2(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP21]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], ptr @_omp_reduction_shuffle_and_reduce_func, ptr @_omp_reduction_inter_warp_copy_func)
-// CHECK-NEXT: [[TMP24:%.*]] = icmp eq i32 [[TMP23]], 1
-// CHECK-NEXT: br i1 [[TMP24]], label [[DOTOMP_REDUCTION_THEN:%.*]], label [[DOTOMP_REDUCTION_DONE:%.*]]
-// CHECK: .omp.reduction.then:
-// CHECK-NEXT: [[TMP25:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
-// CHECK-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP0]], [[TMP25]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE19:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// CHECK: omp.arraycpy.body:
-// CHECK-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM4_ASCAST]], [[DOTOMP_REDUCTION_THEN]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// CHECK-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST15:%.*]] = phi ptr [ [[TMP0]], [[DOTOMP_REDUCTION_THEN]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT17:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// CHECK-NEXT: [[TMP26:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// CHECK-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// CHECK-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP26]], [[TMP27]]
-// CHECK-NEXT: store i32 [[ADD16]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// CHECK-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT17]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// CHECK-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP25]]
-// CHECK-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
-// CHECK: omp.arraycpy.done19:
-// CHECK-NEXT: br label [[DOTOMP_REDUCTION_DONE]]
-// CHECK: .omp.reduction.done:
-// CHECK-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
-// CHECK-NEXT: [[TMP29:%.*]] = icmp ne i32 [[TMP28]], 0
-// CHECK-NEXT: br i1 [[TMP29]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// CHECK: .omp.lastprivate.then:
-// CHECK-NEXT: store i32 10, ptr [[J3_ASCAST]], align 4
-// CHECK-NEXT: [[TMP30:%.*]] = load i32, ptr [[J3_ASCAST]], align 4
-// CHECK-NEXT: store i32 [[TMP30]], ptr [[J_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// CHECK: .omp.lastprivate.done:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_shuffle_and_reduce_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i16 noundef signext [[TMP1:%.*]], i16 noundef signext [[TMP2:%.*]], i16 noundef signext [[TMP3:%.*]]) #[[ATTR3:[0-9]+]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: [[DOTADDR3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR3]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 2
-// CHECK-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 2
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3_ASCAST]], align 2
-// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1_ASCAST]], align 2
-// CHECK-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2_ASCAST]], align 2
-// CHECK-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3_ASCAST]], align 2
-// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0
-// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[TMP8]], align 8
-// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [10 x [10 x i32]], ptr [[TMP9]], i64 1
-// CHECK-NEXT: br label [[DOTSHUFFLE_PRE_COND:%.*]]
-// CHECK: .shuffle.pre_cond:
-// CHECK-NEXT: [[TMP12:%.*]] = phi ptr [ [[TMP9]], [[ENTRY:%.*]] ], [ [[TMP23:%.*]], [[DOTSHUFFLE_THEN:%.*]] ]
-// CHECK-NEXT: [[TMP13:%.*]] = phi ptr [ [[DOTOMP_REDUCTION_ELEMENT_ASCAST]], [[ENTRY]] ], [ [[TMP24:%.*]], [[DOTSHUFFLE_THEN]] ]
-// CHECK-NEXT: [[TMP14:%.*]] = ptrtoint ptr [[TMP11]] to i64
-// CHECK-NEXT: [[TMP15:%.*]] = ptrtoint ptr [[TMP12]] to i64
-// CHECK-NEXT: [[TMP16:%.*]] = sub i64 [[TMP14]], [[TMP15]]
-// CHECK-NEXT: [[TMP17:%.*]] = sdiv exact i64 [[TMP16]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-// CHECK-NEXT: [[TMP18:%.*]] = icmp sgt i64 [[TMP17]], 7
-// CHECK-NEXT: br i1 [[TMP18]], label [[DOTSHUFFLE_THEN]], label [[DOTSHUFFLE_EXIT:%.*]]
-// CHECK: .shuffle.then:
-// CHECK-NEXT: [[TMP19:%.*]] = load i64, ptr [[TMP12]], align 4
-// CHECK-NEXT: [[TMP20:%.*]] = call i32 @__kmpc_get_warp_size()
-// CHECK-NEXT: [[TMP21:%.*]] = trunc i32 [[TMP20]] to i16
-// CHECK-NEXT: [[TMP22:%.*]] = call i64 @__kmpc_shuffle_int64(i64 [[TMP19]], i16 [[TMP6]], i16 [[TMP21]])
-// CHECK-NEXT: store i64 [[TMP22]], ptr [[TMP13]], align 4
-// CHECK-NEXT: [[TMP23]] = getelementptr i64, ptr [[TMP12]], i64 1
-// CHECK-NEXT: [[TMP24]] = getelementptr i64, ptr [[TMP13]], i64 1
-// CHECK-NEXT: br label [[DOTSHUFFLE_PRE_COND]]
-// CHECK: .shuffle.exit:
-// CHECK-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT_ASCAST]], ptr [[TMP10]], align 8
-// CHECK-NEXT: [[TMP25:%.*]] = icmp eq i16 [[TMP7]], 0
-// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i16 [[TMP7]], 1
-// CHECK-NEXT: [[TMP27:%.*]] = icmp ult i16 [[TMP5]], [[TMP6]]
-// CHECK-NEXT: [[TMP28:%.*]] = and i1 [[TMP26]], [[TMP27]]
-// CHECK-NEXT: [[TMP29:%.*]] = icmp eq i16 [[TMP7]], 2
-// CHECK-NEXT: [[TMP30:%.*]] = and i16 [[TMP5]], 1
-// CHECK-NEXT: [[TMP31:%.*]] = icmp eq i16 [[TMP30]], 0
-// CHECK-NEXT: [[TMP32:%.*]] = and i1 [[TMP29]], [[TMP31]]
-// CHECK-NEXT: [[TMP33:%.*]] = icmp sgt i16 [[TMP6]], 0
-// CHECK-NEXT: [[TMP34:%.*]] = and i1 [[TMP32]], [[TMP33]]
-// CHECK-NEXT: [[TMP35:%.*]] = or i1 [[TMP25]], [[TMP28]]
-// CHECK-NEXT: [[TMP36:%.*]] = or i1 [[TMP35]], [[TMP34]]
-// CHECK-NEXT: br i1 [[TMP36]], label [[THEN:%.*]], label [[ELSE:%.*]]
-// CHECK: then:
-// CHECK-NEXT: call void @"_omp$reduction$reduction_func"(ptr [[TMP4]], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]]) #[[ATTR2]]
-// CHECK-NEXT: br label [[IFCONT:%.*]]
-// CHECK: else:
-// CHECK-NEXT: br label [[IFCONT]]
-// CHECK: ifcont:
-// CHECK-NEXT: [[TMP37:%.*]] = icmp eq i16 [[TMP7]], 1
-// CHECK-NEXT: [[TMP38:%.*]] = icmp uge i16 [[TMP5]], [[TMP6]]
-// CHECK-NEXT: [[TMP39:%.*]] = and i1 [[TMP37]], [[TMP38]]
-// CHECK-NEXT: br i1 [[TMP39]], label [[THEN4:%.*]], label [[ELSE5:%.*]]
-// CHECK: then4:
-// CHECK-NEXT: [[TMP40:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[TMP41:%.*]] = load ptr, ptr [[TMP40]], align 8
-// CHECK-NEXT: [[TMP42:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0
-// CHECK-NEXT: [[TMP43:%.*]] = load ptr, ptr [[TMP42]], align 8
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP43]], ptr align 4 [[TMP41]], i64 400, i1 false)
-// CHECK-NEXT: br label [[IFCONT6:%.*]]
-// CHECK: else5:
-// CHECK-NEXT: br label [[IFCONT6]]
-// CHECK: ifcont6:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_inter_warp_copy_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr))
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[NVPTX_LANE_ID:%.*]] = and i32 [[TMP4]], 63
-// CHECK-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 6
-// CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 0, ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[PRECOND:%.*]]
-// CHECK: precond:
-// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 100
-// CHECK-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]]
-// CHECK: body:
-// CHECK-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4:[0-9]+]] to ptr), i32 [[TMP2]])
-// CHECK-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0
-// CHECK-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]]
-// CHECK: then:
-// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0
-// CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
-// CHECK-NEXT: [[TMP11:%.*]] = getelementptr i32, ptr [[TMP10]], i32 [[TMP7]]
-// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]]
-// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK-NEXT: store volatile i32 [[TMP13]], ptr addrspace(3) [[TMP12]], align 4
-// CHECK-NEXT: br label [[IFCONT:%.*]]
-// CHECK: else:
-// CHECK-NEXT: br label [[IFCONT]]
-// CHECK: ifcont:
-// CHECK-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]])
-// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]]
-// CHECK-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]]
-// CHECK: then2:
-// CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]]
-// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0
-// CHECK-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8
-// CHECK-NEXT: [[TMP18:%.*]] = getelementptr i32, ptr [[TMP17]], i32 [[TMP7]]
-// CHECK-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4
-// CHECK-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4
-// CHECK-NEXT: br label [[IFCONT4:%.*]]
-// CHECK: else3:
-// CHECK-NEXT: br label [[IFCONT4]]
-// CHECK: ifcont4:
-// CHECK-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1
-// CHECK-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[PRECOND]]
-// CHECK: exit:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_shuffle_and_reduce_func.3
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i16 noundef signext [[TMP1:%.*]], i16 noundef signext [[TMP2:%.*]], i16 noundef signext [[TMP3:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTADDR3:%.*]] = alloca i16, align 2, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_ELEMENT:%.*]] = alloca [10 x [10 x i32]], align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: [[DOTADDR3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR3]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_ELEMENT_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_ELEMENT]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i16 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 2
-// CHECK-NEXT: store i16 [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 2
-// CHECK-NEXT: store i16 [[TMP3]], ptr [[DOTADDR3_ASCAST]], align 2
-// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP5:%.*]] = load i16, ptr [[DOTADDR1_ASCAST]], align 2
-// CHECK-NEXT: [[TMP6:%.*]] = load i16, ptr [[DOTADDR2_ASCAST]], align 2
-// CHECK-NEXT: [[TMP7:%.*]] = load i16, ptr [[DOTADDR3_ASCAST]], align 2
-// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0
-// CHECK-NEXT: [[TMP9:%.*]] = load ptr, ptr [[TMP8]], align 8
-// CHECK-NEXT: [[TMP10:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[TMP11:%.*]] = getelementptr [10 x [10 x i32]], ptr [[TMP9]], i64 1
-// CHECK-NEXT: br label [[DOTSHUFFLE_PRE_COND:%.*]]
-// CHECK: .shuffle.pre_cond:
-// CHECK-NEXT: [[TMP12:%.*]] = phi ptr [ [[TMP9]], [[ENTRY:%.*]] ], [ [[TMP23:%.*]], [[DOTSHUFFLE_THEN:%.*]] ]
-// CHECK-NEXT: [[TMP13:%.*]] = phi ptr [ [[DOTOMP_REDUCTION_ELEMENT_ASCAST]], [[ENTRY]] ], [ [[TMP24:%.*]], [[DOTSHUFFLE_THEN]] ]
-// CHECK-NEXT: [[TMP14:%.*]] = ptrtoint ptr [[TMP11]] to i64
-// CHECK-NEXT: [[TMP15:%.*]] = ptrtoint ptr [[TMP12]] to i64
-// CHECK-NEXT: [[TMP16:%.*]] = sub i64 [[TMP14]], [[TMP15]]
-// CHECK-NEXT: [[TMP17:%.*]] = sdiv exact i64 [[TMP16]], ptrtoint (ptr getelementptr (i8, ptr null, i32 1) to i64)
-// CHECK-NEXT: [[TMP18:%.*]] = icmp sgt i64 [[TMP17]], 7
-// CHECK-NEXT: br i1 [[TMP18]], label [[DOTSHUFFLE_THEN]], label [[DOTSHUFFLE_EXIT:%.*]]
-// CHECK: .shuffle.then:
-// CHECK-NEXT: [[TMP19:%.*]] = load i64, ptr [[TMP12]], align 4
-// CHECK-NEXT: [[TMP20:%.*]] = call i32 @__kmpc_get_warp_size()
-// CHECK-NEXT: [[TMP21:%.*]] = trunc i32 [[TMP20]] to i16
-// CHECK-NEXT: [[TMP22:%.*]] = call i64 @__kmpc_shuffle_int64(i64 [[TMP19]], i16 [[TMP6]], i16 [[TMP21]])
-// CHECK-NEXT: store i64 [[TMP22]], ptr [[TMP13]], align 4
-// CHECK-NEXT: [[TMP23]] = getelementptr i64, ptr [[TMP12]], i64 1
-// CHECK-NEXT: [[TMP24]] = getelementptr i64, ptr [[TMP13]], i64 1
-// CHECK-NEXT: br label [[DOTSHUFFLE_PRE_COND]]
-// CHECK: .shuffle.exit:
-// CHECK-NEXT: store ptr [[DOTOMP_REDUCTION_ELEMENT_ASCAST]], ptr [[TMP10]], align 8
-// CHECK-NEXT: [[TMP25:%.*]] = icmp eq i16 [[TMP7]], 0
-// CHECK-NEXT: [[TMP26:%.*]] = icmp eq i16 [[TMP7]], 1
-// CHECK-NEXT: [[TMP27:%.*]] = icmp ult i16 [[TMP5]], [[TMP6]]
-// CHECK-NEXT: [[TMP28:%.*]] = and i1 [[TMP26]], [[TMP27]]
-// CHECK-NEXT: [[TMP29:%.*]] = icmp eq i16 [[TMP7]], 2
-// CHECK-NEXT: [[TMP30:%.*]] = and i16 [[TMP5]], 1
-// CHECK-NEXT: [[TMP31:%.*]] = icmp eq i16 [[TMP30]], 0
-// CHECK-NEXT: [[TMP32:%.*]] = and i1 [[TMP29]], [[TMP31]]
-// CHECK-NEXT: [[TMP33:%.*]] = icmp sgt i16 [[TMP6]], 0
-// CHECK-NEXT: [[TMP34:%.*]] = and i1 [[TMP32]], [[TMP33]]
-// CHECK-NEXT: [[TMP35:%.*]] = or i1 [[TMP25]], [[TMP28]]
-// CHECK-NEXT: [[TMP36:%.*]] = or i1 [[TMP35]], [[TMP34]]
-// CHECK-NEXT: br i1 [[TMP36]], label [[THEN:%.*]], label [[ELSE:%.*]]
-// CHECK: then:
-// CHECK-NEXT: call void @"_omp$reduction$reduction_func.2"(ptr [[TMP4]], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]]) #[[ATTR2]]
-// CHECK-NEXT: br label [[IFCONT:%.*]]
-// CHECK: else:
-// CHECK-NEXT: br label [[IFCONT]]
-// CHECK: ifcont:
-// CHECK-NEXT: [[TMP37:%.*]] = icmp eq i16 [[TMP7]], 1
-// CHECK-NEXT: [[TMP38:%.*]] = icmp uge i16 [[TMP5]], [[TMP6]]
-// CHECK-NEXT: [[TMP39:%.*]] = and i1 [[TMP37]], [[TMP38]]
-// CHECK-NEXT: br i1 [[TMP39]], label [[THEN4:%.*]], label [[ELSE5:%.*]]
-// CHECK: then4:
-// CHECK-NEXT: [[TMP40:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_REMOTE_REDUCE_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[TMP41:%.*]] = load ptr, ptr [[TMP40]], align 8
-// CHECK-NEXT: [[TMP42:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP4]], i64 0, i64 0
-// CHECK-NEXT: [[TMP43:%.*]] = load ptr, ptr [[TMP42]], align 8
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP43]], ptr align 4 [[TMP41]], i64 400, i1 false)
-// CHECK-NEXT: br label [[IFCONT6:%.*]]
-// CHECK: else5:
-// CHECK-NEXT: br label [[IFCONT6]]
-// CHECK: ifcont6:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_inter_warp_copy_func.4
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTCNT_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[TMP2:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr))
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTCNT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCNT_ADDR]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP3:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[NVPTX_LANE_ID:%.*]] = and i32 [[TMP4]], 63
-// CHECK-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_get_hardware_thread_id_in_block()
-// CHECK-NEXT: [[NVPTX_WARP_ID:%.*]] = ashr i32 [[TMP5]], 6
-// CHECK-NEXT: [[TMP6:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 0, ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[PRECOND:%.*]]
-// CHECK: precond:
-// CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: [[TMP8:%.*]] = icmp ult i32 [[TMP7]], 100
-// CHECK-NEXT: br i1 [[TMP8]], label [[BODY:%.*]], label [[EXIT:%.*]]
-// CHECK: body:
-// CHECK-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]])
-// CHECK-NEXT: [[WARP_MASTER:%.*]] = icmp eq i32 [[NVPTX_LANE_ID]], 0
-// CHECK-NEXT: br i1 [[WARP_MASTER]], label [[THEN:%.*]], label [[ELSE:%.*]]
-// CHECK: then:
-// CHECK-NEXT: [[TMP9:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0
-// CHECK-NEXT: [[TMP10:%.*]] = load ptr, ptr [[TMP9]], align 8
-// CHECK-NEXT: [[TMP11:%.*]] = getelementptr i32, ptr [[TMP10]], i32 [[TMP7]]
-// CHECK-NEXT: [[TMP12:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[NVPTX_WARP_ID]]
-// CHECK-NEXT: [[TMP13:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK-NEXT: store volatile i32 [[TMP13]], ptr addrspace(3) [[TMP12]], align 4
-// CHECK-NEXT: br label [[IFCONT:%.*]]
-// CHECK: else:
-// CHECK-NEXT: br label [[IFCONT]]
-// CHECK: ifcont:
-// CHECK-NEXT: call void @__kmpc_barrier(ptr addrspacecast (ptr addrspace(1) @[[GLOB4]] to ptr), i32 [[TMP2]])
-// CHECK-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[IS_ACTIVE_THREAD:%.*]] = icmp ult i32 [[TMP3]], [[TMP14]]
-// CHECK-NEXT: br i1 [[IS_ACTIVE_THREAD]], label [[THEN2:%.*]], label [[ELSE3:%.*]]
-// CHECK: then2:
-// CHECK-NEXT: [[TMP15:%.*]] = getelementptr inbounds [64 x i32], ptr addrspace(3) @__openmp_nvptx_data_transfer_temporary_storage, i64 0, i32 [[TMP3]]
-// CHECK-NEXT: [[TMP16:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP6]], i64 0, i64 0
-// CHECK-NEXT: [[TMP17:%.*]] = load ptr, ptr [[TMP16]], align 8
-// CHECK-NEXT: [[TMP18:%.*]] = getelementptr i32, ptr [[TMP17]], i32 [[TMP7]]
-// CHECK-NEXT: [[TMP19:%.*]] = load volatile i32, ptr addrspace(3) [[TMP15]], align 4
-// CHECK-NEXT: store i32 [[TMP19]], ptr [[TMP18]], align 4
-// CHECK-NEXT: br label [[IFCONT4:%.*]]
-// CHECK: else3:
-// CHECK-NEXT: br label [[IFCONT4]]
-// CHECK: ifcont4:
-// CHECK-NEXT: [[TMP20:%.*]] = add nsw i32 [[TMP7]], 1
-// CHECK-NEXT: store i32 [[TMP20]], ptr [[DOTCNT_ADDR_ASCAST]], align 4
-// CHECK-NEXT: br label [[PRECOND]]
-// CHECK: exit:
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_list_to_global_copy_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// CHECK-NEXT: [[SUM:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY:%.*]], ptr [[TMP4]], i32 0, i32 0
-// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1024 x [10 x [10 x i32]]], ptr [[SUM]], i32 0, i32 [[TMP5]]
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 128 [[TMP8]], ptr align 4 [[TMP7]], i64 400, i1 false)
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_list_to_global_reduce_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[SUM:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY:%.*]], ptr [[TMP3]], i32 0, i32 0
-// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1024 x [10 x [10 x i32]]], ptr [[SUM]], i32 0, i32 [[TMP4]]
-// CHECK-NEXT: store ptr [[TMP6]], ptr [[TMP5]], align 8
-// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: call void @"_omp$reduction$reduction_func.2"(ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], ptr [[TMP7]]) #[[ATTR2]]
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_global_to_list_copy_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP4:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// CHECK-NEXT: [[SUM:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY:%.*]], ptr [[TMP4]], i32 0, i32 0
-// CHECK-NEXT: [[TMP8:%.*]] = getelementptr inbounds [1024 x [10 x [10 x i32]]], ptr [[SUM]], i32 0, i32 [[TMP5]]
-// CHECK-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[TMP7]], ptr align 128 [[TMP8]], i64 400, i1 false)
-// CHECK-NEXT: ret void
-// CHECK-LABEL: define {{[^@]+}}@_omp_reduction_global_to_list_reduce_func
-// CHECK-SAME: (ptr noundef [[TMP0:%.*]], i32 noundef [[TMP1:%.*]], ptr noundef [[TMP2:%.*]]) #[[ATTR3]] {
-// CHECK-NEXT: entry:
-// CHECK-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR1:%.*]] = alloca i32, align 4, addrspace(5)
-// CHECK-NEXT: [[DOTADDR2:%.*]] = alloca ptr, align 8, addrspace(5)
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8, addrspace(5)
-// CHECK-NEXT: [[DOTADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR]] to ptr
-// CHECK-NEXT: [[DOTADDR1_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR1]] to ptr
-// CHECK-NEXT: [[DOTADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTADDR2]] to ptr
-// CHECK-NEXT: [[DOTOMP_REDUCTION_RED_LIST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_REDUCTION_RED_LIST]] to ptr
-// CHECK-NEXT: store ptr [[TMP0]], ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: store i32 [[TMP1]], ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: store ptr [[TMP2]], ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR_ASCAST]], align 8
-// CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTADDR1_ASCAST]], align 4
-// CHECK-NEXT: [[TMP5:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]], i64 0, i64 0
-// CHECK-NEXT: [[SUM:%.*]] = getelementptr inbounds [[STRUCT__GLOBALIZED_LOCALS_TY:%.*]], ptr [[TMP3]], i32 0, i32 0
-// CHECK-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1024 x [10 x [10 x i32]]], ptr [[SUM]], i32 0, i32 [[TMP4]]
-// CHECK-NEXT: store ptr [[TMP6]], ptr [[TMP5]], align 8
-// CHECK-NEXT: [[TMP7:%.*]] = load ptr, ptr [[DOTADDR2_ASCAST]], align 8
-// CHECK-NEXT: call void @"_omp$reduction$reduction_func.2"(ptr [[TMP7]], ptr [[DOTOMP_REDUCTION_RED_LIST_ASCAST]]) #[[ATTR2]]
-// CHECK-NEXT: ret void
// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22
// IR-GPU-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR0:[0-9]+]] {
// IR-GPU-NEXT: entry:
@@ -2015,7 +903,7 @@ int foo() {
// IR-NEXT: store ptr [[SUM1]], ptr [[TMP22]], align 8
// IR-NEXT: [[TMP23:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
// IR-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
-// IR-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3:[0-9]+]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: switch i32 [[TMP25]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
@@ -2036,7 +924,7 @@ int foo() {
// IR-NEXT: [[OMP_ARRAYCPY_DONE9:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT8]], [[TMP26]]
// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE9]], label [[OMP_ARRAYCPY_DONE10]], label [[OMP_ARRAYCPY_BODY]]
// IR: omp.arraycpy.done10:
-// IR-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.case2:
// IR-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
@@ -2052,7 +940,6 @@ int foo() {
// IR-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP29]]
// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY12]]
// IR: omp.arraycpy.done18:
-// IR-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.default:
// IR-NEXT: ret void
@@ -2171,7 +1058,7 @@ int foo() {
// IR-NEXT: store ptr [[SUM4]], ptr [[TMP21]], align 8
// IR-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// IR-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: switch i32 [[TMP24]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
@@ -2192,7 +1079,7 @@ int foo() {
// IR-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP25]]
// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
// IR: omp.arraycpy.done19:
-// IR-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.case2:
// IR-NEXT: [[TMP28:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
@@ -2208,7 +1095,6 @@ int foo() {
// IR-NEXT: [[OMP_ARRAYCPY_DONE26:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT24]], [[TMP28]]
// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_DONE27]], label [[OMP_ARRAYCPY_BODY21]]
// IR: omp.arraycpy.done27:
-// IR-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.default:
// IR-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
@@ -2412,7 +1298,7 @@ int foo() {
// IR-PCH-NEXT: store ptr [[SUM1]], ptr [[TMP22]], align 8
// IR-PCH-NEXT: [[TMP23:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
// IR-PCH-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
-// IR-PCH-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3:[0-9]+]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: switch i32 [[TMP25]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-PCH-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-PCH-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
@@ -2433,7 +1319,7 @@ int foo() {
// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE9:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT8]], [[TMP26]]
// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE9]], label [[OMP_ARRAYCPY_DONE10]], label [[OMP_ARRAYCPY_BODY]]
// IR-PCH: omp.arraycpy.done10:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.case2:
// IR-PCH-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
@@ -2449,7 +1335,6 @@ int foo() {
// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP29]]
// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY12]]
// IR-PCH: omp.arraycpy.done18:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.default:
// IR-PCH-NEXT: ret void
@@ -2568,7 +1453,7 @@ int foo() {
// IR-PCH-NEXT: store ptr [[SUM4]], ptr [[TMP21]], align 8
// IR-PCH-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// IR-PCH-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce(ptr @[[GLOB3]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z3foov_l22.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: switch i32 [[TMP24]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-PCH-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-PCH-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
@@ -2589,7 +1474,7 @@ int foo() {
// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP25]]
// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
// IR-PCH: omp.arraycpy.done19:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.case2:
// IR-PCH-NEXT: [[TMP28:%.*]] = getelementptr i32, ptr [[TMP0]], i64 100
@@ -2605,7 +1490,6 @@ int foo() {
// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE26:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT24]], [[TMP28]]
// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_DONE27]], label [[OMP_ARRAYCPY_BODY21]]
// IR-PCH: omp.arraycpy.done27:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.default:
// IR-PCH-NEXT: [[TMP31:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
diff --git a/clang/test/OpenMP/target_teams_generic_loop_codegen_as_distribute.cpp b/clang/test/OpenMP/target_teams_generic_loop_codegen_as_distribute.cpp
new file mode 100644
index 000000000000..f3bbbc6229ab
--- /dev/null
+++ b/clang/test/OpenMP/target_teams_generic_loop_codegen_as_distribute.cpp
@@ -0,0 +1,587 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _ --version 2
+// REQUIRES: amdgpu-registered-target
+
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=IR-GPU
+
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm %s -o - | FileCheck %s --check-prefix=IR
+
+// Check same results after serialization round-trip
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -include-pch %t -emit-llvm %s -o - | FileCheck %s --check-prefix=IR-PCH
+extern int foo(int i);
+
+// expected-no-diagnostics
+
+#ifndef HEADER
+#define HEADER
+int N = 100000;
+int main()
+{
+ int i;
+ int a[N];
+ int b[N];
+
+ // Presence of call. Cannot use 'parallel for', must use 'distribute' when
+ // assume-no-neseted-parallelism isn't specified.
+ #pragma omp target teams loop
+ for (i=0; i < N; i++) {
+ for (int j=0; j < N; j++) {
+ a[i] = b[i] * N + foo(j);
+ }
+ }
+ return 0;
+}
+#endif
+// IR-GPU-LABEL: define weak_odr protected amdgpu_kernel void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27
+// IR-GPU-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DYN_PTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DYN_PTR_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
+// IR-GPU-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27_kernel_environment to ptr), ptr [[DYN_PTR]])
+// IR-GPU-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP4]], -1
+// IR-GPU-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
+// IR-GPU: user_code.entry:
+// IR-GPU-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1:[0-9]+]] to ptr))
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP6]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
+// IR-GPU-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27_omp_outlined(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP7]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) #[[ATTR2:[0-9]+]]
+// IR-GPU-NEXT: call void @__kmpc_target_deinit()
+// IR-GPU-NEXT: ret void
+// IR-GPU: worker.exit:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I5:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_3]] to ptr
+// IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[I5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I5]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-GPU-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB2:[0-9]+]] to ptr), i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 1)
+// IR-GPU-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-GPU-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-GPU: cond.true:
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END:%.*]]
+// IR-GPU: cond.false:
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END]]
+// IR-GPU: cond.end:
+// IR-GPU-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-GPU-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-GPU-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-GPU-NEXT: store i32 [[ADD]], ptr [[I5_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[FOR_COND:%.*]]
+// IR-GPU: for.cond:
+// IR-GPU-NEXT: [[TMP18:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP8:%.*]] = icmp slt i32 [[TMP18]], [[TMP19]]
+// IR-GPU-NEXT: br i1 [[CMP8]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR-GPU: for.body:
+// IR-GPU-NEXT: [[TMP20:%.*]] = load i32, ptr [[I5_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL9:%.*]] = mul nsw i32 [[TMP21]], [[TMP22]]
+// IR-GPU-NEXT: [[TMP23:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP23]]) #[[ATTR4:[0-9]+]]
+// IR-GPU-NEXT: [[ADD10:%.*]] = add nsw i32 [[MUL9]], [[CALL]]
+// IR-GPU-NEXT: [[TMP24:%.*]] = load i32, ptr [[I5_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP24]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM11]]
+// IR-GPU-NEXT: store i32 [[ADD10]], ptr [[ARRAYIDX12]], align 4
+// IR-GPU-NEXT: br label [[FOR_INC:%.*]]
+// IR-GPU: for.inc:
+// IR-GPU-NEXT: [[TMP25:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[INC:%.*]] = add nsw i32 [[TMP25]], 1
+// IR-GPU-NEXT: store i32 [[INC]], ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP7:![0-9]+]]
+// IR-GPU: for.end:
+// IR-GPU-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-GPU: omp.body.continue:
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP26]], 1
+// IR-GPU-NEXT: store i32 [[ADD13]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP28]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-LABEL: define dso_local noundef i32 @main
+// IR-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP7]])
+// IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-NEXT: ret i32 [[TMP8]]
+//
+//
+// IR-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27
+// IR-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I5:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: omp.precond.then:
+// IR-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-NEXT: store i32 [[ADD]], ptr [[I5]], align 4
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: br label [[FOR_COND:%.*]]
+// IR: for.cond:
+// IR-NEXT: [[TMP18:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: [[CMP8:%.*]] = icmp slt i32 [[TMP18]], [[TMP19]]
+// IR-NEXT: br i1 [[CMP8]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR: for.body:
+// IR-NEXT: [[TMP20:%.*]] = load i32, ptr [[I5]], align 4
+// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64
+// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: [[MUL9:%.*]] = mul nsw i32 [[TMP21]], [[TMP22]]
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP23]])
+// IR-NEXT: [[ADD10:%.*]] = add nsw i32 [[MUL9]], [[CALL]]
+// IR-NEXT: [[TMP24:%.*]] = load i32, ptr [[I5]], align 4
+// IR-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP24]] to i64
+// IR-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM11]]
+// IR-NEXT: store i32 [[ADD10]], ptr [[ARRAYIDX12]], align 4
+// IR-NEXT: br label [[FOR_INC:%.*]]
+// IR: for.inc:
+// IR-NEXT: [[TMP25:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[INC:%.*]] = add nsw i32 [[TMP25]], 1
+// IR-NEXT: store i32 [[INC]], ptr [[J]], align 4
+// IR-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP3:![0-9]+]]
+// IR: for.end:
+// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR: omp.body.continue:
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP26]], 1
+// IR-NEXT: store i32 [[ADD13]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP28]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define dso_local noundef i32 @main
+// IR-PCH-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-PCH-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-PCH-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-PCH-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-PCH-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-PCH-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-PCH-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-PCH-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-PCH-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP7]])
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: ret i32 [[TMP8]]
+//
+//
+// IR-PCH-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27
+// IR-PCH-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define internal void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l27.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I5:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-PCH-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-PCH-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[I5]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: br label [[FOR_COND:%.*]]
+// IR-PCH: for.cond:
+// IR-PCH-NEXT: [[TMP18:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: [[CMP8:%.*]] = icmp slt i32 [[TMP18]], [[TMP19]]
+// IR-PCH-NEXT: br i1 [[CMP8]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR-PCH: for.body:
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i32, ptr [[I5]], align 4
+// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: [[MUL9:%.*]] = mul nsw i32 [[TMP21]], [[TMP22]]
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP23]])
+// IR-PCH-NEXT: [[ADD10:%.*]] = add nsw i32 [[MUL9]], [[CALL]]
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i32, ptr [[I5]], align 4
+// IR-PCH-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP24]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM11]]
+// IR-PCH-NEXT: store i32 [[ADD10]], ptr [[ARRAYIDX12]], align 4
+// IR-PCH-NEXT: br label [[FOR_INC:%.*]]
+// IR-PCH: for.inc:
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[INC:%.*]] = add nsw i32 [[TMP25]], 1
+// IR-PCH-NEXT: store i32 [[INC]], ptr [[J]], align 4
+// IR-PCH-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP3:![0-9]+]]
+// IR-PCH: for.end:
+// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH: omp.body.continue:
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP26]], 1
+// IR-PCH-NEXT: store i32 [[ADD13]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP28]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
diff --git a/clang/test/OpenMP/target_teams_generic_loop_codegen_as_parallel_for.cpp b/clang/test/OpenMP/target_teams_generic_loop_codegen_as_parallel_for.cpp
new file mode 100644
index 000000000000..7c7cdc53fa2d
--- /dev/null
+++ b/clang/test/OpenMP/target_teams_generic_loop_codegen_as_parallel_for.cpp
@@ -0,0 +1,3998 @@
+// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py UTC_ARGS: --function-signature --include-generated-funcs --replace-value-regex "__omp_offloading_[0-9a-z]+_[0-9a-z]+" "reduction_size[.].+[.]" "pl_cond[.].+[.|,]" --prefix-filecheck-ir-name _
+// REQUIRES: amdgpu-registered-target
+
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=IR-GPU
+
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-llvm %s -o - | FileCheck %s --check-prefix=IR
+
+// Check same results after serialization round-trip
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -emit-pch -o %t %s
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -include-pch %t -emit-llvm %s -o - | FileCheck %s --check-prefix=IR-PCH
+
+
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple x86_64-unknown-unknown -fopenmp-targets=amdgcn-amd-amdhsa -fopenmp-assume-no-nested-parallelism -DNESTED -emit-llvm-bc %s -o %t-ppc-host.bc
+// RUN: %clang_cc1 -fopenmp -x c++ -std=c++11 -triple amdgcn-amd-amdhsa -fopenmp-targets=amdgcn-amd-amdhsa -emit-llvm %s -fopenmp-is-target-device -fopenmp-assume-no-nested-parallelism -DNESTED -fopenmp-host-ir-file-path %t-ppc-host.bc -o - | FileCheck %s --check-prefix=IR-GPU-NESTED
+
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-assume-no-nested-parallelism -DNESTED -emit-llvm %s -o - | FileCheck %s --check-prefix=IR-NESTED
+
+// Check same results after serialization round-trip
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -fopenmp-assume-no-nested-parallelism -DNESTED -emit-pch -o %t %s
+// RUN: %clang_cc1 -verify -triple x86_64-pc-linux-gnu -fopenmp -include-pch %t -fopenmp-assume-no-nested-parallelism -DNESTED -emit-llvm %s -o - | FileCheck %s --check-prefix=IR-PCH-NESTED
+
+// expected-no-diagnostics
+
+#ifndef NESTED
+extern int omp_get_num_teams(void);
+#endif
+
+#ifndef HEADER
+#define HEADER
+extern int foo(int i);
+
+int N = 100000;
+int main()
+{
+ int a[N];
+ int b[N];
+
+#ifndef NESTED
+ // Should be transformed into 'target teams distribute parallel for'
+ #pragma omp target teams loop
+ for (int j = 0; j != N; j++)
+ a[j]=b[j];
+
+ // Should be transformed into 'target teams distribute parallel for'
+ #pragma omp target teams loop collapse(2)
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ a[i] = b[i] * N + j;
+ }
+ }
+
+ int nt = 0;
+ // Should be transformed into 'target teams distribute parallel for'
+ #pragma omp target teams loop num_teams(32)
+ for (int i=0; i < N; i++) {
+ if (!nt) nt = omp_get_num_teams();
+ for (int j=0; j < N; j++)
+ a[j] = b[j] * N + nt;
+ }
+#else
+ // Should be transformed into 'target teams distribute parallel for'
+ // even with function call because of assume-no-nested-parallelism.
+ #pragma omp target teams loop collapse(2)
+ for (int i = 0; i < N; i++) {
+ for (int j = 0; j < N; j++) {
+ a[i] = b[i] * N + foo(j);
+ }
+ }
+#endif
+ return 0;
+}
+#endif
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41
+// IR-GPU-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DYN_PTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DYN_PTR_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
+// IR-GPU-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41_kernel_environment to ptr), ptr [[DYN_PTR]])
+// IR-GPU-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP4]], -1
+// IR-GPU-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
+// IR-GPU: user_code.entry:
+// IR-GPU-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1:[0-9]+]] to ptr))
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP6]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
+// IR-GPU-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41_omp_outlined(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP7]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) #[[ATTR2:[0-9]+]]
+// IR-GPU-NEXT: call void @__kmpc_target_deinit()
+// IR-GPU-NEXT: ret void
+// IR-GPU: worker.exit:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J5:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [7 x ptr], align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_3]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[J5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J5]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-GPU-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
+// IR-GPU-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB2:[0-9]+]] to ptr), i32 [[TMP9]], i32 91, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 [[NVPTX_NUM_THREADS]])
+// IR-GPU-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-GPU-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-GPU: cond.true:
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END:%.*]]
+// IR-GPU: cond.false:
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END]]
+// IR-GPU: cond.end:
+// IR-GPU-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-GPU-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP16]], 1
+// IR-GPU-NEXT: [[CMP7:%.*]] = icmp slt i32 [[TMP15]], [[ADD]]
+// IR-GPU-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP21]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP23:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 0
+// IR-GPU-NEXT: [[TMP24:%.*]] = inttoptr i64 [[TMP18]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP24]], ptr [[TMP23]], align 8
+// IR-GPU-NEXT: [[TMP25:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 1
+// IR-GPU-NEXT: [[TMP26:%.*]] = inttoptr i64 [[TMP20]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP26]], ptr [[TMP25]], align 8
+// IR-GPU-NEXT: [[TMP27:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 2
+// IR-GPU-NEXT: [[TMP28:%.*]] = inttoptr i64 [[TMP22]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP28]], ptr [[TMP27]], align 8
+// IR-GPU-NEXT: [[TMP29:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 3
+// IR-GPU-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP0]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP30]], ptr [[TMP29]], align 8
+// IR-GPU-NEXT: [[TMP31:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 4
+// IR-GPU-NEXT: store ptr [[TMP1]], ptr [[TMP31]], align 8
+// IR-GPU-NEXT: [[TMP32:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 5
+// IR-GPU-NEXT: [[TMP33:%.*]] = inttoptr i64 [[TMP2]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP33]], ptr [[TMP32]], align 8
+// IR-GPU-NEXT: [[TMP34:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 6
+// IR-GPU-NEXT: store ptr [[TMP3]], ptr [[TMP34]], align 8
+// IR-GPU-NEXT: [[TMP35:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP36:%.*]] = load i32, ptr [[TMP35]], align 4
+// IR-GPU-NEXT: call void @__kmpc_parallel_51(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP36]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 7)
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP37:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP38:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP37]], [[TMP38]]
+// IR-GPU-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP39:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP40:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP39]], [[TMP40]]
+// IR-GPU-NEXT: store i32 [[ADD9]], ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP41:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP42:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP41]], [[TMP42]]
+// IR-GPU-NEXT: store i32 [[ADD10]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP43:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP44:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP11:%.*]] = icmp sgt i32 [[TMP43]], [[TMP44]]
+// IR-GPU-NEXT: br i1 [[CMP11]], label [[COND_TRUE12:%.*]], label [[COND_FALSE13:%.*]]
+// IR-GPU: cond.true12:
+// IR-GPU-NEXT: [[TMP45:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END14:%.*]]
+// IR-GPU: cond.false13:
+// IR-GPU-NEXT: [[TMP46:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END14]]
+// IR-GPU: cond.end14:
+// IR-GPU-NEXT: [[COND15:%.*]] = phi i32 [ [[TMP45]], [[COND_TRUE12]] ], [ [[TMP46]], [[COND_FALSE13]] ]
+// IR-GPU-NEXT: store i32 [[COND15]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP47:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP47]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP48:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP49:%.*]] = load i32, ptr [[TMP48]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP49]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41_omp_outlined_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J6:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_UB__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_3]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[J6_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J6]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-GPU-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-GPU-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB3:[0-9]+]] to ptr), i32 [[TMP11]], i32 33, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_LB_ASCAST]], ptr [[DOTOMP_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 1)
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP12]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[CONV7:%.*]] = sext i32 [[TMP13]] to i64
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CMP8:%.*]] = icmp ule i64 [[CONV7]], [[TMP14]]
+// IR-GPU-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-GPU-NEXT: store i32 [[ADD]], ptr [[J6_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i32, ptr [[J6_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP16]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-GPU-NEXT: [[TMP18:%.*]] = load i32, ptr [[J6_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM9:%.*]] = sext i32 [[TMP18]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM9]]
+// IR-GPU-NEXT: store i32 [[TMP17]], ptr [[ARRAYIDX10]], align 4
+// IR-GPU-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-GPU: omp.body.continue:
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP19]], [[TMP20]]
+// IR-GPU-NEXT: store i32 [[ADD11]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP22]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46
+// IR-GPU-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DYN_PTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DYN_PTR_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
+// IR-GPU-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46_kernel_environment to ptr), ptr [[DYN_PTR]])
+// IR-GPU-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP4]], -1
+// IR-GPU-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
+// IR-GPU: user_code.entry:
+// IR-GPU-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr))
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP6]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
+// IR-GPU-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46_omp_outlined(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP7]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) #[[ATTR2]]
+// IR-GPU-NEXT: call void @__kmpc_target_deinit()
+// IR-GPU-NEXT: ret void
+// IR-GPU: worker.exit:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[_TMP3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I11:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J12:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [7 x ptr], align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[TMP3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP3]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_4]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_5]] to ptr
+// IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[I11_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I11]] to ptr
+// IR-GPU-NEXT: [[J12_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J12]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-GPU-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-GPU-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-GPU-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-GPU-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-GPU-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: land.lhs.true:
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-GPU-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
+// IR-GPU-NEXT: [[CONV13:%.*]] = zext i32 [[NVPTX_NUM_THREADS]] to i64
+// IR-GPU-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_init_8(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP12]], i32 91, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i64 1, i64 [[CONV13]])
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: [[CMP14:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-GPU-NEXT: br i1 [[CMP14]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-GPU: cond.true:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[COND_END:%.*]]
+// IR-GPU: cond.false:
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[COND_END]]
+// IR-GPU: cond.end:
+// IR-GPU-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-GPU-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP19]], 1
+// IR-GPU-NEXT: [[CMP15:%.*]] = icmp slt i64 [[TMP18]], [[ADD]]
+// IR-GPU-NEXT: br i1 [[CMP15]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP22]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP24:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 0
+// IR-GPU-NEXT: [[TMP25:%.*]] = inttoptr i64 [[TMP20]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP25]], ptr [[TMP24]], align 8
+// IR-GPU-NEXT: [[TMP26:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 1
+// IR-GPU-NEXT: [[TMP27:%.*]] = inttoptr i64 [[TMP21]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP27]], ptr [[TMP26]], align 8
+// IR-GPU-NEXT: [[TMP28:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 2
+// IR-GPU-NEXT: [[TMP29:%.*]] = inttoptr i64 [[TMP23]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP29]], ptr [[TMP28]], align 8
+// IR-GPU-NEXT: [[TMP30:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 3
+// IR-GPU-NEXT: [[TMP31:%.*]] = inttoptr i64 [[TMP0]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP31]], ptr [[TMP30]], align 8
+// IR-GPU-NEXT: [[TMP32:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 4
+// IR-GPU-NEXT: store ptr [[TMP1]], ptr [[TMP32]], align 8
+// IR-GPU-NEXT: [[TMP33:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 5
+// IR-GPU-NEXT: [[TMP34:%.*]] = inttoptr i64 [[TMP2]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP34]], ptr [[TMP33]], align 8
+// IR-GPU-NEXT: [[TMP35:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 6
+// IR-GPU-NEXT: store ptr [[TMP3]], ptr [[TMP35]], align 8
+// IR-GPU-NEXT: [[TMP36:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP37:%.*]] = load i32, ptr [[TMP36]], align 4
+// IR-GPU-NEXT: call void @__kmpc_parallel_51(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP37]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 7)
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP38:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP39:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: [[ADD16:%.*]] = add nsw i64 [[TMP38]], [[TMP39]]
+// IR-GPU-NEXT: store i64 [[ADD16]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP40:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP41:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: [[ADD17:%.*]] = add nsw i64 [[TMP40]], [[TMP41]]
+// IR-GPU-NEXT: store i64 [[ADD17]], ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP42:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP43:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: [[ADD18:%.*]] = add nsw i64 [[TMP42]], [[TMP43]]
+// IR-GPU-NEXT: store i64 [[ADD18]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP44:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP45:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: [[CMP19:%.*]] = icmp sgt i64 [[TMP44]], [[TMP45]]
+// IR-GPU-NEXT: br i1 [[CMP19]], label [[COND_TRUE20:%.*]], label [[COND_FALSE21:%.*]]
+// IR-GPU: cond.true20:
+// IR-GPU-NEXT: [[TMP46:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[COND_END22:%.*]]
+// IR-GPU: cond.false21:
+// IR-GPU-NEXT: [[TMP47:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[COND_END22]]
+// IR-GPU: cond.end22:
+// IR-GPU-NEXT: [[COND23:%.*]] = phi i64 [ [[TMP46]], [[COND_TRUE20]] ], [ [[TMP47]], [[COND_FALSE21]] ]
+// IR-GPU-NEXT: store i64 [[COND23]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP48:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP48]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP49:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP50:%.*]] = load i32, ptr [[TMP49]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP50]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46_omp_outlined_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[_TMP3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I11:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J12:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_UB__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[TMP3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP3]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_4]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_5]] to ptr
+// IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[I11_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I11]] to ptr
+// IR-GPU-NEXT: [[J12_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J12]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-GPU-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-GPU-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-GPU-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-GPU-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-GPU-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: land.lhs.true:
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-GPU-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i64 0, ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_init_8(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP14]], i32 33, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_LB_ASCAST]], ptr [[DOTOMP_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i64 1, i64 1)
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[TMP15]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CMP13:%.*]] = icmp ule i64 [[TMP16]], [[TMP17]]
+// IR-GPU-NEXT: br i1 [[CMP13]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB14:%.*]] = sub nsw i32 [[TMP19]], 0
+// IR-GPU-NEXT: [[DIV15:%.*]] = sdiv i32 [[SUB14]], 1
+// IR-GPU-NEXT: [[MUL16:%.*]] = mul nsw i32 1, [[DIV15]]
+// IR-GPU-NEXT: [[CONV17:%.*]] = sext i32 [[MUL16]] to i64
+// IR-GPU-NEXT: [[DIV18:%.*]] = sdiv i64 [[TMP18]], [[CONV17]]
+// IR-GPU-NEXT: [[MUL19:%.*]] = mul nsw i64 [[DIV18]], 1
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL19]]
+// IR-GPU-NEXT: [[CONV20:%.*]] = trunc i64 [[ADD]] to i32
+// IR-GPU-NEXT: store i32 [[CONV20]], ptr [[I11_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB21:%.*]] = sub nsw i32 [[TMP22]], 0
+// IR-GPU-NEXT: [[DIV22:%.*]] = sdiv i32 [[SUB21]], 1
+// IR-GPU-NEXT: [[MUL23:%.*]] = mul nsw i32 1, [[DIV22]]
+// IR-GPU-NEXT: [[CONV24:%.*]] = sext i32 [[MUL23]] to i64
+// IR-GPU-NEXT: [[DIV25:%.*]] = sdiv i64 [[TMP21]], [[CONV24]]
+// IR-GPU-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB26:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-GPU-NEXT: [[DIV27:%.*]] = sdiv i32 [[SUB26]], 1
+// IR-GPU-NEXT: [[MUL28:%.*]] = mul nsw i32 1, [[DIV27]]
+// IR-GPU-NEXT: [[CONV29:%.*]] = sext i32 [[MUL28]] to i64
+// IR-GPU-NEXT: [[MUL30:%.*]] = mul nsw i64 [[DIV25]], [[CONV29]]
+// IR-GPU-NEXT: [[SUB31:%.*]] = sub nsw i64 [[TMP20]], [[MUL30]]
+// IR-GPU-NEXT: [[MUL32:%.*]] = mul nsw i64 [[SUB31]], 1
+// IR-GPU-NEXT: [[ADD33:%.*]] = add nsw i64 0, [[MUL32]]
+// IR-GPU-NEXT: [[CONV34:%.*]] = trunc i64 [[ADD33]] to i32
+// IR-GPU-NEXT: store i32 [[CONV34]], ptr [[J12_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP24:%.*]] = load i32, ptr [[I11_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP24]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-GPU-NEXT: [[TMP25:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-GPU-NEXT: [[TMP26:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL35:%.*]] = mul nsw i32 [[TMP25]], [[TMP26]]
+// IR-GPU-NEXT: [[TMP27:%.*]] = load i32, ptr [[J12_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD36:%.*]] = add nsw i32 [[MUL35]], [[TMP27]]
+// IR-GPU-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM37:%.*]] = sext i32 [[TMP28]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX38:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM37]]
+// IR-GPU-NEXT: store i32 [[ADD36]], ptr [[ARRAYIDX38]], align 4
+// IR-GPU-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-GPU: omp.body.continue:
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP29:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP30:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NEXT: [[ADD39:%.*]] = add nsw i64 [[TMP29]], [[TMP30]]
+// IR-GPU-NEXT: store i64 [[ADD39]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP32]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55
+// IR-GPU-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR4:[0-9]+]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DYN_PTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DYN_PTR_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[NT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[NT_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[NT_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[NT_CASTED]] to ptr
+// IR-GPU-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
+// IR-GPU-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[NT]], ptr [[NT_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55_kernel_environment to ptr), ptr [[DYN_PTR]])
+// IR-GPU-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP4]], -1
+// IR-GPU-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
+// IR-GPU: user_code.entry:
+// IR-GPU-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr))
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP6]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP8:%.*]] = load i32, ptr [[NT_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP8]], ptr [[NT_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i64, ptr [[NT_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP5]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
+// IR-GPU-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55_omp_outlined(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP7]], i64 [[TMP9]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) #[[ATTR2]]
+// IR-GPU-NEXT: call void @__kmpc_target_deinit()
+// IR-GPU-NEXT: ret void
+// IR-GPU: worker.exit:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I5:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [8 x ptr], align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[NT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[NT_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_3]] to ptr
+// IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[I5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I5]] to ptr
+// IR-GPU-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NEXT: [[NT_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[NT_CASTED]] to ptr
+// IR-GPU-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[NT]], ptr [[NT_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-GPU-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
+// IR-GPU-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP9]], i32 91, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 [[NVPTX_NUM_THREADS]])
+// IR-GPU-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-GPU-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-GPU: cond.true:
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END:%.*]]
+// IR-GPU: cond.false:
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END]]
+// IR-GPU: cond.end:
+// IR-GPU-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-GPU-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP16]], 1
+// IR-GPU-NEXT: [[CMP7:%.*]] = icmp slt i32 [[TMP15]], [[ADD]]
+// IR-GPU-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP21]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP23:%.*]] = load i32, ptr [[NT_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP23]], ptr [[NT_CASTED_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP24:%.*]] = load i64, ptr [[NT_CASTED_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP25:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 0
+// IR-GPU-NEXT: [[TMP26:%.*]] = inttoptr i64 [[TMP18]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP26]], ptr [[TMP25]], align 8
+// IR-GPU-NEXT: [[TMP27:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 1
+// IR-GPU-NEXT: [[TMP28:%.*]] = inttoptr i64 [[TMP20]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP28]], ptr [[TMP27]], align 8
+// IR-GPU-NEXT: [[TMP29:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 2
+// IR-GPU-NEXT: [[TMP30:%.*]] = inttoptr i64 [[TMP22]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP30]], ptr [[TMP29]], align 8
+// IR-GPU-NEXT: [[TMP31:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 3
+// IR-GPU-NEXT: [[TMP32:%.*]] = inttoptr i64 [[TMP24]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP32]], ptr [[TMP31]], align 8
+// IR-GPU-NEXT: [[TMP33:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 4
+// IR-GPU-NEXT: [[TMP34:%.*]] = inttoptr i64 [[TMP0]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP34]], ptr [[TMP33]], align 8
+// IR-GPU-NEXT: [[TMP35:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 5
+// IR-GPU-NEXT: store ptr [[TMP1]], ptr [[TMP35]], align 8
+// IR-GPU-NEXT: [[TMP36:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 6
+// IR-GPU-NEXT: [[TMP37:%.*]] = inttoptr i64 [[TMP2]] to ptr
+// IR-GPU-NEXT: store ptr [[TMP37]], ptr [[TMP36]], align 8
+// IR-GPU-NEXT: [[TMP38:%.*]] = getelementptr inbounds [8 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 7
+// IR-GPU-NEXT: store ptr [[TMP3]], ptr [[TMP38]], align 8
+// IR-GPU-NEXT: [[TMP39:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP40:%.*]] = load i32, ptr [[TMP39]], align 4
+// IR-GPU-NEXT: call void @__kmpc_parallel_51(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP40]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 8)
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP41:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP42:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP41]], [[TMP42]]
+// IR-GPU-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP43:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP44:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP43]], [[TMP44]]
+// IR-GPU-NEXT: store i32 [[ADD9]], ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP45:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP46:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP45]], [[TMP46]]
+// IR-GPU-NEXT: store i32 [[ADD10]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP47:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP48:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP11:%.*]] = icmp sgt i32 [[TMP47]], [[TMP48]]
+// IR-GPU-NEXT: br i1 [[CMP11]], label [[COND_TRUE12:%.*]], label [[COND_FALSE13:%.*]]
+// IR-GPU: cond.true12:
+// IR-GPU-NEXT: [[TMP49:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END14:%.*]]
+// IR-GPU: cond.false13:
+// IR-GPU-NEXT: [[TMP50:%.*]] = load i32, ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[COND_END14]]
+// IR-GPU: cond.end14:
+// IR-GPU-NEXT: [[COND15:%.*]] = phi i32 [ [[TMP49]], [[COND_TRUE12]] ], [ [[TMP50]], [[COND_FALSE13]] ]
+// IR-GPU-NEXT: store i32 [[COND15]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP51:%.*]] = load i32, ptr [[DOTOMP_COMB_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP51]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP52:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP53:%.*]] = load i32, ptr [[TMP52]], align 4
+// IR-GPU-NEXT: call void @__kmpc_distribute_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP53]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-GPU-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55_omp_outlined_omp_outlined
+// IR-GPU-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NEXT: entry:
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[I6:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTPREVIOUS_UB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_UB__ADDR]] to ptr
+// IR-GPU-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NEXT: [[NT_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[NT_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NEXT: [[DOTCAPTURE_EXPR_3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_3]] to ptr
+// IR-GPU-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_LB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_UB]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NEXT: [[I6_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I6]] to ptr
+// IR-GPU-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[NT]], ptr [[NT_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-GPU-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-GPU-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-GPU-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU: omp.precond.then:
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-GPU-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-GPU-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_init_4(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP11]], i32 33, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_LB_ASCAST]], ptr [[DOTOMP_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i32 1, i32 1)
+// IR-GPU-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_LB_ASCAST]], align 4
+// IR-GPU-NEXT: store i32 [[TMP12]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU: omp.inner.for.cond:
+// IR-GPU-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[CONV7:%.*]] = sext i32 [[TMP13]] to i64
+// IR-GPU-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[CMP8:%.*]] = icmp ule i64 [[CONV7]], [[TMP14]]
+// IR-GPU-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU: omp.inner.for.body:
+// IR-GPU-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
+// IR-GPU-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-GPU-NEXT: store i32 [[ADD]], ptr [[I6_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP16:%.*]] = load i32, ptr [[NT_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP16]], 0
+// IR-GPU-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+// IR-GPU: if.then:
+// IR-GPU-NEXT: [[CALL:%.*]] = call noundef i32 @_Z17omp_get_num_teamsv() #[[ATTR6:[0-9]+]]
+// IR-GPU-NEXT: store i32 [[CALL]], ptr [[NT_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[IF_END]]
+// IR-GPU: if.end:
+// IR-GPU-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[FOR_COND:%.*]]
+// IR-GPU: for.cond:
+// IR-GPU-NEXT: [[TMP17:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP18:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[CMP9:%.*]] = icmp slt i32 [[TMP17]], [[TMP18]]
+// IR-GPU-NEXT: br i1 [[CMP9]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR-GPU: for.body:
+// IR-GPU-NEXT: [[TMP19:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP19]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-GPU-NEXT: [[TMP20:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-GPU-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[MUL10:%.*]] = mul nsw i32 [[TMP20]], [[TMP21]]
+// IR-GPU-NEXT: [[TMP22:%.*]] = load i32, ptr [[NT_ADDR_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD11:%.*]] = add nsw i32 [[MUL10]], [[TMP22]]
+// IR-GPU-NEXT: [[TMP23:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[IDXPROM12:%.*]] = sext i32 [[TMP23]] to i64
+// IR-GPU-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM12]]
+// IR-GPU-NEXT: store i32 [[ADD11]], ptr [[ARRAYIDX13]], align 4
+// IR-GPU-NEXT: br label [[FOR_INC:%.*]]
+// IR-GPU: for.inc:
+// IR-GPU-NEXT: [[TMP24:%.*]] = load i32, ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: [[INC:%.*]] = add nsw i32 [[TMP24]], 1
+// IR-GPU-NEXT: store i32 [[INC]], ptr [[J_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP11:![0-9]+]]
+// IR-GPU: for.end:
+// IR-GPU-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-GPU: omp.body.continue:
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU: omp.inner.for.inc:
+// IR-GPU-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_STRIDE_ASCAST]], align 4
+// IR-GPU-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP25]], [[TMP26]]
+// IR-GPU-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV_ASCAST]], align 4
+// IR-GPU-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU: omp.inner.for.end:
+// IR-GPU-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU: omp.loop.exit:
+// IR-GPU-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-GPU-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP28]])
+// IR-GPU-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU: omp.precond.end:
+// IR-GPU-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@main
+// IR-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_CASTED2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT:%.*]] = alloca i32, align 4
+// IR-NEXT: [[N_CASTED3:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[N_CASTED2]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i64, ptr [[N_CASTED2]], align 8
+// IR-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46(i64 [[TMP8]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3]]
+// IR-NEXT: store i32 0, ptr [[NT]], align 4
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr @N, align 4
+// IR-NEXT: store i32 [[TMP9]], ptr [[N_CASTED3]], align 4
+// IR-NEXT: [[TMP10:%.*]] = load i64, ptr [[N_CASTED3]], align 8
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[NT]], align 4
+// IR-NEXT: store i32 [[TMP11]], ptr [[NT_CASTED]], align 4
+// IR-NEXT: [[TMP12:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55(i64 [[TMP10]], i64 [[TMP12]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3]]
+// IR-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NEXT: [[TMP13:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP13]])
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-NEXT: ret i32 [[TMP14]]
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41
+// IR-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J5:%.*]] = alloca i32, align 4
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: omp.precond.then:
+// IR-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP21]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined.omp_outlined, i64 [[TMP18]], i64 [[TMP20]], i64 [[TMP22]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP24:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP23]], [[TMP24]]
+// IR-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP25:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[TMP25]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP26]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J6:%.*]] = alloca i32, align 4
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: omp.precond.then:
+// IR-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP11]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: [[CMP7:%.*]] = icmp sgt i32 [[TMP12]], [[TMP13]]
+// IR-NEXT: br i1 [[CMP7]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i32 [ [[TMP14]], [[COND_TRUE]] ], [ [[TMP15]], [[COND_FALSE]] ]
+// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: store i32 [[TMP16]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[CMP8:%.*]] = icmp sle i32 [[TMP17]], [[TMP18]]
+// IR-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP19]], 1
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-NEXT: store i32 [[ADD]], ptr [[J6]], align 4
+// IR-NEXT: [[TMP20:%.*]] = load i32, ptr [[J6]], align 4
+// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64
+// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i32, ptr [[J6]], align 4
+// IR-NEXT: [[IDXPROM9:%.*]] = sext i32 [[TMP22]] to i64
+// IR-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM9]]
+// IR-NEXT: store i32 [[TMP21]], ptr [[ARRAYIDX10]], align 4
+// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR: omp.body.continue:
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP23]], 1
+// IR-NEXT: store i32 [[ADD11]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP24:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP25:%.*]] = load i32, ptr [[TMP24]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP25]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46
+// IR-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: land.lhs.true:
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR: omp.precond.then:
+// IR-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB1]], i32 [[TMP12]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP18]], [[TMP19]]
+// IR-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP22]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined.omp_outlined, i64 [[TMP20]], i64 [[TMP21]], i64 [[TMP23]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP24]], [[TMP25]]
+// IR-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP26:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP27:%.*]] = load i32, ptr [[TMP26]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP27]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: land.lhs.true:
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR: omp.precond.then:
+// IR-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
+// IR-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB]], align 8
+// IR-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2]], i32 [[TMP14]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP15]], [[TMP16]]
+// IR-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i64 [ [[TMP17]], [[COND_TRUE]] ], [ [[TMP18]], [[COND_FALSE]] ]
+// IR-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
+// IR-NEXT: store i64 [[TMP19]], ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP20]], [[TMP21]]
+// IR-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
+// IR-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
+// IR-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
+// IR-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP22]], [[CONV18]]
+// IR-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
+// IR-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
+// IR-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
+// IR-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
+// IR-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP26]], 0
+// IR-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
+// IR-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
+// IR-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
+// IR-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP25]], [[CONV25]]
+// IR-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP27]], 0
+// IR-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
+// IR-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
+// IR-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
+// IR-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
+// IR-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP24]], [[MUL31]]
+// IR-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
+// IR-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
+// IR-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
+// IR-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
+// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11]], align 4
+// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP28]] to i64
+// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-NEXT: [[TMP29:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-NEXT: [[TMP30:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: [[MUL36:%.*]] = mul nsw i32 [[TMP29]], [[TMP30]]
+// IR-NEXT: [[TMP31:%.*]] = load i32, ptr [[J12]], align 4
+// IR-NEXT: [[ADD37:%.*]] = add nsw i32 [[MUL36]], [[TMP31]]
+// IR-NEXT: [[TMP32:%.*]] = load i32, ptr [[I11]], align 4
+// IR-NEXT: [[IDXPROM38:%.*]] = sext i32 [[TMP32]] to i64
+// IR-NEXT: [[ARRAYIDX39:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM38]]
+// IR-NEXT: store i32 [[ADD37]], ptr [[ARRAYIDX39]], align 4
+// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR: omp.body.continue:
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP33:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: [[ADD40:%.*]] = add nsw i64 [[TMP33]], 1
+// IR-NEXT: store i64 [[ADD40]], ptr [[DOTOMP_IV]], align 8
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP34:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP34]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP35]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55
+// IR-SAME: (i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 32, i32 0)
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[NT_CASTED]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 6, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined, i64 [[TMP6]], i64 [[TMP8]], i64 [[TMP1]], ptr [[TMP2]], i64 [[TMP3]], ptr [[TMP4]])
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I5:%.*]] = alloca i32, align 4
+// IR-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: omp.precond.then:
+// IR-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP21]], ptr [[N_CASTED]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP23]], ptr [[NT_CASTED]], align 4
+// IR-NEXT: [[TMP24:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 8, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined.omp_outlined, i64 [[TMP18]], i64 [[TMP20]], i64 [[TMP22]], i64 [[TMP24]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP25]], [[TMP26]]
+// IR-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP28]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined.omp_outlined
+// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NEXT: entry:
+// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NEXT: [[I6:%.*]] = alloca i32, align 4
+// IR-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR: omp.precond.then:
+// IR-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP11]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: [[CMP7:%.*]] = icmp sgt i32 [[TMP12]], [[TMP13]]
+// IR-NEXT: br i1 [[CMP7]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR: cond.true:
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-NEXT: br label [[COND_END:%.*]]
+// IR: cond.false:
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: br label [[COND_END]]
+// IR: cond.end:
+// IR-NEXT: [[COND:%.*]] = phi i32 [ [[TMP14]], [[COND_TRUE]] ], [ [[TMP15]], [[COND_FALSE]] ]
+// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
+// IR-NEXT: store i32 [[TMP16]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR: omp.inner.for.cond:
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-NEXT: [[CMP8:%.*]] = icmp sle i32 [[TMP17]], [[TMP18]]
+// IR-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR: omp.inner.for.body:
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP19]], 1
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-NEXT: store i32 [[ADD]], ptr [[I6]], align 4
+// IR-NEXT: [[TMP20:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP20]], 0
+// IR-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+// IR: if.then:
+// IR-NEXT: [[CALL:%.*]] = call noundef i32 @_Z17omp_get_num_teamsv()
+// IR-NEXT: store i32 [[CALL]], ptr [[NT_ADDR]], align 4
+// IR-NEXT: br label [[IF_END]]
+// IR: if.end:
+// IR-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NEXT: br label [[FOR_COND:%.*]]
+// IR: for.cond:
+// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: [[CMP9:%.*]] = icmp slt i32 [[TMP21]], [[TMP22]]
+// IR-NEXT: br i1 [[CMP9]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR: for.body:
+// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP23]] to i64
+// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-NEXT: [[TMP24:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-NEXT: [[TMP25:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NEXT: [[MUL10:%.*]] = mul nsw i32 [[TMP24]], [[TMP25]]
+// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-NEXT: [[ADD11:%.*]] = add nsw i32 [[MUL10]], [[TMP26]]
+// IR-NEXT: [[TMP27:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[IDXPROM12:%.*]] = sext i32 [[TMP27]] to i64
+// IR-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM12]]
+// IR-NEXT: store i32 [[ADD11]], ptr [[ARRAYIDX13]], align 4
+// IR-NEXT: br label [[FOR_INC:%.*]]
+// IR: for.inc:
+// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[J]], align 4
+// IR-NEXT: [[INC:%.*]] = add nsw i32 [[TMP28]], 1
+// IR-NEXT: store i32 [[INC]], ptr [[J]], align 4
+// IR-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP5:![0-9]+]]
+// IR: for.end:
+// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR: omp.body.continue:
+// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR: omp.inner.for.inc:
+// IR-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP29]], 1
+// IR-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR: omp.inner.for.end:
+// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR: omp.loop.exit:
+// IR-NEXT: [[TMP30:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP31:%.*]] = load i32, ptr [[TMP30]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP31]])
+// IR-NEXT: br label [[OMP_PRECOND_END]]
+// IR: omp.precond.end:
+// IR-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@main
+// IR-PCH-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_CASTED2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[N_CASTED3:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-PCH-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-PCH-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-PCH-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-PCH-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-PCH-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-PCH-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[N_CASTED2]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i64, ptr [[N_CASTED2]], align 8
+// IR-PCH-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46(i64 [[TMP8]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3]]
+// IR-PCH-NEXT: store i32 0, ptr [[NT]], align 4
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NEXT: store i32 [[TMP9]], ptr [[N_CASTED3]], align 4
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i64, ptr [[N_CASTED3]], align 8
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[NT]], align 4
+// IR-PCH-NEXT: store i32 [[TMP11]], ptr [[NT_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-PCH-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55(i64 [[TMP10]], i64 [[TMP12]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3]]
+// IR-PCH-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: [[TMP13:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-PCH-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP13]])
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-PCH-NEXT: ret i32 [[TMP14]]
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41
+// IR-PCH-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J5:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1:[0-9]+]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-PCH-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-PCH-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP21]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined.omp_outlined, i64 [[TMP18]], i64 [[TMP20]], i64 [[TMP22]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP23]], [[TMP24]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP25:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[TMP25]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP26]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l41.omp_outlined.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J6:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-PCH-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP11]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: [[CMP7:%.*]] = icmp sgt i32 [[TMP12]], [[TMP13]]
+// IR-PCH-NEXT: br i1 [[CMP7]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ [[TMP14]], [[COND_TRUE]] ], [ [[TMP15]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: store i32 [[TMP16]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[CMP8:%.*]] = icmp sle i32 [[TMP17]], [[TMP18]]
+// IR-PCH-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP19]], 1
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[J6]], align 4
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i32, ptr [[J6]], align 4
+// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP20]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i32, ptr [[J6]], align 4
+// IR-PCH-NEXT: [[IDXPROM9:%.*]] = sext i32 [[TMP22]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX10:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM9]]
+// IR-PCH-NEXT: store i32 [[TMP21]], ptr [[ARRAYIDX10]], align 4
+// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH: omp.body.continue:
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[ADD11:%.*]] = add nsw i32 [[TMP23]], 1
+// IR-PCH-NEXT: store i32 [[ADD11]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP24:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i32, ptr [[TMP24]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP25]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46
+// IR-PCH-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-PCH-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-PCH-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-PCH-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-PCH-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: land.lhs.true:
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-PCH-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB1]], i32 [[TMP12]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-PCH-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP18]], [[TMP19]]
+// IR-PCH-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP22]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined.omp_outlined, i64 [[TMP20]], i64 [[TMP21]], i64 [[TMP23]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP24]], [[TMP25]]
+// IR-PCH-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP26:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP27:%.*]] = load i32, ptr [[TMP26]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP27]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l46.omp_outlined.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-PCH-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-PCH-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-PCH-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-PCH-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: land.lhs.true:
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-PCH-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2]], i32 [[TMP14]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP15]], [[TMP16]]
+// IR-PCH-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i64 [ [[TMP17]], [[COND_TRUE]] ], [ [[TMP18]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NEXT: store i64 [[TMP19]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP20]], [[TMP21]]
+// IR-PCH-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-PCH-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
+// IR-PCH-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
+// IR-PCH-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
+// IR-PCH-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP22]], [[CONV18]]
+// IR-PCH-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
+// IR-PCH-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
+// IR-PCH-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP26]], 0
+// IR-PCH-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
+// IR-PCH-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
+// IR-PCH-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
+// IR-PCH-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP25]], [[CONV25]]
+// IR-PCH-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP27]], 0
+// IR-PCH-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
+// IR-PCH-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
+// IR-PCH-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
+// IR-PCH-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
+// IR-PCH-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP24]], [[MUL31]]
+// IR-PCH-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
+// IR-PCH-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
+// IR-PCH-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
+// IR-PCH-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
+// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11]], align 4
+// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP28]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-PCH-NEXT: [[TMP29:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-PCH-NEXT: [[TMP30:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: [[MUL36:%.*]] = mul nsw i32 [[TMP29]], [[TMP30]]
+// IR-PCH-NEXT: [[TMP31:%.*]] = load i32, ptr [[J12]], align 4
+// IR-PCH-NEXT: [[ADD37:%.*]] = add nsw i32 [[MUL36]], [[TMP31]]
+// IR-PCH-NEXT: [[TMP32:%.*]] = load i32, ptr [[I11]], align 4
+// IR-PCH-NEXT: [[IDXPROM38:%.*]] = sext i32 [[TMP32]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX39:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM38]]
+// IR-PCH-NEXT: store i32 [[ADD37]], ptr [[ARRAYIDX39]], align 4
+// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH: omp.body.continue:
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP33:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: [[ADD40:%.*]] = add nsw i64 [[TMP33]], 1
+// IR-PCH-NEXT: store i64 [[ADD40]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP34:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP34]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP35]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55
+// IR-PCH-SAME: (i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 32, i32 0)
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[NT_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 6, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined, i64 [[TMP6]], i64 [[TMP8]], i64 [[TMP1]], ptr [[TMP2]], i64 [[TMP3]], ptr [[TMP4]])
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I5:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB1]], i32 [[TMP9]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: [[CMP6:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
+// IR-PCH-NEXT: br i1 [[CMP6]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[CMP7:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
+// IR-PCH-NEXT: br i1 [[CMP7]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
+// IR-PCH-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
+// IR-PCH-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP21]], ptr [[N_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP23]], ptr [[NT_CASTED]], align 4
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i64, ptr [[NT_CASTED]], align 8
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 8, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined.omp_outlined, i64 [[TMP18]], i64 [[TMP20]], i64 [[TMP22]], i64 [[TMP24]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP25]], [[TMP26]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP28]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-PCH-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l55.omp_outlined.omp_outlined
+// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[NT:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NEXT: entry:
+// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[NT_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTCAPTURE_EXPR_3:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[I6:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[NT]], ptr [[NT_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP5]], 0
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NEXT: [[SUB4:%.*]] = sub nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: store i32 [[SUB4]], ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP6]]
+// IR-PCH-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH: omp.precond.then:
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NEXT: [[CONV:%.*]] = trunc i64 [[TMP8]] to i32
+// IR-PCH-NEXT: [[TMP9:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NEXT: [[CONV5:%.*]] = trunc i64 [[TMP9]] to i32
+// IR-PCH-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: store i32 [[CONV5]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
+// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP10:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[TMP10]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP11]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: [[CMP7:%.*]] = icmp sgt i32 [[TMP12]], [[TMP13]]
+// IR-PCH-NEXT: br i1 [[CMP7]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH: cond.true:
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_3]], align 4
+// IR-PCH-NEXT: br label [[COND_END:%.*]]
+// IR-PCH: cond.false:
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: br label [[COND_END]]
+// IR-PCH: cond.end:
+// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ [[TMP14]], [[COND_TRUE]] ], [ [[TMP15]], [[COND_FALSE]] ]
+// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
+// IR-PCH-NEXT: store i32 [[TMP16]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH: omp.inner.for.cond:
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
+// IR-PCH-NEXT: [[CMP8:%.*]] = icmp sle i32 [[TMP17]], [[TMP18]]
+// IR-PCH-NEXT: br i1 [[CMP8]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH: omp.inner.for.body:
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP19]], 1
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[I6]], align 4
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-PCH-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP20]], 0
+// IR-PCH-NEXT: br i1 [[TOBOOL]], label [[IF_END:%.*]], label [[IF_THEN:%.*]]
+// IR-PCH: if.then:
+// IR-PCH-NEXT: [[CALL:%.*]] = call noundef i32 @_Z17omp_get_num_teamsv()
+// IR-PCH-NEXT: store i32 [[CALL]], ptr [[NT_ADDR]], align 4
+// IR-PCH-NEXT: br label [[IF_END]]
+// IR-PCH: if.end:
+// IR-PCH-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NEXT: br label [[FOR_COND:%.*]]
+// IR-PCH: for.cond:
+// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: [[CMP9:%.*]] = icmp slt i32 [[TMP21]], [[TMP22]]
+// IR-PCH-NEXT: br i1 [[CMP9]], label [[FOR_BODY:%.*]], label [[FOR_END:%.*]]
+// IR-PCH: for.body:
+// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP23]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-PCH-NEXT: [[TMP24:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NEXT: [[MUL10:%.*]] = mul nsw i32 [[TMP24]], [[TMP25]]
+// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[NT_ADDR]], align 4
+// IR-PCH-NEXT: [[ADD11:%.*]] = add nsw i32 [[MUL10]], [[TMP26]]
+// IR-PCH-NEXT: [[TMP27:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[IDXPROM12:%.*]] = sext i32 [[TMP27]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX13:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM12]]
+// IR-PCH-NEXT: store i32 [[ADD11]], ptr [[ARRAYIDX13]], align 4
+// IR-PCH-NEXT: br label [[FOR_INC:%.*]]
+// IR-PCH: for.inc:
+// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[J]], align 4
+// IR-PCH-NEXT: [[INC:%.*]] = add nsw i32 [[TMP28]], 1
+// IR-PCH-NEXT: store i32 [[INC]], ptr [[J]], align 4
+// IR-PCH-NEXT: br label [[FOR_COND]], !llvm.loop [[LOOP5:![0-9]+]]
+// IR-PCH: for.end:
+// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH: omp.body.continue:
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH: omp.inner.for.inc:
+// IR-PCH-NEXT: [[TMP29:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP29]], 1
+// IR-PCH-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH: omp.inner.for.end:
+// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH: omp.loop.exit:
+// IR-PCH-NEXT: [[TMP30:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP31:%.*]] = load i32, ptr [[TMP30]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP31]])
+// IR-PCH-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH: omp.precond.end:
+// IR-PCH-NEXT: ret void
+//
+//
+// IR-GPU-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64
+// IR-GPU-NESTED-SAME: (ptr noalias noundef [[DYN_PTR:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+// IR-GPU-NESTED-NEXT: entry:
+// IR-GPU-NESTED-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTZERO_ADDR:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTTHREADID_TEMP_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DYN_PTR_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DYN_PTR_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NESTED-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTZERO_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTZERO_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTTHREADID_TEMP__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTTHREADID_TEMP_]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP4:%.*]] = call i32 @__kmpc_target_init(ptr addrspacecast (ptr addrspace(1) @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64_kernel_environment to ptr), ptr [[DYN_PTR]])
+// IR-GPU-NESTED-NEXT: [[EXEC_USER_CODE:%.*]] = icmp eq i32 [[TMP4]], -1
+// IR-GPU-NESTED-NEXT: br i1 [[EXEC_USER_CODE]], label [[USER_CODE_ENTRY:%.*]], label [[WORKER_EXIT:%.*]]
+// IR-GPU-NESTED: user_code.entry:
+// IR-GPU-NESTED-NEXT: [[TMP5:%.*]] = call i32 @__kmpc_global_thread_num(ptr addrspacecast (ptr addrspace(1) @[[GLOB1:[0-9]+]] to ptr))
+// IR-GPU-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP6]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP7:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[DOTZERO_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTTHREADID_TEMP__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64_omp_outlined(ptr [[DOTTHREADID_TEMP__ASCAST]], ptr [[DOTZERO_ADDR_ASCAST]], i64 [[TMP7]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]]) #[[ATTR2:[0-9]+]]
+// IR-GPU-NESTED-NEXT: call void @__kmpc_target_deinit()
+// IR-GPU-NESTED-NEXT: ret void
+// IR-GPU-NESTED: worker.exit:
+// IR-GPU-NESTED-NEXT: ret void
+//
+//
+// IR-GPU-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64_omp_outlined
+// IR-GPU-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1:[0-9]+]] {
+// IR-GPU-NESTED-NEXT: entry:
+// IR-GPU-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[CAPTURED_VARS_ADDRS:%.*]] = alloca [7 x ptr], align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NESTED-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NESTED-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NESTED-NEXT: [[TMP3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP3]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_4]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_5]] to ptr
+// IR-GPU-NESTED-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NESTED-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_COMB_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_LB]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_COMB_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_COMB_UB]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NESTED-NEXT: [[I11_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I11]] to ptr
+// IR-GPU-NESTED-NEXT: [[J12_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J12]] to ptr
+// IR-GPU-NESTED-NEXT: [[N_CASTED_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_CASTED]] to ptr
+// IR-GPU-NESTED-NEXT: [[CAPTURED_VARS_ADDRS_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[CAPTURED_VARS_ADDRS]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-GPU-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-GPU-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-GPU-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-GPU-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-GPU-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-GPU-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-GPU-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU-NESTED: land.lhs.true:
+// IR-GPU-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-GPU-NESTED: omp.precond.then:
+// IR-GPU-NESTED-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[NVPTX_NUM_THREADS:%.*]] = call i32 @__kmpc_get_hardware_num_threads_in_block()
+// IR-GPU-NESTED-NEXT: [[CONV13:%.*]] = zext i32 [[NVPTX_NUM_THREADS]] to i64
+// IR-GPU-NESTED-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-GPU-NESTED-NEXT: call void @__kmpc_distribute_static_init_8(ptr addrspacecast (ptr addrspace(1) @[[GLOB2:[0-9]+]] to ptr), i32 [[TMP12]], i32 91, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_COMB_LB_ASCAST]], ptr [[DOTOMP_COMB_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i64 1, i64 [[CONV13]])
+// IR-GPU-NESTED-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[CMP14:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP14]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-GPU-NESTED: cond.true:
+// IR-GPU-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[COND_END:%.*]]
+// IR-GPU-NESTED: cond.false:
+// IR-GPU-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[COND_END]]
+// IR-GPU-NESTED: cond.end:
+// IR-GPU-NESTED-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-GPU-NESTED-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU-NESTED: omp.inner.for.cond:
+// IR-GPU-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP19]], 1
+// IR-GPU-NESTED-NEXT: [[CMP15:%.*]] = icmp slt i64 [[TMP18]], [[ADD]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP15]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU-NESTED: omp.inner.for.body:
+// IR-GPU-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP22]], ptr [[N_CASTED_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP24:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 0
+// IR-GPU-NESTED-NEXT: [[TMP25:%.*]] = inttoptr i64 [[TMP20]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[TMP25]], ptr [[TMP24]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP26:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 1
+// IR-GPU-NESTED-NEXT: [[TMP27:%.*]] = inttoptr i64 [[TMP21]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[TMP27]], ptr [[TMP26]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP28:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 2
+// IR-GPU-NESTED-NEXT: [[TMP29:%.*]] = inttoptr i64 [[TMP23]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[TMP29]], ptr [[TMP28]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP30:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 3
+// IR-GPU-NESTED-NEXT: [[TMP31:%.*]] = inttoptr i64 [[TMP0]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[TMP31]], ptr [[TMP30]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP32:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 4
+// IR-GPU-NESTED-NEXT: store ptr [[TMP1]], ptr [[TMP32]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP33:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 5
+// IR-GPU-NESTED-NEXT: [[TMP34:%.*]] = inttoptr i64 [[TMP2]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[TMP34]], ptr [[TMP33]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP35:%.*]] = getelementptr inbounds [7 x ptr], ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 0, i64 6
+// IR-GPU-NESTED-NEXT: store ptr [[TMP3]], ptr [[TMP35]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP36:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP37:%.*]] = load i32, ptr [[TMP36]], align 4
+// IR-GPU-NESTED-NEXT: call void @__kmpc_parallel_51(ptr addrspacecast (ptr addrspace(1) @[[GLOB1]] to ptr), i32 [[TMP37]], i32 1, i32 -1, i32 -1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64_omp_outlined_omp_outlined, ptr null, ptr [[CAPTURED_VARS_ADDRS_ASCAST]], i64 7)
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU-NESTED: omp.inner.for.inc:
+// IR-GPU-NESTED-NEXT: [[TMP38:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP39:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[ADD16:%.*]] = add nsw i64 [[TMP38]], [[TMP39]]
+// IR-GPU-NESTED-NEXT: store i64 [[ADD16]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP40:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP41:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[ADD17:%.*]] = add nsw i64 [[TMP40]], [[TMP41]]
+// IR-GPU-NESTED-NEXT: store i64 [[ADD17]], ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP42:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP43:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[ADD18:%.*]] = add nsw i64 [[TMP42]], [[TMP43]]
+// IR-GPU-NESTED-NEXT: store i64 [[ADD18]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP44:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP45:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[CMP19:%.*]] = icmp sgt i64 [[TMP44]], [[TMP45]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP19]], label [[COND_TRUE20:%.*]], label [[COND_FALSE21:%.*]]
+// IR-GPU-NESTED: cond.true20:
+// IR-GPU-NESTED-NEXT: [[TMP46:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[COND_END22:%.*]]
+// IR-GPU-NESTED: cond.false21:
+// IR-GPU-NESTED-NEXT: [[TMP47:%.*]] = load i64, ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[COND_END22]]
+// IR-GPU-NESTED: cond.end22:
+// IR-GPU-NESTED-NEXT: [[COND23:%.*]] = phi i64 [ [[TMP46]], [[COND_TRUE20]] ], [ [[TMP47]], [[COND_FALSE21]] ]
+// IR-GPU-NESTED-NEXT: store i64 [[COND23]], ptr [[DOTOMP_COMB_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP48:%.*]] = load i64, ptr [[DOTOMP_COMB_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP48]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU-NESTED: omp.inner.for.end:
+// IR-GPU-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU-NESTED: omp.loop.exit:
+// IR-GPU-NESTED-NEXT: [[TMP49:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP50:%.*]] = load i32, ptr [[TMP49]], align 4
+// IR-GPU-NESTED-NEXT: call void @__kmpc_distribute_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB2]] to ptr), i32 [[TMP50]])
+// IR-GPU-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU-NESTED: omp.precond.end:
+// IR-GPU-NESTED-NEXT: ret void
+//
+//
+// IR-GPU-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64_omp_outlined_omp_outlined
+// IR-GPU-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR1]] {
+// IR-GPU-NESTED-NEXT: entry:
+// IR-GPU-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4, addrspace(5)
+// IR-GPU-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTGLOBAL_TID__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTBOUND_TID__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTBOUND_TID__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTPREVIOUS_LB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_LB__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTPREVIOUS_UB__ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTPREVIOUS_UB__ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[N_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[N_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[A_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[A_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[VLA_ADDR2_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[VLA_ADDR2]] to ptr
+// IR-GPU-NESTED-NEXT: [[B_ADDR_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[B_ADDR]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IV_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IV]] to ptr
+// IR-GPU-NESTED-NEXT: [[TMP_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[TMP]] to ptr
+// IR-GPU-NESTED-NEXT: [[TMP3_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[_TMP3]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR__ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_4_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_4]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTCAPTURE_EXPR_5_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTCAPTURE_EXPR_5]] to ptr
+// IR-GPU-NESTED-NEXT: [[I_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I]] to ptr
+// IR-GPU-NESTED-NEXT: [[J_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_LB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_LB]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_UB_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_UB]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_STRIDE_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_STRIDE]] to ptr
+// IR-GPU-NESTED-NEXT: [[DOTOMP_IS_LAST_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[DOTOMP_IS_LAST]] to ptr
+// IR-GPU-NESTED-NEXT: [[I11_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[I11]] to ptr
+// IR-GPU-NESTED-NEXT: [[J12_ASCAST:%.*]] = addrspacecast ptr addrspace(5) [[J12]] to ptr
+// IR-GPU-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-GPU-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-GPU-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-GPU-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-GPU-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-GPU-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-GPU-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-GPU-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-GPU-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[I_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[J_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR__ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-GPU-NESTED: land.lhs.true:
+// IR-GPU-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-GPU-NESTED: omp.precond.then:
+// IR-GPU-NESTED-NEXT: store i64 0, ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-GPU-NESTED-NEXT: call void @__kmpc_for_static_init_8(ptr addrspacecast (ptr addrspace(1) @[[GLOB3:[0-9]+]] to ptr), i32 [[TMP14]], i32 33, ptr [[DOTOMP_IS_LAST_ASCAST]], ptr [[DOTOMP_LB_ASCAST]], ptr [[DOTOMP_UB_ASCAST]], ptr [[DOTOMP_STRIDE_ASCAST]], i64 1, i64 1)
+// IR-GPU-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_LB_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: store i64 [[TMP15]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-GPU-NESTED: omp.inner.for.cond:
+// IR-GPU-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[CMP13:%.*]] = icmp ule i64 [[TMP16]], [[TMP17]]
+// IR-GPU-NESTED-NEXT: br i1 [[CMP13]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-GPU-NESTED: omp.inner.for.body:
+// IR-GPU-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB14:%.*]] = sub nsw i32 [[TMP19]], 0
+// IR-GPU-NESTED-NEXT: [[DIV15:%.*]] = sdiv i32 [[SUB14]], 1
+// IR-GPU-NESTED-NEXT: [[MUL16:%.*]] = mul nsw i32 1, [[DIV15]]
+// IR-GPU-NESTED-NEXT: [[CONV17:%.*]] = sext i32 [[MUL16]] to i64
+// IR-GPU-NESTED-NEXT: [[DIV18:%.*]] = sdiv i64 [[TMP18]], [[CONV17]]
+// IR-GPU-NESTED-NEXT: [[MUL19:%.*]] = mul nsw i64 [[DIV18]], 1
+// IR-GPU-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL19]]
+// IR-GPU-NESTED-NEXT: [[CONV20:%.*]] = trunc i64 [[ADD]] to i32
+// IR-GPU-NESTED-NEXT: store i32 [[CONV20]], ptr [[I11_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB21:%.*]] = sub nsw i32 [[TMP22]], 0
+// IR-GPU-NESTED-NEXT: [[DIV22:%.*]] = sdiv i32 [[SUB21]], 1
+// IR-GPU-NESTED-NEXT: [[MUL23:%.*]] = mul nsw i32 1, [[DIV22]]
+// IR-GPU-NESTED-NEXT: [[CONV24:%.*]] = sext i32 [[MUL23]] to i64
+// IR-GPU-NESTED-NEXT: [[DIV25:%.*]] = sdiv i64 [[TMP21]], [[CONV24]]
+// IR-GPU-NESTED-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[SUB26:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-GPU-NESTED-NEXT: [[DIV27:%.*]] = sdiv i32 [[SUB26]], 1
+// IR-GPU-NESTED-NEXT: [[MUL28:%.*]] = mul nsw i32 1, [[DIV27]]
+// IR-GPU-NESTED-NEXT: [[CONV29:%.*]] = sext i32 [[MUL28]] to i64
+// IR-GPU-NESTED-NEXT: [[MUL30:%.*]] = mul nsw i64 [[DIV25]], [[CONV29]]
+// IR-GPU-NESTED-NEXT: [[SUB31:%.*]] = sub nsw i64 [[TMP20]], [[MUL30]]
+// IR-GPU-NESTED-NEXT: [[MUL32:%.*]] = mul nsw i64 [[SUB31]], 1
+// IR-GPU-NESTED-NEXT: [[ADD33:%.*]] = add nsw i64 0, [[MUL32]]
+// IR-GPU-NESTED-NEXT: [[CONV34:%.*]] = trunc i64 [[ADD33]] to i32
+// IR-GPU-NESTED-NEXT: store i32 [[CONV34]], ptr [[J12_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP24:%.*]] = load i32, ptr [[I11_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP24]] to i64
+// IR-GPU-NESTED-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-GPU-NESTED-NEXT: [[TMP25:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-GPU-NESTED-NEXT: [[TMP26:%.*]] = load i32, ptr [[N_ADDR_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[MUL35:%.*]] = mul nsw i32 [[TMP25]], [[TMP26]]
+// IR-GPU-NESTED-NEXT: [[TMP27:%.*]] = load i32, ptr [[J12_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP27]]) #[[ATTR5:[0-9]+]]
+// IR-GPU-NESTED-NEXT: [[ADD36:%.*]] = add nsw i32 [[MUL35]], [[CALL]]
+// IR-GPU-NESTED-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11_ASCAST]], align 4
+// IR-GPU-NESTED-NEXT: [[IDXPROM37:%.*]] = sext i32 [[TMP28]] to i64
+// IR-GPU-NESTED-NEXT: [[ARRAYIDX38:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM37]]
+// IR-GPU-NESTED-NEXT: store i32 [[ADD36]], ptr [[ARRAYIDX38]], align 4
+// IR-GPU-NESTED-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-GPU-NESTED: omp.body.continue:
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-GPU-NESTED: omp.inner.for.inc:
+// IR-GPU-NESTED-NEXT: [[TMP29:%.*]] = load i64, ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP30:%.*]] = load i64, ptr [[DOTOMP_STRIDE_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[ADD39:%.*]] = add nsw i64 [[TMP29]], [[TMP30]]
+// IR-GPU-NESTED-NEXT: store i64 [[ADD39]], ptr [[DOTOMP_IV_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-GPU-NESTED: omp.inner.for.end:
+// IR-GPU-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-GPU-NESTED: omp.loop.exit:
+// IR-GPU-NESTED-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR_ASCAST]], align 8
+// IR-GPU-NESTED-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4
+// IR-GPU-NESTED-NEXT: call void @__kmpc_for_static_fini(ptr addrspacecast (ptr addrspace(1) @[[GLOB3]] to ptr), i32 [[TMP32]])
+// IR-GPU-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-GPU-NESTED: omp.precond.end:
+// IR-GPU-NESTED-NEXT: ret void
+//
+//
+// IR-NESTED-LABEL: define {{[^@]+}}@main
+// IR-NESTED-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-NESTED-NEXT: entry:
+// IR-NESTED-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NESTED-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-NESTED-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-NESTED-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-NESTED-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-NESTED-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-NESTED-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-NESTED-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-NESTED-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-NESTED-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-NESTED-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-NESTED-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-NESTED-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NESTED-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-NESTED-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-NESTED-NEXT: [[TMP7:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-NESTED-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP7]])
+// IR-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-NESTED-NEXT: ret i32 [[TMP8]]
+//
+//
+// IR-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64
+// IR-NESTED-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-NESTED-NEXT: entry:
+// IR-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-NESTED-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NESTED-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NESTED-NEXT: ret void
+//
+//
+// IR-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined
+// IR-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NESTED-NEXT: entry:
+// IR-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NESTED-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-NESTED: land.lhs.true:
+// IR-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-NESTED: omp.precond.then:
+// IR-NESTED-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NESTED-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-NESTED-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB1:[0-9]+]], i32 [[TMP12]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-NESTED-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-NESTED-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-NESTED: cond.true:
+// IR-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: br label [[COND_END:%.*]]
+// IR-NESTED: cond.false:
+// IR-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: br label [[COND_END]]
+// IR-NESTED: cond.end:
+// IR-NESTED-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-NESTED-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-NESTED: omp.inner.for.cond:
+// IR-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP18]], [[TMP19]]
+// IR-NESTED-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-NESTED: omp.inner.for.body:
+// IR-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-NESTED-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP22]], ptr [[N_CASTED]], align 4
+// IR-NESTED-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-NESTED-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined.omp_outlined, i64 [[TMP20]], i64 [[TMP21]], i64 [[TMP23]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-NESTED: omp.inner.for.inc:
+// IR-NESTED-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP24]], [[TMP25]]
+// IR-NESTED-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-NESTED: omp.inner.for.end:
+// IR-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-NESTED: omp.loop.exit:
+// IR-NESTED-NEXT: [[TMP26:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP27:%.*]] = load i32, ptr [[TMP26]], align 4
+// IR-NESTED-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP27]])
+// IR-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-NESTED: omp.precond.end:
+// IR-NESTED-NEXT: ret void
+//
+//
+// IR-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined.omp_outlined
+// IR-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-NESTED-NEXT: entry:
+// IR-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: store i32 0, ptr [[I]], align 4
+// IR-NESTED-NEXT: store i32 0, ptr [[J]], align 4
+// IR-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-NESTED: land.lhs.true:
+// IR-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-NESTED: omp.precond.then:
+// IR-NESTED-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
+// IR-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NESTED-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-NESTED-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2:[0-9]+]], i32 [[TMP14]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP15]], [[TMP16]]
+// IR-NESTED-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-NESTED: cond.true:
+// IR-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-NESTED-NEXT: br label [[COND_END:%.*]]
+// IR-NESTED: cond.false:
+// IR-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: br label [[COND_END]]
+// IR-NESTED: cond.end:
+// IR-NESTED-NEXT: [[COND:%.*]] = phi i64 [ [[TMP17]], [[COND_TRUE]] ], [ [[TMP18]], [[COND_FALSE]] ]
+// IR-NESTED-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
+// IR-NESTED-NEXT: store i64 [[TMP19]], ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-NESTED: omp.inner.for.cond:
+// IR-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-NESTED-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP20]], [[TMP21]]
+// IR-NESTED-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-NESTED: omp.inner.for.body:
+// IR-NESTED-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-NESTED-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
+// IR-NESTED-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
+// IR-NESTED-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
+// IR-NESTED-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP22]], [[CONV18]]
+// IR-NESTED-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
+// IR-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
+// IR-NESTED-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
+// IR-NESTED-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
+// IR-NESTED-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP26]], 0
+// IR-NESTED-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
+// IR-NESTED-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
+// IR-NESTED-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
+// IR-NESTED-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP25]], [[CONV25]]
+// IR-NESTED-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-NESTED-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP27]], 0
+// IR-NESTED-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
+// IR-NESTED-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
+// IR-NESTED-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
+// IR-NESTED-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
+// IR-NESTED-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP24]], [[MUL31]]
+// IR-NESTED-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
+// IR-NESTED-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
+// IR-NESTED-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
+// IR-NESTED-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
+// IR-NESTED-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11]], align 4
+// IR-NESTED-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP28]] to i64
+// IR-NESTED-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-NESTED-NEXT: [[TMP29:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-NESTED-NEXT: [[TMP30:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-NESTED-NEXT: [[MUL36:%.*]] = mul nsw i32 [[TMP29]], [[TMP30]]
+// IR-NESTED-NEXT: [[TMP31:%.*]] = load i32, ptr [[J12]], align 4
+// IR-NESTED-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP31]])
+// IR-NESTED-NEXT: [[ADD37:%.*]] = add nsw i32 [[MUL36]], [[CALL]]
+// IR-NESTED-NEXT: [[TMP32:%.*]] = load i32, ptr [[I11]], align 4
+// IR-NESTED-NEXT: [[IDXPROM38:%.*]] = sext i32 [[TMP32]] to i64
+// IR-NESTED-NEXT: [[ARRAYIDX39:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM38]]
+// IR-NESTED-NEXT: store i32 [[ADD37]], ptr [[ARRAYIDX39]], align 4
+// IR-NESTED-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-NESTED: omp.body.continue:
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-NESTED: omp.inner.for.inc:
+// IR-NESTED-NEXT: [[TMP33:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: [[ADD40:%.*]] = add nsw i64 [[TMP33]], 1
+// IR-NESTED-NEXT: store i64 [[ADD40]], ptr [[DOTOMP_IV]], align 8
+// IR-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-NESTED: omp.inner.for.end:
+// IR-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-NESTED: omp.loop.exit:
+// IR-NESTED-NEXT: [[TMP34:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NESTED-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP34]], align 4
+// IR-NESTED-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP35]])
+// IR-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-NESTED: omp.precond.end:
+// IR-NESTED-NEXT: ret void
+//
+//
+// IR-PCH-NESTED-LABEL: define {{[^@]+}}@main
+// IR-PCH-NESTED-SAME: () #[[ATTR0:[0-9]+]] {
+// IR-PCH-NESTED-NEXT: entry:
+// IR-PCH-NESTED-NEXT: [[RETVAL:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[SAVED_STACK:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[__VLA_EXPR0:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[__VLA_EXPR1:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP0:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NESTED-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64
+// IR-PCH-NESTED-NEXT: [[TMP2:%.*]] = call ptr @llvm.stacksave.p0()
+// IR-PCH-NESTED-NEXT: store ptr [[TMP2]], ptr [[SAVED_STACK]], align 8
+// IR-PCH-NESTED-NEXT: [[VLA:%.*]] = alloca i32, i64 [[TMP1]], align 16
+// IR-PCH-NESTED-NEXT: store i64 [[TMP1]], ptr [[__VLA_EXPR0]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP3:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NESTED-NEXT: [[TMP4:%.*]] = zext i32 [[TMP3]] to i64
+// IR-PCH-NESTED-NEXT: [[VLA1:%.*]] = alloca i32, i64 [[TMP4]], align 16
+// IR-PCH-NESTED-NEXT: store i64 [[TMP4]], ptr [[__VLA_EXPR1]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr @N, align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP5]], ptr [[N_CASTED]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP6:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NESTED-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64(i64 [[TMP6]], i64 [[TMP1]], ptr [[VLA]], i64 [[TMP4]], ptr [[VLA1]]) #[[ATTR3:[0-9]+]]
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[RETVAL]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP7:%.*]] = load ptr, ptr [[SAVED_STACK]], align 8
+// IR-PCH-NESTED-NEXT: call void @llvm.stackrestore.p0(ptr [[TMP7]])
+// IR-PCH-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[RETVAL]], align 4
+// IR-PCH-NESTED-NEXT: ret i32 [[TMP8]]
+//
+//
+// IR-PCH-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64
+// IR-PCH-NESTED-SAME: (i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2:[0-9]+]] {
+// IR-PCH-NESTED-NEXT: entry:
+// IR-PCH-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP4]], ptr [[N_CASTED]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP5:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NESTED-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined, i64 [[TMP5]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NESTED-NEXT: ret void
+//
+//
+// IR-PCH-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined
+// IR-PCH-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NESTED-NEXT: entry:
+// IR-PCH-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_COMB_UB:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[N_CASTED:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-PCH-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-PCH-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-PCH-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-PCH-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-PCH-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-PCH-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-PCH-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH-NESTED: land.lhs.true:
+// IR-PCH-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-PCH-NESTED: omp.precond.then:
+// IR-PCH-NESTED-NEXT: store i64 0, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
+// IR-PCH-NESTED-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB1:[0-9]+]], i32 [[TMP12]], i32 92, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_COMB_LB]], ptr [[DOTOMP_COMB_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-PCH-NESTED-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP14:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP13]], [[TMP14]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH-NESTED: cond.true:
+// IR-PCH-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: br label [[COND_END:%.*]]
+// IR-PCH-NESTED: cond.false:
+// IR-PCH-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: br label [[COND_END]]
+// IR-PCH-NESTED: cond.end:
+// IR-PCH-NESTED-NEXT: [[COND:%.*]] = phi i64 [ [[TMP15]], [[COND_TRUE]] ], [ [[TMP16]], [[COND_FALSE]] ]
+// IR-PCH-NESTED-NEXT: store i64 [[COND]], ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP17]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH-NESTED: omp.inner.for.cond:
+// IR-PCH-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP18]], [[TMP19]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH-NESTED: omp.inner.for.body:
+// IR-PCH-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP22:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP22]], ptr [[N_CASTED]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP23:%.*]] = load i64, ptr [[N_CASTED]], align 8
+// IR-PCH-NESTED-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined.omp_outlined, i64 [[TMP20]], i64 [[TMP21]], i64 [[TMP23]], i64 [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], ptr [[TMP3]])
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH-NESTED: omp.inner.for.inc:
+// IR-PCH-NESTED-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP24]], [[TMP25]]
+// IR-PCH-NESTED-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH-NESTED: omp.inner.for.end:
+// IR-PCH-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH-NESTED: omp.loop.exit:
+// IR-PCH-NESTED-NEXT: [[TMP26:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP27:%.*]] = load i32, ptr [[TMP26]], align 4
+// IR-PCH-NESTED-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP27]])
+// IR-PCH-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH-NESTED: omp.precond.end:
+// IR-PCH-NESTED-NEXT: ret void
+//
+//
+// IR-PCH-NESTED-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l64.omp_outlined.omp_outlined
+// IR-PCH-NESTED-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], i64 noundef [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[B:%.*]]) #[[ATTR2]] {
+// IR-PCH-NESTED-NEXT: entry:
+// IR-PCH-NESTED-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[B_ADDR:%.*]] = alloca ptr, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[TMP:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[I:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[J:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
+// IR-PCH-NESTED-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[I11:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: [[J12:%.*]] = alloca i32, align 4
+// IR-PCH-NESTED-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: store ptr [[B]], ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP3:%.*]] = load ptr, ptr [[B_ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP4:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP4]], ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP5:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP6]], 0
+// IR-PCH-NESTED-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
+// IR-PCH-NESTED-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
+// IR-PCH-NESTED-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP7]], 0
+// IR-PCH-NESTED-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
+// IR-PCH-NESTED-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
+// IR-PCH-NESTED-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
+// IR-PCH-NESTED-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
+// IR-PCH-NESTED-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[I]], align 4
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[J]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
+// IR-PCH-NESTED-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP8]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
+// IR-PCH-NESTED: land.lhs.true:
+// IR-PCH-NESTED-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP9]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
+// IR-PCH-NESTED: omp.precond.then:
+// IR-PCH-NESTED-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP10:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP10]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
+// IR-PCH-NESTED-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// IR-PCH-NESTED-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2:[0-9]+]], i32 [[TMP14]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
+// IR-PCH-NESTED-NEXT: [[TMP15:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP15]], [[TMP16]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
+// IR-PCH-NESTED: cond.true:
+// IR-PCH-NESTED-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
+// IR-PCH-NESTED-NEXT: br label [[COND_END:%.*]]
+// IR-PCH-NESTED: cond.false:
+// IR-PCH-NESTED-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: br label [[COND_END]]
+// IR-PCH-NESTED: cond.end:
+// IR-PCH-NESTED-NEXT: [[COND:%.*]] = phi i64 [ [[TMP17]], [[COND_TRUE]] ], [ [[TMP18]], [[COND_FALSE]] ]
+// IR-PCH-NESTED-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
+// IR-PCH-NESTED-NEXT: store i64 [[TMP19]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
+// IR-PCH-NESTED: omp.inner.for.cond:
+// IR-PCH-NESTED-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
+// IR-PCH-NESTED-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP20]], [[TMP21]]
+// IR-PCH-NESTED-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
+// IR-PCH-NESTED: omp.inner.for.body:
+// IR-PCH-NESTED-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP23:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP23]], 0
+// IR-PCH-NESTED-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
+// IR-PCH-NESTED-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
+// IR-PCH-NESTED-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
+// IR-PCH-NESTED-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP22]], [[CONV18]]
+// IR-PCH-NESTED-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
+// IR-PCH-NESTED-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
+// IR-PCH-NESTED-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
+// IR-PCH-NESTED-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP26]], 0
+// IR-PCH-NESTED-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
+// IR-PCH-NESTED-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
+// IR-PCH-NESTED-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
+// IR-PCH-NESTED-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP25]], [[CONV25]]
+// IR-PCH-NESTED-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// IR-PCH-NESTED-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP27]], 0
+// IR-PCH-NESTED-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
+// IR-PCH-NESTED-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
+// IR-PCH-NESTED-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
+// IR-PCH-NESTED-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
+// IR-PCH-NESTED-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP24]], [[MUL31]]
+// IR-PCH-NESTED-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
+// IR-PCH-NESTED-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
+// IR-PCH-NESTED-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
+// IR-PCH-NESTED-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP28:%.*]] = load i32, ptr [[I11]], align 4
+// IR-PCH-NESTED-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP28]] to i64
+// IR-PCH-NESTED-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP3]], i64 [[IDXPROM]]
+// IR-PCH-NESTED-NEXT: [[TMP29:%.*]] = load i32, ptr [[ARRAYIDX]], align 4
+// IR-PCH-NESTED-NEXT: [[TMP30:%.*]] = load i32, ptr [[N_ADDR]], align 4
+// IR-PCH-NESTED-NEXT: [[MUL36:%.*]] = mul nsw i32 [[TMP29]], [[TMP30]]
+// IR-PCH-NESTED-NEXT: [[TMP31:%.*]] = load i32, ptr [[J12]], align 4
+// IR-PCH-NESTED-NEXT: [[CALL:%.*]] = call noundef i32 @_Z3fooi(i32 noundef [[TMP31]])
+// IR-PCH-NESTED-NEXT: [[ADD37:%.*]] = add nsw i32 [[MUL36]], [[CALL]]
+// IR-PCH-NESTED-NEXT: [[TMP32:%.*]] = load i32, ptr [[I11]], align 4
+// IR-PCH-NESTED-NEXT: [[IDXPROM38:%.*]] = sext i32 [[TMP32]] to i64
+// IR-PCH-NESTED-NEXT: [[ARRAYIDX39:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[IDXPROM38]]
+// IR-PCH-NESTED-NEXT: store i32 [[ADD37]], ptr [[ARRAYIDX39]], align 4
+// IR-PCH-NESTED-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH-NESTED: omp.body.continue:
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
+// IR-PCH-NESTED: omp.inner.for.inc:
+// IR-PCH-NESTED-NEXT: [[TMP33:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: [[ADD40:%.*]] = add nsw i64 [[TMP33]], 1
+// IR-PCH-NESTED-NEXT: store i64 [[ADD40]], ptr [[DOTOMP_IV]], align 8
+// IR-PCH-NESTED-NEXT: br label [[OMP_INNER_FOR_COND]]
+// IR-PCH-NESTED: omp.inner.for.end:
+// IR-PCH-NESTED-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
+// IR-PCH-NESTED: omp.loop.exit:
+// IR-PCH-NESTED-NEXT: [[TMP34:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NESTED-NEXT: [[TMP35:%.*]] = load i32, ptr [[TMP34]], align 4
+// IR-PCH-NESTED-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP35]])
+// IR-PCH-NESTED-NEXT: br label [[OMP_PRECOND_END]]
+// IR-PCH-NESTED: omp.precond.end:
+// IR-PCH-NESTED-NEXT: ret void
+//
diff --git a/clang/test/OpenMP/target_teams_generic_loop_if_codegen.cpp b/clang/test/OpenMP/target_teams_generic_loop_if_codegen.cpp
index 1edcbfe2d777..e1a6aad65b79 100644
--- a/clang/test/OpenMP/target_teams_generic_loop_if_codegen.cpp
+++ b/clang/test/OpenMP/target_teams_generic_loop_if_codegen.cpp
@@ -332,78 +332,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9gtid_testv_l51.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z9gtid_testv_l51.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z9gtid_testv()
@@ -411,14 +341,14 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -586,78 +516,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l76.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l76.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn4v()
@@ -665,14 +525,14 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -695,7 +555,6 @@ int main() {
// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTBOUND_ZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
@@ -725,82 +584,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void @__kmpc_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTBOUND_ZERO_ADDR]], align 4
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined(ptr [[TMP11]], ptr [[DOTBOUND_ZERO_ADDR]], i64 [[TMP8]], i64 [[TMP10]]) #[[ATTR2]]
-// CHECK1-NEXT: call void @__kmpc_end_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn5v()
@@ -808,14 +593,14 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -847,7 +632,6 @@ int main() {
// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTBOUND_ZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
@@ -878,91 +662,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: [[TMP11:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
-// CHECK1-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP11]] to i1
-// CHECK1-NEXT: br i1 [[TOBOOL]], label [[OMP_IF_THEN:%.*]], label [[OMP_IF_ELSE:%.*]]
-// CHECK1: omp_if.then:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l90.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_IF_END:%.*]]
-// CHECK1: omp_if.else:
-// CHECK1-NEXT: call void @__kmpc_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: [[TMP12:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTBOUND_ZERO_ADDR]], align 4
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l90.omp_outlined.omp_outlined(ptr [[TMP12]], ptr [[DOTBOUND_ZERO_ADDR]], i64 [[TMP8]], i64 [[TMP10]]) #[[ATTR2]]
-// CHECK1-NEXT: call void @__kmpc_end_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: br label [[OMP_IF_END]]
-// CHECK1: omp_if.end:
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP13]], [[TMP14]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l90.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn6v()
@@ -970,14 +671,14 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -987,8 +688,13 @@ int main() {
// CHECK1-NEXT: [[ARG_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[KERNEL_ARGS:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS:%.*]], align 8
-// CHECK1-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[KERNEL_ARGS2:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i8, align 1
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
+// CHECK1-NEXT: [[DOTOFFLOAD_BASEPTRS:%.*]] = alloca [1 x ptr], align 8
+// CHECK1-NEXT: [[DOTOFFLOAD_PTRS:%.*]] = alloca [1 x ptr], align 8
+// CHECK1-NEXT: [[DOTOFFLOAD_MAPPERS:%.*]] = alloca [1 x ptr], align 8
+// CHECK1-NEXT: [[_TMP4:%.*]] = alloca i32, align 4
+// CHECK1-NEXT: [[KERNEL_ARGS5:%.*]] = alloca [[STRUCT___TGT_KERNEL_ARGUMENTS]], align 8
// CHECK1-NEXT: store i32 [[ARG]], ptr [[ARG_ADDR]], align 4
// CHECK1-NEXT: [[TMP0:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 0
// CHECK1-NEXT: store i32 3, ptr [[TMP0]], align 4
@@ -1026,44 +732,61 @@ int main() {
// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l64() #[[ATTR2]]
// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[ARG_ADDR]], align 4
// CHECK1-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[TMP15]], 0
-// CHECK1-NEXT: br i1 [[TOBOOL]], label [[OMP_IF_THEN:%.*]], label [[OMP_IF_ELSE:%.*]]
+// CHECK1-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK1-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR_]], align 1
+// CHECK1-NEXT: [[TMP16:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR_]], align 1
+// CHECK1-NEXT: [[TOBOOL1:%.*]] = trunc i8 [[TMP16]] to i1
+// CHECK1-NEXT: [[FROMBOOL2:%.*]] = zext i1 [[TOBOOL1]] to i8
+// CHECK1-NEXT: store i8 [[FROMBOOL2]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK1-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED]], align 8
+// CHECK1-NEXT: [[TMP18:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR_]], align 1
+// CHECK1-NEXT: [[TOBOOL3:%.*]] = trunc i8 [[TMP18]] to i1
+// CHECK1-NEXT: br i1 [[TOBOOL3]], label [[OMP_IF_THEN:%.*]], label [[OMP_IF_ELSE:%.*]]
// CHECK1: omp_if.then:
-// CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 0
-// CHECK1-NEXT: store i32 3, ptr [[TMP16]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 1
-// CHECK1-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 2
-// CHECK1-NEXT: store ptr null, ptr [[TMP18]], align 8
-// CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 3
-// CHECK1-NEXT: store ptr null, ptr [[TMP19]], align 8
-// CHECK1-NEXT: [[TMP20:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 4
-// CHECK1-NEXT: store ptr null, ptr [[TMP20]], align 8
-// CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 5
+// CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK1-NEXT: store i64 [[TMP17]], ptr [[TMP19]], align 8
+// CHECK1-NEXT: [[TMP20:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0
+// CHECK1-NEXT: store i64 [[TMP17]], ptr [[TMP20]], align 8
+// CHECK1-NEXT: [[TMP21:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_MAPPERS]], i64 0, i64 0
// CHECK1-NEXT: store ptr null, ptr [[TMP21]], align 8
-// CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 6
-// CHECK1-NEXT: store ptr null, ptr [[TMP22]], align 8
-// CHECK1-NEXT: [[TMP23:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 7
-// CHECK1-NEXT: store ptr null, ptr [[TMP23]], align 8
-// CHECK1-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 8
-// CHECK1-NEXT: store i64 100, ptr [[TMP24]], align 8
-// CHECK1-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 9
-// CHECK1-NEXT: store i64 0, ptr [[TMP25]], align 8
-// CHECK1-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 10
-// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP26]], align 4
-// CHECK1-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 11
-// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP27]], align 4
-// CHECK1-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS2]], i32 0, i32 12
-// CHECK1-NEXT: store i32 0, ptr [[TMP28]], align 4
-// CHECK1-NEXT: [[TMP29:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.region_id, ptr [[KERNEL_ARGS2]])
-// CHECK1-NEXT: [[TMP30:%.*]] = icmp ne i32 [[TMP29]], 0
-// CHECK1-NEXT: br i1 [[TMP30]], label [[OMP_OFFLOAD_FAILED3:%.*]], label [[OMP_OFFLOAD_CONT4:%.*]]
-// CHECK1: omp_offload.failed3:
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68() #[[ATTR2]]
-// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT4]]
-// CHECK1: omp_offload.cont4:
+// CHECK1-NEXT: [[TMP22:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_BASEPTRS]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP23:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOFFLOAD_PTRS]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP24:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 0
+// CHECK1-NEXT: store i32 3, ptr [[TMP24]], align 4
+// CHECK1-NEXT: [[TMP25:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 1
+// CHECK1-NEXT: store i32 1, ptr [[TMP25]], align 4
+// CHECK1-NEXT: [[TMP26:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 2
+// CHECK1-NEXT: store ptr [[TMP22]], ptr [[TMP26]], align 8
+// CHECK1-NEXT: [[TMP27:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 3
+// CHECK1-NEXT: store ptr [[TMP23]], ptr [[TMP27]], align 8
+// CHECK1-NEXT: [[TMP28:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 4
+// CHECK1-NEXT: store ptr @.offload_sizes.1, ptr [[TMP28]], align 8
+// CHECK1-NEXT: [[TMP29:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 5
+// CHECK1-NEXT: store ptr @.offload_maptypes.2, ptr [[TMP29]], align 8
+// CHECK1-NEXT: [[TMP30:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 6
+// CHECK1-NEXT: store ptr null, ptr [[TMP30]], align 8
+// CHECK1-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 7
+// CHECK1-NEXT: store ptr null, ptr [[TMP31]], align 8
+// CHECK1-NEXT: [[TMP32:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 8
+// CHECK1-NEXT: store i64 100, ptr [[TMP32]], align 8
+// CHECK1-NEXT: [[TMP33:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 9
+// CHECK1-NEXT: store i64 0, ptr [[TMP33]], align 8
+// CHECK1-NEXT: [[TMP34:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 10
+// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP34]], align 4
+// CHECK1-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 11
+// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP35]], align 4
+// CHECK1-NEXT: [[TMP36:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS5]], i32 0, i32 12
+// CHECK1-NEXT: store i32 0, ptr [[TMP36]], align 4
+// CHECK1-NEXT: [[TMP37:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.region_id, ptr [[KERNEL_ARGS5]])
+// CHECK1-NEXT: [[TMP38:%.*]] = icmp ne i32 [[TMP37]], 0
+// CHECK1-NEXT: br i1 [[TMP38]], label [[OMP_OFFLOAD_FAILED6:%.*]], label [[OMP_OFFLOAD_CONT7:%.*]]
+// CHECK1: omp_offload.failed6:
+// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68(i64 [[TMP17]]) #[[ATTR2]]
+// CHECK1-NEXT: br label [[OMP_OFFLOAD_CONT7]]
+// CHECK1: omp_offload.cont7:
// CHECK1-NEXT: br label [[OMP_IF_END:%.*]]
// CHECK1: omp_if.else:
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68() #[[ATTR2]]
+// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68(i64 [[TMP17]]) #[[ATTR2]]
// CHECK1-NEXT: br label [[OMP_IF_END]]
// CHECK1: omp_if.end:
// CHECK1-NEXT: ret i32 0
@@ -1117,78 +840,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l60.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l60.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn1v()
@@ -1196,14 +849,14 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -1226,7 +879,6 @@ int main() {
// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTBOUND_ZERO_ADDR:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
@@ -1256,82 +908,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void @__kmpc_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTBOUND_ZERO_ADDR]], align 4
-// CHECK1-NEXT: call void @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l64.omp_outlined.omp_outlined(ptr [[TMP11]], ptr [[DOTBOUND_ZERO_ADDR]], i64 [[TMP8]], i64 [[TMP10]]) #[[ATTR2]]
-// CHECK1-NEXT: call void @__kmpc_end_serialized_parallel(ptr @[[GLOB3]], i32 [[TMP1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l64.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn2v()
@@ -1339,29 +917,38 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68
-// CHECK1-SAME: () #[[ATTR1]] {
+// CHECK1-SAME: (i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.omp_outlined)
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__CASTED:%.*]] = alloca i64, align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
+// CHECK1-NEXT: [[TMP0:%.*]] = load i8, ptr [[DOTCAPTURE_EXPR__ADDR]], align 1
+// CHECK1-NEXT: [[TOBOOL:%.*]] = trunc i8 [[TMP0]] to i1
+// CHECK1-NEXT: [[FROMBOOL:%.*]] = zext i1 [[TOBOOL]] to i8
+// CHECK1-NEXT: store i8 [[FROMBOOL]], ptr [[DOTCAPTURE_EXPR__CASTED]], align 1
+// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR__CASTED]], align 8
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.omp_outlined, i64 [[TMP1]])
// CHECK1-NEXT: ret void
//
//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]]) #[[ATTR1]] {
+// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTCAPTURE_EXPR_:%.*]]) #[[ATTR1]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
+// CHECK1-NEXT: [[DOTCAPTURE_EXPR__ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
// CHECK1-NEXT: [[DOTOMP_COMB_LB:%.*]] = alloca i32, align 4
@@ -1371,6 +958,7 @@ int main() {
// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
+// CHECK1-NEXT: store i64 [[DOTCAPTURE_EXPR_]], ptr [[DOTCAPTURE_EXPR__ADDR]], align 8
// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_COMB_LB]], align 4
// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_COMB_UB]], align 4
// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
@@ -1398,78 +986,8 @@ int main() {
// CHECK1-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK1-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiEiT__l68.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 99
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK1-NEXT: call void @_Z3fn3v()
@@ -1477,13 +995,13 @@ int main() {
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], 1
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP8]], 1
+// CHECK1-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK1-NEXT: ret void
//
diff --git a/clang/test/OpenMP/target_teams_generic_loop_private_codegen.cpp b/clang/test/OpenMP/target_teams_generic_loop_private_codegen.cpp
index 99416f76e409..9b3d77f5b0ad 100644
--- a/clang/test/OpenMP/target_teams_generic_loop_private_codegen.cpp
+++ b/clang/test/OpenMP/target_teams_generic_loop_private_codegen.cpp
@@ -326,7 +326,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK1-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -340,7 +340,7 @@ int main() {
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124
// CHECK1-SAME: () #[[ATTR4:[0-9]+]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
// CHECK1-NEXT: ret void
//
//
@@ -403,149 +403,48 @@ int main() {
// CHECK1: omp.inner.for.cond.cleanup:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
-// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i64 2
-// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done3:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK1-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK1-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK1-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK1: arrayctor.loop:
-// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK1-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK1: arrayctor.cont:
-// CHECK1-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK1: omp.inner.for.cond.cleanup:
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK1-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM3:%.*]] = sext i32 [[TMP12]] to i64
-// CHECK1-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM3]]
-// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[VAR]], i64 4, i1 false)
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD5]], ptr [[SIVAR]], align 4
+// CHECK1-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM2:%.*]] = sext i32 [[TMP10]] to i64
+// CHECK1-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM2]]
+// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX3]], ptr align 4 [[VAR]], i64 4, i1 false)
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
+// CHECK1-NEXT: store i32 [[ADD4]], ptr [[SIVAR]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK1-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
+// CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN7]], i64 2
+// CHECK1-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN6]], i64 2
// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done8:
+// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
+// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE7:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK1: arraydestroy.done7:
// CHECK1-NEXT: ret void
//
//
@@ -596,7 +495,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK1-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -645,7 +544,7 @@ int main() {
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80
// CHECK1-SAME: () #[[ATTR4]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
// CHECK1-NEXT: ret void
//
//
@@ -711,149 +610,45 @@ int main() {
// CHECK1: omp.inner.for.cond.cleanup:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
-// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i64 2
-// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done5:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK1-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK1-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK1-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK1: arrayctor.loop:
-// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK1-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK1: arrayctor.cont:
-// CHECK1-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK1-NEXT: store ptr [[VAR]], ptr [[_TMP3]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK1: omp.inner.for.cond.cleanup:
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK1-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM5:%.*]] = sext i32 [[TMP13]] to i64
-// CHECK1-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM5]]
-// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX6]], ptr align 4 [[TMP12]], i64 4, i1 false)
+// CHECK1-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM4:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM4]]
+// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX5]], ptr align 4 [[TMP10]], i64 4, i1 false)
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP14]], 1
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
+// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN8:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN8]], i64 2
+// CHECK1-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN7]], i64 2
// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN8]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE9:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done9:
+// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
+// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK1: arraydestroy.done8:
// CHECK1-NEXT: ret void
//
//
@@ -1059,7 +854,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK3-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -1073,7 +868,7 @@ int main() {
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124
// CHECK3-SAME: () #[[ATTR4:[0-9]+]] {
// CHECK3-NEXT: entry:
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
// CHECK3-NEXT: ret void
//
//
@@ -1136,138 +931,41 @@ int main() {
// CHECK3: omp.inner.for.cond.cleanup:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i32 2
-// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK3-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK3: arraydestroy.done3:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK3-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK3-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK3-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK3-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK3: arrayctor.loop:
-// CHECK3-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK3-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK3-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK3-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK3-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK3: arrayctor.cont:
-// CHECK3-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK3-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK3: omp.inner.for.cond.cleanup:
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK3-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP12]]
+// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK3-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP10]]
// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX2]], ptr align 4 [[VAR]], i32 4, i1 false)
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
+// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
// CHECK3-NEXT: store i32 [[ADD3]], ptr [[SIVAR]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
// CHECK3-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
+// CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAY_BEGIN5:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
+// CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN5]]
@@ -1323,7 +1021,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK3-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -1372,7 +1070,7 @@ int main() {
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80
// CHECK3-SAME: () #[[ATTR4]] {
// CHECK3-NEXT: entry:
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
// CHECK3-NEXT: ret void
//
//
@@ -1438,138 +1136,38 @@ int main() {
// CHECK3: omp.inner.for.cond.cleanup:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i32 2
-// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK3-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK3: arraydestroy.done5:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[_TMP1:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK3-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK3-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK3-NEXT: [[_TMP2:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr undef, ptr [[_TMP1]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK3-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK3: arrayctor.loop:
-// CHECK3-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK3-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK3-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK3-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK3-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK3: arrayctor.cont:
-// CHECK3-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK3-NEXT: store ptr [[VAR]], ptr [[_TMP2]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK3-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK3: omp.inner.for.cond.cleanup:
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK3-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 4
// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK3-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP2]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP13]]
-// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP12]], i32 4, i1 false)
+// CHECK3-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP11]]
+// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP10]], i32 4, i1 false)
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], 1
+// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP12]], 1
// CHECK3-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
+// CHECK3-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
+// CHECK3-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
@@ -1760,7 +1358,7 @@ int main() {
// CHECK5-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104
// CHECK5-SAME: () #[[ATTR4:[0-9]+]] {
// CHECK5-NEXT: entry:
-// CHECK5-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined)
+// CHECK5-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined)
// CHECK5-NEXT: ret void
//
//
@@ -1781,6 +1379,7 @@ int main() {
// CHECK5-NEXT: [[_TMP2:%.*]] = alloca ptr, align 8
// CHECK5-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
// CHECK5-NEXT: [[I:%.*]] = alloca i32, align 4
+// CHECK5-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
// CHECK5-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK5-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK5-NEXT: store ptr undef, ptr [[_TMP1]], align 8
@@ -1812,112 +1411,34 @@ int main() {
// CHECK5-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK5-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK5: omp.inner.for.body:
-// CHECK5-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK5-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK5-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK5-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK5-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK5-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK5: omp.inner.for.inc:
-// CHECK5-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK5-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK5-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK5: omp.inner.for.end:
-// CHECK5-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK5: omp.loop.exit:
-// CHECK5-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK5-NEXT: ret void
-//
-//
-// CHECK5-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined.omp_outlined
-// CHECK5-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK5-NEXT: entry:
-// CHECK5-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK5-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK5-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK5-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK5-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK5-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[G:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[G1:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK5-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK5-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
-// CHECK5-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK5-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK5-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK5-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK5-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK5-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK5-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK5-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK5-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK5-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK5-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK5-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK5-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK5-NEXT: store ptr [[G1]], ptr [[_TMP3]], align 8
-// CHECK5-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK5-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK5-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK5-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK5-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK5: cond.true:
-// CHECK5-NEXT: br label [[COND_END:%.*]]
-// CHECK5: cond.false:
-// CHECK5-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: br label [[COND_END]]
-// CHECK5: cond.end:
-// CHECK5-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK5-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK5-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK5: omp.inner.for.cond:
// CHECK5-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK5-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK5-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK5: omp.inner.for.body:
-// CHECK5-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK5-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK5-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK5-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK5-NEXT: store i32 1, ptr [[G]], align 4
-// CHECK5-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK5-NEXT: store volatile i32 1, ptr [[TMP10]], align 4
+// CHECK5-NEXT: [[TMP8:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK5-NEXT: store volatile i32 1, ptr [[TMP8]], align 4
// CHECK5-NEXT: store i32 2, ptr [[SIVAR]], align 4
-// CHECK5-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
-// CHECK5-NEXT: store ptr [[G]], ptr [[TMP11]], align 8
-// CHECK5-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 1
-// CHECK5-NEXT: [[TMP13:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK5-NEXT: store ptr [[TMP13]], ptr [[TMP12]], align 8
-// CHECK5-NEXT: [[TMP14:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 2
-// CHECK5-NEXT: store ptr [[SIVAR]], ptr [[TMP14]], align 8
+// CHECK5-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK5-NEXT: store ptr [[G]], ptr [[TMP9]], align 8
+// CHECK5-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK5-NEXT: [[TMP11:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK5-NEXT: store ptr [[TMP11]], ptr [[TMP10]], align 8
+// CHECK5-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 2
+// CHECK5-NEXT: store ptr [[SIVAR]], ptr [[TMP12]], align 8
// CHECK5-NEXT: call void @"_ZZZ4mainENK3$_0clEvENKUlvE_clEv"(ptr noundef nonnull align 8 dereferenceable(24) [[REF_TMP]])
// CHECK5-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK5: omp.body.continue:
// CHECK5-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK5: omp.inner.for.inc:
-// CHECK5-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK5-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK5-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK5-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK5-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK5-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK5-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK5: omp.inner.for.end:
// CHECK5-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK5: omp.loop.exit:
-// CHECK5-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK5-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK5-NEXT: ret void
//
//
@@ -1935,7 +1456,7 @@ int main() {
// CHECK13-NEXT: entry:
// CHECK13-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK13-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
-// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
+// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
// CHECK13-NEXT: ret void
//
//
@@ -1998,35 +1519,48 @@ int main() {
// CHECK13: omp.inner.for.cond.cleanup:
// CHECK13-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK13: omp.inner.for.body:
-// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK13-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK13-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
+// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
+// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// CHECK13-NEXT: store i32 [[ADD]], ptr [[I]], align 4
+// CHECK13-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK13-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
+// CHECK13-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
+// CHECK13-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK13-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK13-NEXT: [[IDXPROM2:%.*]] = sext i32 [[TMP10]] to i64
+// CHECK13-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM2]]
+// CHECK13-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX3]], ptr align 4 [[VAR]], i64 4, i1 false)
+// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK13-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK13-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
+// CHECK13-NEXT: store i32 [[ADD4]], ptr [[SIVAR]], align 4
+// CHECK13-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// CHECK13: omp.body.continue:
// CHECK13-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK13: omp.inner.for.inc:
-// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK13-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK13-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK13: omp.inner.for.end:
// CHECK13-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK13: omp.loop.exit:
-// CHECK13-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
-// CHECK13-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
+// CHECK13-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK13-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK13-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
// CHECK13-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5:[0-9]+]]
-// CHECK13-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i64 2
+// CHECK13-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
+// CHECK13-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN6]], i64 2
// CHECK13-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK13: arraydestroy.body:
-// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK13-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK13: arraydestroy.done3:
+// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
+// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE7:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK13: arraydestroy.done7:
// CHECK13-NEXT: ret void
//
//
@@ -2040,120 +1574,6 @@ int main() {
// CHECK13-NEXT: ret void
//
//
-// CHECK13-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined
-// CHECK13-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR0]] {
-// CHECK13-NEXT: entry:
-// CHECK13-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK13-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK13-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK13-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK13-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK13-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK13-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK13-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK13-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK13-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK13-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK13-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK13-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK13-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK13-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK13-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK13: arrayctor.loop:
-// CHECK13-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK13-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) #[[ATTR4]]
-// CHECK13-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK13-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK13-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK13: arrayctor.cont:
-// CHECK13-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR4]]
-// CHECK13-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK13-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK13-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK13-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK13: cond.true:
-// CHECK13-NEXT: br label [[COND_END:%.*]]
-// CHECK13: cond.false:
-// CHECK13-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: br label [[COND_END]]
-// CHECK13: cond.end:
-// CHECK13-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK13-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK13: omp.inner.for.cond:
-// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK13-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK13: omp.inner.for.cond.cleanup:
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK13: omp.inner.for.body:
-// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
-// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK13-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK13-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK13-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
-// CHECK13-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK13-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK13-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK13-NEXT: [[IDXPROM3:%.*]] = sext i32 [[TMP12]] to i64
-// CHECK13-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM3]]
-// CHECK13-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[VAR]], i64 4, i1 false)
-// CHECK13-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK13-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK13-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
-// CHECK13-NEXT: store i32 [[ADD5]], ptr [[SIVAR]], align 4
-// CHECK13-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// CHECK13: omp.body.continue:
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK13: omp.inner.for.inc:
-// CHECK13-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK13-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK13: omp.inner.for.end:
-// CHECK13-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK13: omp.loop.exit:
-// CHECK13-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK13-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
-// CHECK13-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN7]], i64 2
-// CHECK13-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK13: arraydestroy.body:
-// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK13-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
-// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK13: arraydestroy.done8:
-// CHECK13-NEXT: ret void
-//
-//
// CHECK13-LABEL: define {{[^@]+}}@_ZN1SIfED1Ev
// CHECK13-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat {
// CHECK13-NEXT: entry:
@@ -2169,7 +1589,7 @@ int main() {
// CHECK13-NEXT: entry:
// CHECK13-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK13-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
-// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
+// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
// CHECK13-NEXT: ret void
//
//
@@ -2235,17 +1655,27 @@ int main() {
// CHECK13: omp.inner.for.cond.cleanup:
// CHECK13-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK13: omp.inner.for.body:
-// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK13-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK13-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK13-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
+// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
+// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// CHECK13-NEXT: store i32 [[ADD]], ptr [[I]], align 4
+// CHECK13-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK13-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
+// CHECK13-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
+// CHECK13-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK13-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK13-NEXT: [[IDXPROM4:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK13-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM4]]
+// CHECK13-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX5]], ptr align 4 [[TMP10]], i64 4, i1 false)
+// CHECK13-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// CHECK13: omp.body.continue:
// CHECK13-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK13: omp.inner.for.inc:
-// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK13-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK13-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK13-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK13: omp.inner.for.end:
// CHECK13-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
@@ -2254,16 +1684,16 @@ int main() {
// CHECK13-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
// CHECK13-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK13-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i64 2
+// CHECK13-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
+// CHECK13-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN7]], i64 2
// CHECK13-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK13: arraydestroy.body:
// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK13-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK13: arraydestroy.done5:
+// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
+// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK13: arraydestroy.done8:
// CHECK13-NEXT: ret void
//
//
@@ -2277,120 +1707,6 @@ int main() {
// CHECK13-NEXT: ret void
//
//
-// CHECK13-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined
-// CHECK13-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR0]] {
-// CHECK13-NEXT: entry:
-// CHECK13-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK13-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK13-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK13-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK13-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK13-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK13-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK13-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK13-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK13-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK13-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK13-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK13-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK13-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK13-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK13-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK13-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK13-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK13-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK13: arrayctor.loop:
-// CHECK13-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK13-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) #[[ATTR4]]
-// CHECK13-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK13-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK13-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK13: arrayctor.cont:
-// CHECK13-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR4]]
-// CHECK13-NEXT: store ptr [[VAR]], ptr [[_TMP3]], align 8
-// CHECK13-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK13-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK13-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK13-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK13: cond.true:
-// CHECK13-NEXT: br label [[COND_END:%.*]]
-// CHECK13: cond.false:
-// CHECK13-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: br label [[COND_END]]
-// CHECK13: cond.end:
-// CHECK13-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK13-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK13-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK13: omp.inner.for.cond:
-// CHECK13-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK13-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK13-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK13: omp.inner.for.cond.cleanup:
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK13: omp.inner.for.body:
-// CHECK13-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
-// CHECK13-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK13-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK13-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK13-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK13-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
-// CHECK13-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK13-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK13-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK13-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK13-NEXT: [[IDXPROM5:%.*]] = sext i32 [[TMP13]] to i64
-// CHECK13-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM5]]
-// CHECK13-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX6]], ptr align 4 [[TMP12]], i64 4, i1 false)
-// CHECK13-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// CHECK13: omp.body.continue:
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK13: omp.inner.for.inc:
-// CHECK13-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP14]], 1
-// CHECK13-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
-// CHECK13-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK13: omp.inner.for.end:
-// CHECK13-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK13: omp.loop.exit:
-// CHECK13-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK13-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK13-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
-// CHECK13-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAY_BEGIN8:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK13-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN8]], i64 2
-// CHECK13-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK13: arraydestroy.body:
-// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK13-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK13-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK13-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN8]]
-// CHECK13-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE9:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK13: arraydestroy.done9:
-// CHECK13-NEXT: ret void
-//
-//
// CHECK13-LABEL: define {{[^@]+}}@_ZN1SIiED1Ev
// CHECK13-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat {
// CHECK13-NEXT: entry:
@@ -2449,7 +1765,7 @@ int main() {
// CHECK15-NEXT: entry:
// CHECK15-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4
// CHECK15-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4
-// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
+// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined)
// CHECK15-NEXT: ret void
//
//
@@ -2512,148 +1828,41 @@ int main() {
// CHECK15: omp.inner.for.cond.cleanup:
// CHECK15-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK15: omp.inner.for.body:
-// CHECK15-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK15: omp.inner.for.inc:
-// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK15-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK15-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK15: omp.inner.for.end:
-// CHECK15-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK15: omp.loop.exit:
-// CHECK15-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK15-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5:[0-9]+]]
-// CHECK15-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i32 2
-// CHECK15-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK15: arraydestroy.body:
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK15-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK15-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK15-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK15: arraydestroy.done3:
-// CHECK15-NEXT: ret void
-//
-//
-// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIfEC1Ev
-// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1:[0-9]+]] comdat align 2 {
-// CHECK15-NEXT: entry:
-// CHECK15-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
-// CHECK15-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK15-NEXT: call void @_ZN1SIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR4]]
-// CHECK15-NEXT: ret void
-//
-//
-// CHECK15-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l124.omp_outlined.omp_outlined
-// CHECK15-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR0]] {
-// CHECK15-NEXT: entry:
-// CHECK15-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK15-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK15-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK15-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK15-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK15-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK15-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK15-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK15-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK15: arrayctor.loop:
-// CHECK15-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK15-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) #[[ATTR4]]
-// CHECK15-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK15-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK15-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK15: arrayctor.cont:
-// CHECK15-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR4]]
-// CHECK15-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK15-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK15-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK15: cond.true:
-// CHECK15-NEXT: br label [[COND_END:%.*]]
-// CHECK15: cond.false:
-// CHECK15-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: br label [[COND_END]]
-// CHECK15: cond.end:
-// CHECK15-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK15-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK15: omp.inner.for.cond:
// CHECK15-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK15-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK15: omp.inner.for.cond.cleanup:
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK15: omp.inner.for.body:
-// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK15-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK15-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK15-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK15-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK15-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK15-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK15-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK15-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK15-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP12]]
+// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK15-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK15-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK15-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK15-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP10]]
// CHECK15-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX2]], ptr align 4 [[VAR]], i32 4, i1 false)
-// CHECK15-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK15-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK15-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
+// CHECK15-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK15-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK15-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
// CHECK15-NEXT: store i32 [[ADD3]], ptr [[SIVAR]], align 4
// CHECK15-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK15: omp.body.continue:
// CHECK15-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK15: omp.inner.for.inc:
-// CHECK15-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK15-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK15-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
// CHECK15-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK15: omp.inner.for.end:
// CHECK15-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK15: omp.loop.exit:
-// CHECK15-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
-// CHECK15-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
+// CHECK15-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK15-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
+// CHECK15-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5:[0-9]+]]
// CHECK15-NEXT: [[ARRAY_BEGIN5:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
+// CHECK15-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
// CHECK15-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK15: arraydestroy.body:
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK15-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
// CHECK15-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN5]]
@@ -2662,6 +1871,16 @@ int main() {
// CHECK15-NEXT: ret void
//
//
+// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIfEC1Ev
+// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1:[0-9]+]] comdat align 2 {
+// CHECK15-NEXT: entry:
+// CHECK15-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
+// CHECK15-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
+// CHECK15-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
+// CHECK15-NEXT: call void @_ZN1SIfEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR4]]
+// CHECK15-NEXT: ret void
+//
+//
// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIfED1Ev
// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat align 2 {
// CHECK15-NEXT: entry:
@@ -2677,7 +1896,7 @@ int main() {
// CHECK15-NEXT: entry:
// CHECK15-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 4
// CHECK15-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 4
-// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
+// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined)
// CHECK15-NEXT: ret void
//
//
@@ -2743,148 +1962,38 @@ int main() {
// CHECK15: omp.inner.for.cond.cleanup:
// CHECK15-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK15: omp.inner.for.body:
-// CHECK15-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK15-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK15: omp.inner.for.inc:
-// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK15-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK15-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK15: omp.inner.for.end:
-// CHECK15-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK15: omp.loop.exit:
-// CHECK15-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK15-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
-// CHECK15-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i32 2
-// CHECK15-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK15: arraydestroy.body:
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK15-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
-// CHECK15-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK15-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK15: arraydestroy.done5:
-// CHECK15-NEXT: ret void
-//
-//
-// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIiEC1Ev
-// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat align 2 {
-// CHECK15-NEXT: entry:
-// CHECK15-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
-// CHECK15-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK15-NEXT: call void @_ZN1SIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR4]]
-// CHECK15-NEXT: ret void
-//
-//
-// CHECK15-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l80.omp_outlined.omp_outlined
-// CHECK15-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR0]] {
-// CHECK15-NEXT: entry:
-// CHECK15-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[_TMP1:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK15-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK15-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK15-NEXT: [[_TMP2:%.*]] = alloca ptr, align 4
-// CHECK15-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK15-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK15-NEXT: store ptr undef, ptr [[_TMP1]], align 4
-// CHECK15-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK15-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK15-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK15-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK15-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK15-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK15: arrayctor.loop:
-// CHECK15-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK15-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]]) #[[ATTR4]]
-// CHECK15-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK15-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK15-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK15: arrayctor.cont:
-// CHECK15-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR4]]
-// CHECK15-NEXT: store ptr [[VAR]], ptr [[_TMP2]], align 4
-// CHECK15-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK15-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK15-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK15: cond.true:
-// CHECK15-NEXT: br label [[COND_END:%.*]]
-// CHECK15: cond.false:
-// CHECK15-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: br label [[COND_END]]
-// CHECK15: cond.end:
-// CHECK15-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK15-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK15-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK15: omp.inner.for.cond:
// CHECK15-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK15-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK15-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK15: omp.inner.for.cond.cleanup:
-// CHECK15-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK15: omp.inner.for.body:
-// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK15-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK15-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK15-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK15-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK15-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK15-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK15-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK15-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK15-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 4
// CHECK15-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK15-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK15-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK15-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP2]], align 4
-// CHECK15-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK15-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP13]]
-// CHECK15-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP12]], i32 4, i1 false)
+// CHECK15-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP11]]
+// CHECK15-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP10]], i32 4, i1 false)
// CHECK15-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK15: omp.body.continue:
// CHECK15-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK15: omp.inner.for.inc:
-// CHECK15-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK15-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], 1
+// CHECK15-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK15-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP12]], 1
// CHECK15-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK15-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK15: omp.inner.for.end:
// CHECK15-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK15: omp.loop.exit:
-// CHECK15-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK15-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
+// CHECK15-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK15-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// CHECK15-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK15-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR5]]
// CHECK15-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK15-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
+// CHECK15-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
// CHECK15-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK15: arraydestroy.body:
-// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK15-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK15-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR5]]
// CHECK15-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
@@ -2893,6 +2002,16 @@ int main() {
// CHECK15-NEXT: ret void
//
//
+// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIiEC1Ev
+// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat align 2 {
+// CHECK15-NEXT: entry:
+// CHECK15-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
+// CHECK15-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
+// CHECK15-NEXT: [[THIS1:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
+// CHECK15-NEXT: call void @_ZN1SIiEC2Ev(ptr noundef nonnull align 4 dereferenceable(4) [[THIS1]]) #[[ATTR4]]
+// CHECK15-NEXT: ret void
+//
+//
// CHECK15-LABEL: define {{[^@]+}}@_ZN1SIiED1Ev
// CHECK15-SAME: (ptr noundef nonnull align 4 dereferenceable(4) [[THIS:%.*]]) unnamed_addr #[[ATTR1]] comdat align 2 {
// CHECK15-NEXT: entry:
@@ -2951,7 +2070,7 @@ int main() {
// CHECK17-NEXT: entry:
// CHECK17-NEXT: [[DYN_PTR_ADDR:%.*]] = alloca ptr, align 8
// CHECK17-NEXT: store ptr [[DYN_PTR]], ptr [[DYN_PTR_ADDR]], align 8
-// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined)
+// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined)
// CHECK17-NEXT: ret void
//
//
@@ -2972,6 +2091,7 @@ int main() {
// CHECK17-NEXT: [[_TMP2:%.*]] = alloca ptr, align 8
// CHECK17-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
// CHECK17-NEXT: [[I:%.*]] = alloca i32, align 4
+// CHECK17-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 8
// CHECK17-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK17-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK17-NEXT: store ptr undef, ptr [[_TMP1]], align 8
@@ -3003,111 +2123,33 @@ int main() {
// CHECK17-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK17-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK17: omp.inner.for.body:
-// CHECK17-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK17-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK17-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK17-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK17: omp.inner.for.inc:
-// CHECK17-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK17-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK17-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK17: omp.inner.for.end:
-// CHECK17-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK17: omp.loop.exit:
-// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK17-NEXT: ret void
-//
-//
-// CHECK17-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l104.omp_outlined.omp_outlined
-// CHECK17-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR0]] {
-// CHECK17-NEXT: entry:
-// CHECK17-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK17-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK17-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[G:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[G1:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON:%.*]], align 8
-// CHECK17-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK17-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK17-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK17-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK17-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK17-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK17-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK17-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK17-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK17-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK17-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK17-NEXT: store ptr [[G1]], ptr [[_TMP3]], align 8
-// CHECK17-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK17-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK17-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK17-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK17-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK17: cond.true:
-// CHECK17-NEXT: br label [[COND_END:%.*]]
-// CHECK17: cond.false:
-// CHECK17-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: br label [[COND_END]]
-// CHECK17: cond.end:
-// CHECK17-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK17-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK17: omp.inner.for.cond:
// CHECK17-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK17-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK17: omp.inner.for.body:
-// CHECK17-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK17-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK17-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK17-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK17-NEXT: store i32 1, ptr [[G]], align 4
-// CHECK17-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK17-NEXT: store volatile i32 1, ptr [[TMP10]], align 4
+// CHECK17-NEXT: [[TMP8:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK17-NEXT: store volatile i32 1, ptr [[TMP8]], align 4
// CHECK17-NEXT: store i32 2, ptr [[SIVAR]], align 4
-// CHECK17-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 0
-// CHECK17-NEXT: store ptr [[G]], ptr [[TMP11]], align 8
-// CHECK17-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 1
-// CHECK17-NEXT: [[TMP13:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK17-NEXT: store ptr [[TMP13]], ptr [[TMP12]], align 8
-// CHECK17-NEXT: [[TMP14:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 2
-// CHECK17-NEXT: store ptr [[SIVAR]], ptr [[TMP14]], align 8
+// CHECK17-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK17-NEXT: store ptr [[G]], ptr [[TMP9]], align 8
+// CHECK17-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK17-NEXT: [[TMP11:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK17-NEXT: store ptr [[TMP11]], ptr [[TMP10]], align 8
+// CHECK17-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON]], ptr [[REF_TMP]], i32 0, i32 2
+// CHECK17-NEXT: store ptr [[SIVAR]], ptr [[TMP12]], align 8
// CHECK17-NEXT: call void @"_ZZZ4mainENK3$_0clEvENKUlvE_clEv"(ptr noundef nonnull align 8 dereferenceable(24) [[REF_TMP]]) #[[ATTR3:[0-9]+]]
// CHECK17-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK17: omp.body.continue:
// CHECK17-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK17: omp.inner.for.inc:
-// CHECK17-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK17-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK17-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK17-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK17-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK17: omp.inner.for.end:
// CHECK17-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK17: omp.loop.exit:
-// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK17-NEXT: ret void
//
diff --git a/clang/test/OpenMP/teams_generic_loop_codegen-1.cpp b/clang/test/OpenMP/teams_generic_loop_codegen-1.cpp
index d4a98f07fe24..23c5c9db9c70 100644
--- a/clang/test/OpenMP/teams_generic_loop_codegen-1.cpp
+++ b/clang/test/OpenMP/teams_generic_loop_codegen-1.cpp
@@ -278,7 +278,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: store [3 x i32] [[TMP28]], ptr [[TMP40]], align 4
// CHECK1-NEXT: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP41]], align 4
-// CHECK1-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 [[TMP21]], i32 [[TMP22]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 [[TMP21]], i32 [[TMP22]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP43:%.*]] = icmp ne i32 [[TMP42]], 0
// CHECK1-NEXT: br i1 [[TMP43]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -338,7 +338,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP69]], align 4
// CHECK1-NEXT: [[TMP70:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS15]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP70]], align 4
-// CHECK1-NEXT: [[TMP71:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.region_id, ptr [[KERNEL_ARGS15]])
+// CHECK1-NEXT: [[TMP71:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.region_id, ptr [[KERNEL_ARGS15]])
// CHECK1-NEXT: [[TMP72:%.*]] = icmp ne i32 [[TMP71]], 0
// CHECK1-NEXT: br i1 [[TMP72]], label [[OMP_OFFLOAD_FAILED16:%.*]], label [[OMP_OFFLOAD_CONT17:%.*]]
// CHECK1: omp_offload.failed16:
@@ -356,7 +356,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[TH_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[N_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// CHECK1-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2]])
// CHECK1-NEXT: store i64 [[TE]], ptr [[TE_ADDR]], align 8
// CHECK1-NEXT: store i64 [[TH]], ptr [[TH_ADDR]], align 8
// CHECK1-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
@@ -364,8 +364,8 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[TE_ADDR]], align 4
// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TH_ADDR]], align 4
-// CHECK1-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined, ptr [[N_ADDR]], ptr [[TMP1]])
+// CHECK1-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB2]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined, ptr [[N_ADDR]], ptr [[TMP1]])
// CHECK1-NEXT: ret void
//
//
@@ -434,126 +434,28 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP13]], [[TMP14]]
// CHECK1-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP16:%.*]] = zext i32 [[TMP15]] to i64
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined.omp_outlined, i64 [[TMP16]], i64 [[TMP18]], ptr [[TMP0]], ptr [[TMP1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP19]], [[TMP20]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP22]])
-// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK1: omp.precond.end:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[A:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I4:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 8
-// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 8
-// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP3]], 0
-// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK1-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK1-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP4]]
-// CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK1: omp.precond.then:
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP6]] to i32
-// CHECK1-NEXT: [[TMP7:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV3:%.*]] = trunc i64 [[TMP7]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV3]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP9]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
-// CHECK1-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
-// CHECK1-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[I4]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP18]] to i64
+// CHECK1-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
+// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP16]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
// CHECK1-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP19]], 1
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP17]], 1
+// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
+// CHECK1-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
// CHECK1: omp.precond.end:
// CHECK1-NEXT: ret void
@@ -567,7 +469,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: store i64 [[N]], ptr [[N_ADDR]], align 8
// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined, ptr [[N_ADDR]], ptr [[TMP0]])
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined, ptr [[N_ADDR]], ptr [[TMP0]])
// CHECK1-NEXT: ret void
//
//
@@ -636,126 +538,28 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP13]], [[TMP14]]
// CHECK1-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP16:%.*]] = zext i32 [[TMP15]] to i64
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = zext i32 [[TMP17]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined.omp_outlined, i64 [[TMP16]], i64 [[TMP18]], ptr [[TMP0]], ptr [[TMP1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP19]], [[TMP20]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP22]])
-// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK1: omp.precond.end:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[A:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I4:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 8
-// CHECK1-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 8
-// CHECK1-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: store i32 [[TMP2]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP3]], 0
-// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK1-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK1-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP4]]
-// CHECK1-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK1: omp.precond.then:
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP6]] to i32
-// CHECK1-NEXT: [[TMP7:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV3:%.*]] = trunc i64 [[TMP7]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV3]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP9]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
-// CHECK1-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
-// CHECK1-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[I4]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP18]] to i64
+// CHECK1-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
+// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP16]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i64 0, i64 [[IDXPROM]]
// CHECK1-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP19]], 1
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP17]], 1
+// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
+// CHECK1-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
// CHECK1-NEXT: br label [[OMP_PRECOND_END]]
// CHECK1: omp.precond.end:
// CHECK1-NEXT: ret void
@@ -865,7 +669,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: store [3 x i32] [[TMP28]], ptr [[TMP40]], align 4
// CHECK3-NEXT: [[TMP41:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP41]], align 4
-// CHECK3-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 [[TMP21]], i32 [[TMP22]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP42:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 [[TMP21]], i32 [[TMP22]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP43:%.*]] = icmp ne i32 [[TMP42]], 0
// CHECK3-NEXT: br i1 [[TMP43]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -925,7 +729,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP69]], align 4
// CHECK3-NEXT: [[TMP70:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS15]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP70]], align 4
-// CHECK3-NEXT: [[TMP71:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.region_id, ptr [[KERNEL_ARGS15]])
+// CHECK3-NEXT: [[TMP71:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.region_id, ptr [[KERNEL_ARGS15]])
// CHECK3-NEXT: [[TMP72:%.*]] = icmp ne i32 [[TMP71]], 0
// CHECK3-NEXT: br i1 [[TMP72]], label [[OMP_OFFLOAD_FAILED16:%.*]], label [[OMP_OFFLOAD_CONT17:%.*]]
// CHECK3: omp_offload.failed16:
@@ -943,7 +747,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[TH_ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[N_ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// CHECK3-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2]])
// CHECK3-NEXT: store i32 [[TE]], ptr [[TE_ADDR]], align 4
// CHECK3-NEXT: store i32 [[TH]], ptr [[TH_ADDR]], align 4
// CHECK3-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
@@ -951,8 +755,8 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[TE_ADDR]], align 4
// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TH_ADDR]], align 4
-// CHECK3-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined, ptr [[N_ADDR]], ptr [[TMP1]])
+// CHECK3-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB2]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined, ptr [[N_ADDR]], ptr [[TMP1]])
// CHECK3-NEXT: ret void
//
//
@@ -1021,121 +825,27 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP13]], [[TMP14]]
// CHECK3-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined.omp_outlined, i32 [[TMP15]], i32 [[TMP16]], ptr [[TMP0]], ptr [[TMP1]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP17]], [[TMP18]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
-// CHECK3-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK3: omp.precond.end:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l28.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[A:%.*]]) #[[ATTR1]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 4
-// CHECK3-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP3]], 0
-// CHECK3-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK3-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK3-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP4]]
-// CHECK3-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK3: omp.precond.then:
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP9]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
-// CHECK3-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
-// CHECK3-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[I3]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i32 0, i32 [[TMP18]]
+// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i32 0, i32 [[TMP16]]
// CHECK3-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP19]], 1
+// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP17]], 1
// CHECK3-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
+// CHECK3-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
// CHECK3-NEXT: br label [[OMP_PRECOND_END]]
// CHECK3: omp.precond.end:
// CHECK3-NEXT: ret void
@@ -1149,7 +859,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4
// CHECK3-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined, ptr [[N_ADDR]], ptr [[TMP0]])
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined, ptr [[N_ADDR]], ptr [[TMP0]])
// CHECK3-NEXT: ret void
//
//
@@ -1218,121 +928,27 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP13]], [[TMP14]]
// CHECK3-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 4, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined.omp_outlined, i32 [[TMP15]], i32 [[TMP16]], ptr [[TMP0]], ptr [[TMP1]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP17]], [[TMP18]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
-// CHECK3-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK3: omp.precond.end:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z21teams_argument_globali_l34.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[A:%.*]]) #[[ATTR1]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 4
-// CHECK3-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP3]], 0
-// CHECK3-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK3-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK3-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP4]]
-// CHECK3-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK3: omp.precond.then:
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: store i32 [[TMP5]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP9]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP10]], [[TMP11]]
-// CHECK3-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ [[TMP12]], [[COND_TRUE]] ], [ [[TMP13]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP14]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP15]], [[TMP16]]
-// CHECK3-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP17]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP15]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[I3]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i32 0, i32 [[TMP18]]
+// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [100 x i32], ptr [[TMP1]], i32 0, i32 [[TMP16]]
// CHECK3-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP19]], 1
+// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP17]], 1
// CHECK3-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
+// CHECK3-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
// CHECK3-NEXT: br label [[OMP_PRECOND_END]]
// CHECK3: omp.precond.end:
// CHECK3-NEXT: ret void
@@ -1424,7 +1040,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP34]], align 4
// CHECK9-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK9-NEXT: store i32 0, ptr [[TMP35]], align 4
-// CHECK9-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.region_id, ptr [[KERNEL_ARGS]])
+// CHECK9-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.region_id, ptr [[KERNEL_ARGS]])
// CHECK9-NEXT: [[TMP37:%.*]] = icmp ne i32 [[TMP36]], 0
// CHECK9-NEXT: br i1 [[TMP37]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK9: omp_offload.failed:
@@ -1449,7 +1065,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
// CHECK9-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
// CHECK9-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined, ptr [[N_ADDR]], i64 [[TMP0]], ptr [[TMP1]])
+// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined, ptr [[N_ADDR]], i64 [[TMP0]], ptr [[TMP1]])
// CHECK9-NEXT: ret void
//
//
@@ -1521,129 +1137,28 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP14]], [[TMP15]]
// CHECK9-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK9-NEXT: [[TMP17:%.*]] = zext i32 [[TMP16]] to i64
-// CHECK9-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK9-NEXT: [[TMP19:%.*]] = zext i32 [[TMP18]] to i64
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined.omp_outlined, i64 [[TMP17]], i64 [[TMP19]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]])
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP20]], [[TMP21]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK9: omp.inner.for.end:
-// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP23]])
-// CHECK9-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK9: omp.precond.end:
-// CHECK9-NEXT: ret void
-//
-//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined.omp_outlined
-// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I4:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 8
-// CHECK9-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
-// CHECK9-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 8
-// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
-// CHECK9-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK9-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP4]], 0
-// CHECK9-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK9-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK9-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK9-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP5]]
-// CHECK9-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK9: omp.precond.then:
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK9-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP7:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV:%.*]] = trunc i64 [[TMP7]] to i32
-// CHECK9-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV3:%.*]] = trunc i64 [[TMP8]] to i32
-// CHECK9-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[CONV3]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP9]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP10]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK9-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK9-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP11]], [[TMP12]]
-// CHECK9-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK9: cond.true:
-// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK9-NEXT: br label [[COND_END:%.*]]
-// CHECK9: cond.false:
-// CHECK9-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: br label [[COND_END]]
-// CHECK9: cond.end:
-// CHECK9-NEXT: [[COND:%.*]] = phi i32 [ [[TMP13]], [[COND_TRUE]] ], [ [[TMP14]], [[COND_FALSE]] ]
-// CHECK9-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[TMP15]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK9: omp.inner.for.cond:
// CHECK9-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP16]], [[TMP17]]
-// CHECK9-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP18]], 1
+// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP16]], 1
// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
-// CHECK9-NEXT: [[TMP19:%.*]] = load i32, ptr [[I4]], align 4
-// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP19]] to i64
+// CHECK9-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
+// CHECK9-NEXT: [[TMP17:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP17]] to i64
// CHECK9-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 [[IDXPROM]]
// CHECK9-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK9-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK9: omp.body.continue:
// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP20]], 1
-// CHECK9-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP18]], 1
+// CHECK9-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK9: omp.inner.for.end:
// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP22]])
+// CHECK9-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK9-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
+// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
// CHECK9-NEXT: br label [[OMP_PRECOND_END]]
// CHECK9: omp.precond.end:
// CHECK9-NEXT: ret void
@@ -1735,7 +1250,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP34]], align 4
// CHECK11-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK11-NEXT: store i32 0, ptr [[TMP35]], align 4
-// CHECK11-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.region_id, ptr [[KERNEL_ARGS]])
+// CHECK11-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.region_id, ptr [[KERNEL_ARGS]])
// CHECK11-NEXT: [[TMP37:%.*]] = icmp ne i32 [[TMP36]], 0
// CHECK11-NEXT: br i1 [[TMP37]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK11: omp_offload.failed:
@@ -1760,7 +1275,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
// CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
// CHECK11-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined, ptr [[N_ADDR]], i32 [[TMP0]], ptr [[TMP1]])
+// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined, ptr [[N_ADDR]], i32 [[TMP0]], ptr [[TMP1]])
// CHECK11-NEXT: ret void
//
//
@@ -1832,124 +1347,27 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP14]], [[TMP15]]
// CHECK11-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK11: omp.inner.for.body:
-// CHECK11-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK11-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined.omp_outlined, i32 [[TMP16]], i32 [[TMP17]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]])
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK11-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP18]], [[TMP19]]
-// CHECK11-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK11: omp.inner.for.end:
-// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP21]])
-// CHECK11-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK11: omp.precond.end:
-// CHECK11-NEXT: ret void
-//
-//
-// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z15teams_local_argv_l72.omp_outlined.omp_outlined
-// CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK11-NEXT: entry:
-// CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[VLA_ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 4
-// CHECK11-NEXT: store i32 [[VLA]], ptr [[VLA_ADDR]], align 4
-// CHECK11-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 4
-// CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
-// CHECK11-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK11-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP4]], 0
-// CHECK11-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK11-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK11-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK11-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK11-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP5]]
-// CHECK11-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK11: omp.precond.then:
-// CHECK11-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK11-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: store i32 [[TMP8]], ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK11-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK11-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP9]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP10]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK11-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK11-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP11]], [[TMP12]]
-// CHECK11-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK11: cond.true:
-// CHECK11-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK11-NEXT: br label [[COND_END:%.*]]
-// CHECK11: cond.false:
-// CHECK11-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: br label [[COND_END]]
-// CHECK11: cond.end:
-// CHECK11-NEXT: [[COND:%.*]] = phi i32 [ [[TMP13]], [[COND_TRUE]] ], [ [[TMP14]], [[COND_FALSE]] ]
-// CHECK11-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: store i32 [[TMP15]], ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK11: omp.inner.for.cond:
// CHECK11-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP16]], [[TMP17]]
-// CHECK11-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK11: omp.inner.for.body:
-// CHECK11-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP18]], 1
+// CHECK11-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP16]], 1
// CHECK11-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK11-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
-// CHECK11-NEXT: [[TMP19:%.*]] = load i32, ptr [[I3]], align 4
-// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 [[TMP19]]
+// CHECK11-NEXT: [[TMP17:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 [[TMP17]]
// CHECK11-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK11-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK11: omp.body.continue:
// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP20]], 1
+// CHECK11-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK11-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP18]], 1
// CHECK11-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK11: omp.inner.for.end:
// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP22]])
+// CHECK11-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK11-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
+// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
// CHECK11-NEXT: br label [[OMP_PRECOND_END]]
// CHECK11: omp.precond.end:
// CHECK11-NEXT: ret void
@@ -2009,7 +1427,7 @@ int main (int argc, char **argv) {
// CHECK17-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK17-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK17-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK17-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.region_id, ptr [[KERNEL_ARGS]])
+// CHECK17-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.region_id, ptr [[KERNEL_ARGS]])
// CHECK17-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK17-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK17: omp_offload.failed:
@@ -2028,7 +1446,7 @@ int main (int argc, char **argv) {
// CHECK17-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
// CHECK17-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
// CHECK17-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined, ptr [[TMP0]])
+// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined, ptr [[TMP0]])
// CHECK17-NEXT: ret void
//
//
@@ -2076,100 +1494,27 @@ int main (int argc, char **argv) {
// CHECK17-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK17-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK17: omp.inner.for.body:
-// CHECK17-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK17-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK17-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK17-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK17-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[TMP0]])
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK17: omp.inner.for.inc:
-// CHECK17-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK17-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK17-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK17: omp.inner.for.end:
-// CHECK17-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK17: omp.loop.exit:
-// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK17-NEXT: ret void
-//
-//
-// CHECK17-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined.omp_outlined
-// CHECK17-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef [[THIS:%.*]]) #[[ATTR1]] {
-// CHECK17-NEXT: entry:
-// CHECK17-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK17-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK17-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
-// CHECK17-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK17-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK17-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK17-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK17-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK17-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
-// CHECK17-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK17-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 122, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK17-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK17-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK17-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK17-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK17-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK17-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK17-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK17-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK17-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 122
-// CHECK17-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK17: cond.true:
-// CHECK17-NEXT: br label [[COND_END:%.*]]
-// CHECK17: cond.false:
-// CHECK17-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: br label [[COND_END]]
-// CHECK17: cond.end:
-// CHECK17-NEXT: [[COND:%.*]] = phi i32 [ 122, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK17-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK17-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK17: omp.inner.for.cond:
// CHECK17-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK17-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK17-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK17: omp.inner.for.body:
-// CHECK17-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK17-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK17-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK17-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK17-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_SS:%.*]], ptr [[TMP0]], i32 0, i32 0
-// CHECK17-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK17-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK17-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK17-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK17-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x i32], ptr [[A]], i64 0, i64 [[IDXPROM]]
// CHECK17-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK17-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK17: omp.body.continue:
// CHECK17-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK17: omp.inner.for.inc:
-// CHECK17-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK17-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], 1
-// CHECK17-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK17-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK17-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP10]], 1
+// CHECK17-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK17-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK17: omp.inner.for.end:
// CHECK17-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK17: omp.loop.exit:
-// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK17-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK17-NEXT: ret void
//
//
@@ -2227,7 +1572,7 @@ int main (int argc, char **argv) {
// CHECK19-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK19-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK19-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK19-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.region_id, ptr [[KERNEL_ARGS]])
+// CHECK19-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.region_id, ptr [[KERNEL_ARGS]])
// CHECK19-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK19-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK19: omp_offload.failed:
@@ -2246,7 +1591,7 @@ int main (int argc, char **argv) {
// CHECK19-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
// CHECK19-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
// CHECK19-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK19-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined, ptr [[TMP0]])
+// CHECK19-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined, ptr [[TMP0]])
// CHECK19-NEXT: ret void
//
//
@@ -2294,95 +1639,26 @@ int main (int argc, char **argv) {
// CHECK19-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK19-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK19: omp.inner.for.body:
-// CHECK19-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK19-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK19-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[TMP0]])
-// CHECK19-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK19: omp.inner.for.inc:
-// CHECK19-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK19-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK19-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK19: omp.inner.for.end:
-// CHECK19-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK19: omp.loop.exit:
-// CHECK19-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK19-NEXT: ret void
-//
-//
-// CHECK19-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l108.omp_outlined.omp_outlined
-// CHECK19-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef [[THIS:%.*]]) #[[ATTR1]] {
-// CHECK19-NEXT: entry:
-// CHECK19-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK19-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK19-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK19-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK19-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK19-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK19-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK19-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK19-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
-// CHECK19-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK19-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK19-NEXT: store i32 122, ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK19-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK19-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK19-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK19-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK19-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK19-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK19-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK19-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 122
-// CHECK19-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK19: cond.true:
-// CHECK19-NEXT: br label [[COND_END:%.*]]
-// CHECK19: cond.false:
-// CHECK19-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: br label [[COND_END]]
-// CHECK19: cond.end:
-// CHECK19-NEXT: [[COND:%.*]] = phi i32 [ 122, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK19-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK19-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK19: omp.inner.for.cond:
// CHECK19-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK19-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK19-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK19: omp.inner.for.body:
-// CHECK19-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK19-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK19-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK19-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK19-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_SS:%.*]], ptr [[TMP0]], i32 0, i32 0
-// CHECK19-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK19-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x i32], ptr [[A]], i32 0, i32 [[TMP11]]
+// CHECK19-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK19-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x i32], ptr [[A]], i32 0, i32 [[TMP9]]
// CHECK19-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK19-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK19: omp.body.continue:
// CHECK19-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK19: omp.inner.for.inc:
-// CHECK19-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK19-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK19-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK19-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP10]], 1
// CHECK19-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK19-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK19: omp.inner.for.end:
// CHECK19-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK19: omp.loop.exit:
-// CHECK19-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK19-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK19-NEXT: ret void
//
//
@@ -2478,7 +1754,7 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP34]], align 4
// CHECK25-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK25-NEXT: store i32 0, ptr [[TMP35]], align 4
-// CHECK25-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.region_id, ptr [[KERNEL_ARGS]])
+// CHECK25-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.region_id, ptr [[KERNEL_ARGS]])
// CHECK25-NEXT: [[TMP37:%.*]] = icmp ne i32 [[TMP36]], 0
// CHECK25-NEXT: br i1 [[TMP37]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK25: omp_offload.failed:
@@ -2505,7 +1781,7 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
// CHECK25-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
// CHECK25-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined, ptr [[N_ADDR]], i64 [[TMP0]], ptr [[TMP1]])
+// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined, ptr [[N_ADDR]], i64 [[TMP0]], ptr [[TMP1]])
// CHECK25-NEXT: ret void
//
//
@@ -2577,129 +1853,28 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP14]], [[TMP15]]
// CHECK25-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK25: omp.inner.for.body:
-// CHECK25-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK25-NEXT: [[TMP17:%.*]] = zext i32 [[TMP16]] to i64
-// CHECK25-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK25-NEXT: [[TMP19:%.*]] = zext i32 [[TMP18]] to i64
-// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined.omp_outlined, i64 [[TMP17]], i64 [[TMP19]], ptr [[TMP0]], i64 [[TMP1]], ptr [[TMP2]])
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK25: omp.inner.for.inc:
-// CHECK25-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[TMP21:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK25-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP20]], [[TMP21]]
-// CHECK25-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK25: omp.inner.for.end:
-// CHECK25-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK25: omp.loop.exit:
-// CHECK25-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP23]])
-// CHECK25-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK25: omp.precond.end:
-// CHECK25-NEXT: ret void
-//
-//
-// CHECK25-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined.omp_outlined
-// CHECK25-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], i64 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK25-NEXT: entry:
-// CHECK25-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK25-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK25-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
-// CHECK25-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[I4:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK25-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK25-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK25-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 8
-// CHECK25-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
-// CHECK25-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK25-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 8
-// CHECK25-NEXT: [[TMP1:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
-// CHECK25-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK25-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK25-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK25-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK25-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP4]], 0
-// CHECK25-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK25-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK25-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK25-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK25-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK25-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP5]]
-// CHECK25-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK25: omp.precond.then:
-// CHECK25-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK25-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[TMP7:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK25-NEXT: [[CONV:%.*]] = trunc i64 [[TMP7]] to i32
-// CHECK25-NEXT: [[TMP8:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK25-NEXT: [[CONV3:%.*]] = trunc i64 [[TMP8]] to i32
-// CHECK25-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: store i32 [[CONV3]], ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK25-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK25-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP9]], align 4
-// CHECK25-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP10]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK25-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK25-NEXT: [[CMP5:%.*]] = icmp sgt i32 [[TMP11]], [[TMP12]]
-// CHECK25-NEXT: br i1 [[CMP5]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK25: cond.true:
-// CHECK25-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK25-NEXT: br label [[COND_END:%.*]]
-// CHECK25: cond.false:
-// CHECK25-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: br label [[COND_END]]
-// CHECK25: cond.end:
-// CHECK25-NEXT: [[COND:%.*]] = phi i32 [ [[TMP13]], [[COND_TRUE]] ], [ [[TMP14]], [[COND_FALSE]] ]
-// CHECK25-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: store i32 [[TMP15]], ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK25: omp.inner.for.cond:
// CHECK25-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP16]], [[TMP17]]
-// CHECK25-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK25: omp.inner.for.body:
-// CHECK25-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP18]], 1
+// CHECK25-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP16]], 1
// CHECK25-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// CHECK25-NEXT: store i32 [[ADD]], ptr [[I4]], align 4
-// CHECK25-NEXT: [[TMP19:%.*]] = load i32, ptr [[I4]], align 4
-// CHECK25-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP19]] to i64
+// CHECK25-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
+// CHECK25-NEXT: [[TMP17:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK25-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP17]] to i64
// CHECK25-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i64 [[IDXPROM]]
// CHECK25-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK25-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK25: omp.body.continue:
// CHECK25-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK25: omp.inner.for.inc:
-// CHECK25-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP20]], 1
-// CHECK25-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK25-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK25-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP18]], 1
+// CHECK25-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK25: omp.inner.for.end:
// CHECK25-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK25: omp.loop.exit:
-// CHECK25-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP22]])
+// CHECK25-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK25-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
+// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
// CHECK25-NEXT: br label [[OMP_PRECOND_END]]
// CHECK25: omp.precond.end:
// CHECK25-NEXT: ret void
@@ -2778,7 +1953,7 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: store [3 x i32] [[TMP18]], ptr [[TMP30]], align 4
// CHECK25-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK25-NEXT: store i32 0, ptr [[TMP31]], align 4
-// CHECK25-NEXT: [[TMP32:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 [[TMP15]], i32 [[TMP16]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.region_id, ptr [[KERNEL_ARGS]])
+// CHECK25-NEXT: [[TMP32:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 [[TMP15]], i32 [[TMP16]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.region_id, ptr [[KERNEL_ARGS]])
// CHECK25-NEXT: [[TMP33:%.*]] = icmp ne i32 [[TMP32]], 0
// CHECK25-NEXT: br i1 [[TMP33]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK25: omp_offload.failed:
@@ -2794,15 +1969,15 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: [[TE_ADDR:%.*]] = alloca i64, align 8
// CHECK25-NEXT: [[TH_ADDR:%.*]] = alloca i64, align 8
// CHECK25-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// CHECK25-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2]])
// CHECK25-NEXT: store i64 [[TE]], ptr [[TE_ADDR]], align 8
// CHECK25-NEXT: store i64 [[TH]], ptr [[TH_ADDR]], align 8
// CHECK25-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
// CHECK25-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 8
// CHECK25-NEXT: [[TMP2:%.*]] = load i32, ptr [[TE_ADDR]], align 4
// CHECK25-NEXT: [[TMP3:%.*]] = load i32, ptr [[TH_ADDR]], align 4
-// CHECK25-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
-// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined, ptr [[TMP1]])
+// CHECK25-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB2]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
+// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined, ptr [[TMP1]])
// CHECK25-NEXT: ret void
//
//
@@ -2850,99 +2025,26 @@ int main (int argc, char **argv) {
// CHECK25-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK25-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK25: omp.inner.for.body:
-// CHECK25-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK25-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK25-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK25-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK25-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[TMP0]])
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK25: omp.inner.for.inc:
-// CHECK25-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK25-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK25-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK25: omp.inner.for.end:
-// CHECK25-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK25: omp.loop.exit:
-// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK25-NEXT: ret void
-//
-//
-// CHECK25-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined.omp_outlined
-// CHECK25-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[A:%.*]]) #[[ATTR2]] {
-// CHECK25-NEXT: entry:
-// CHECK25-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK25-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK25-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK25-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK25-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK25-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK25-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK25-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK25-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK25-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: store i32 9, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK25-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK25-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK25-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK25-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK25-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK25-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK25-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK25-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK25-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 9
-// CHECK25-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK25: cond.true:
-// CHECK25-NEXT: br label [[COND_END:%.*]]
-// CHECK25: cond.false:
-// CHECK25-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: br label [[COND_END]]
-// CHECK25: cond.end:
-// CHECK25-NEXT: [[COND:%.*]] = phi i32 [ 9, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK25-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK25-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK25: omp.inner.for.cond:
// CHECK25-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK25-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK25-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK25: omp.inner.for.body:
-// CHECK25-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK25-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK25-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK25-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK25-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK25-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK25-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK25-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK25-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], ptr [[TMP0]], i64 0, i64 [[IDXPROM]]
// CHECK25-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK25-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK25: omp.body.continue:
// CHECK25-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK25: omp.inner.for.inc:
-// CHECK25-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK25-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], 1
-// CHECK25-NEXT: store i32 [[ADD3]], ptr [[DOTOMP_IV]], align 4
+// CHECK25-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK25-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP10]], 1
+// CHECK25-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK25-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK25: omp.inner.for.end:
// CHECK25-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK25: omp.loop.exit:
-// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK25-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK25-NEXT: ret void
//
//
@@ -3038,7 +2140,7 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP34]], align 4
// CHECK27-NEXT: [[TMP35:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK27-NEXT: store i32 0, ptr [[TMP35]], align 4
-// CHECK27-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.region_id, ptr [[KERNEL_ARGS]])
+// CHECK27-NEXT: [[TMP36:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.region_id, ptr [[KERNEL_ARGS]])
// CHECK27-NEXT: [[TMP37:%.*]] = icmp ne i32 [[TMP36]], 0
// CHECK27-NEXT: br i1 [[TMP37]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK27: omp_offload.failed:
@@ -3065,7 +2167,7 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
// CHECK27-NEXT: [[TMP0:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
// CHECK27-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined, ptr [[N_ADDR]], i32 [[TMP0]], ptr [[TMP1]])
+// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined, ptr [[N_ADDR]], i32 [[TMP0]], ptr [[TMP1]])
// CHECK27-NEXT: ret void
//
//
@@ -3137,124 +2239,27 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP14]], [[TMP15]]
// CHECK27-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK27: omp.inner.for.body:
-// CHECK27-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK27-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined.omp_outlined, i32 [[TMP16]], i32 [[TMP17]], ptr [[TMP0]], i32 [[TMP1]], ptr [[TMP2]])
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK27: omp.inner.for.inc:
-// CHECK27-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK27-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP18]], [[TMP19]]
-// CHECK27-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK27: omp.inner.for.end:
-// CHECK27-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK27: omp.loop.exit:
-// CHECK27-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP21]])
-// CHECK27-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK27: omp.precond.end:
-// CHECK27-NEXT: ret void
-//
-//
-// CHECK27-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l161.omp_outlined.omp_outlined
-// CHECK27-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], i32 noundef [[VLA:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK27-NEXT: entry:
-// CHECK27-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[VLA_ADDR:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTCAPTURE_EXPR_1:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[I3:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK27-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 4
-// CHECK27-NEXT: store i32 [[VLA]], ptr [[VLA_ADDR]], align 4
-// CHECK27-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK27-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 4
-// CHECK27-NEXT: [[TMP1:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
-// CHECK27-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK27-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK27-NEXT: store i32 [[TMP3]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK27-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK27-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP4]], 0
-// CHECK27-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK27-NEXT: [[SUB2:%.*]] = sub nsw i32 [[DIV]], 1
-// CHECK27-NEXT: store i32 [[SUB2]], ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK27-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK27-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK27-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP5]]
-// CHECK27-NEXT: br i1 [[CMP]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK27: omp.precond.then:
-// CHECK27-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK27-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK27-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: store i32 [[TMP8]], ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK27-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK27-NEXT: [[TMP9:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: [[TMP10:%.*]] = load i32, ptr [[TMP9]], align 4
-// CHECK27-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP10]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK27-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK27-NEXT: [[CMP4:%.*]] = icmp sgt i32 [[TMP11]], [[TMP12]]
-// CHECK27-NEXT: br i1 [[CMP4]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK27: cond.true:
-// CHECK27-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_1]], align 4
-// CHECK27-NEXT: br label [[COND_END:%.*]]
-// CHECK27: cond.false:
-// CHECK27-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: br label [[COND_END]]
-// CHECK27: cond.end:
-// CHECK27-NEXT: [[COND:%.*]] = phi i32 [ [[TMP13]], [[COND_TRUE]] ], [ [[TMP14]], [[COND_FALSE]] ]
-// CHECK27-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: store i32 [[TMP15]], ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK27: omp.inner.for.cond:
// CHECK27-NEXT: [[TMP16:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP16]], [[TMP17]]
-// CHECK27-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK27: omp.inner.for.body:
-// CHECK27-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP18]], 1
+// CHECK27-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP16]], 1
// CHECK27-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK27-NEXT: store i32 [[ADD]], ptr [[I3]], align 4
-// CHECK27-NEXT: [[TMP19:%.*]] = load i32, ptr [[I3]], align 4
-// CHECK27-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 [[TMP19]]
+// CHECK27-NEXT: [[TMP17:%.*]] = load i32, ptr [[I3]], align 4
+// CHECK27-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP2]], i32 [[TMP17]]
// CHECK27-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK27-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK27: omp.body.continue:
// CHECK27-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK27: omp.inner.for.inc:
-// CHECK27-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP20]], 1
+// CHECK27-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK27-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP18]], 1
// CHECK27-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK27: omp.inner.for.end:
// CHECK27-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK27: omp.loop.exit:
-// CHECK27-NEXT: [[TMP21:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4
-// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP22]])
+// CHECK27-NEXT: [[TMP19:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK27-NEXT: [[TMP20:%.*]] = load i32, ptr [[TMP19]], align 4
+// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP20]])
// CHECK27-NEXT: br label [[OMP_PRECOND_END]]
// CHECK27: omp.precond.end:
// CHECK27-NEXT: ret void
@@ -3333,7 +2338,7 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: store [3 x i32] [[TMP18]], ptr [[TMP30]], align 4
// CHECK27-NEXT: [[TMP31:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK27-NEXT: store i32 0, ptr [[TMP31]], align 4
-// CHECK27-NEXT: [[TMP32:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 [[TMP15]], i32 [[TMP16]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.region_id, ptr [[KERNEL_ARGS]])
+// CHECK27-NEXT: [[TMP32:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 [[TMP15]], i32 [[TMP16]], ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.region_id, ptr [[KERNEL_ARGS]])
// CHECK27-NEXT: [[TMP33:%.*]] = icmp ne i32 [[TMP32]], 0
// CHECK27-NEXT: br i1 [[TMP33]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK27: omp_offload.failed:
@@ -3349,15 +2354,15 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: [[TE_ADDR:%.*]] = alloca i32, align 4
// CHECK27-NEXT: [[TH_ADDR:%.*]] = alloca i32, align 4
// CHECK27-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB3]])
+// CHECK27-NEXT: [[TMP0:%.*]] = call i32 @__kmpc_global_thread_num(ptr @[[GLOB2]])
// CHECK27-NEXT: store i32 [[TE]], ptr [[TE_ADDR]], align 4
// CHECK27-NEXT: store i32 [[TH]], ptr [[TH_ADDR]], align 4
// CHECK27-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
// CHECK27-NEXT: [[TMP1:%.*]] = load ptr, ptr [[A_ADDR]], align 4
// CHECK27-NEXT: [[TMP2:%.*]] = load i32, ptr [[TE_ADDR]], align 4
// CHECK27-NEXT: [[TMP3:%.*]] = load i32, ptr [[TH_ADDR]], align 4
-// CHECK27-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB3]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
-// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined, ptr [[TMP1]])
+// CHECK27-NEXT: call void @__kmpc_push_num_teams(ptr @[[GLOB2]], i32 [[TMP0]], i32 [[TMP2]], i32 [[TMP3]])
+// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined, ptr [[TMP1]])
// CHECK27-NEXT: ret void
//
//
@@ -3405,93 +2410,24 @@ int main (int argc, char **argv) {
// CHECK27-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK27-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK27: omp.inner.for.body:
-// CHECK27-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK27-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK27-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[TMP0]])
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK27: omp.inner.for.inc:
-// CHECK27-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK27-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK27-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK27: omp.inner.for.end:
-// CHECK27-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK27: omp.loop.exit:
-// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK27-NEXT: ret void
-//
-//
-// CHECK27-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10EEiT__l150.omp_outlined.omp_outlined
-// CHECK27-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(40) [[A:%.*]]) #[[ATTR2]] {
-// CHECK27-NEXT: entry:
-// CHECK27-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK27-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK27-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK27-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK27-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK27-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: store i32 9, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK27-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK27-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK27-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK27-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK27-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK27-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK27-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 9
-// CHECK27-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK27: cond.true:
-// CHECK27-NEXT: br label [[COND_END:%.*]]
-// CHECK27: cond.false:
-// CHECK27-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: br label [[COND_END]]
-// CHECK27: cond.end:
-// CHECK27-NEXT: [[COND:%.*]] = phi i32 [ 9, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK27-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK27-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK27: omp.inner.for.cond:
// CHECK27-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK27-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK27-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK27: omp.inner.for.body:
-// CHECK27-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK27-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK27-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK27-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK27-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK27-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], ptr [[TMP0]], i32 0, i32 [[TMP11]]
+// CHECK27-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK27-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x i32], ptr [[TMP0]], i32 0, i32 [[TMP9]]
// CHECK27-NEXT: store i32 0, ptr [[ARRAYIDX]], align 4
// CHECK27-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK27: omp.body.continue:
// CHECK27-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK27: omp.inner.for.inc:
-// CHECK27-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK27-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK27-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK27-NEXT: [[ADD2:%.*]] = add nsw i32 [[TMP10]], 1
// CHECK27-NEXT: store i32 [[ADD2]], ptr [[DOTOMP_IV]], align 4
// CHECK27-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK27: omp.inner.for.end:
// CHECK27-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK27: omp.loop.exit:
-// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK27-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK27-NEXT: ret void
//
diff --git a/clang/test/OpenMP/teams_generic_loop_codegen.cpp b/clang/test/OpenMP/teams_generic_loop_codegen.cpp
index 2499fbb6811c..85dcae26970b 100644
--- a/clang/test/OpenMP/teams_generic_loop_codegen.cpp
+++ b/clang/test/OpenMP/teams_generic_loop_codegen.cpp
@@ -29,7 +29,7 @@ int foo() {
// IR-NEXT: [[I:%.*]] = alloca i32, align 4
// IR-NEXT: [[J:%.*]] = alloca i32, align 4
// IR-NEXT: [[SUM:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4:[0-9]+]], i32 2, ptr @_Z3foov.omp_outlined, ptr [[J]], ptr [[SUM]])
+// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 2, ptr @_Z3foov.omp_outlined, ptr [[J]], ptr [[SUM]])
// IR-NEXT: ret i32 0
//
//
@@ -96,277 +96,100 @@ int foo() {
// IR-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
// IR-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// IR: omp.inner.for.body:
-// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// IR-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-NEXT: [[TMP13:%.*]] = zext i32 [[TMP12]] to i64
-// IR-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 4, ptr @_Z3foov.omp_outlined.omp_outlined, i64 [[TMP11]], i64 [[TMP13]], ptr [[J3]], ptr [[SUM1]])
+// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 10
+// IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
+// IR-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-NEXT: store i32 [[ADD]], ptr [[I]], align 4
+// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[DIV6:%.*]] = sdiv i32 [[TMP12]], 10
+// IR-NEXT: [[MUL7:%.*]] = mul nsw i32 [[DIV6]], 10
+// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL7]]
+// IR-NEXT: [[MUL8:%.*]] = mul nsw i32 [[SUB]], 1
+// IR-NEXT: [[ADD9:%.*]] = add nsw i32 0, [[MUL8]]
+// IR-NEXT: store i32 [[ADD9]], ptr [[J3]], align 4
+// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
+// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[I]], align 4
+// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP14]] to i64
+// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM1]], i64 0, i64 [[IDXPROM]]
+// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[J3]], align 4
+// IR-NEXT: [[IDXPROM10:%.*]] = sext i32 [[TMP15]] to i64
+// IR-NEXT: [[ARRAYIDX11:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM10]]
+// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[ARRAYIDX11]], align 4
+// IR-NEXT: [[ADD12:%.*]] = add nsw i32 [[TMP16]], [[TMP13]]
+// IR-NEXT: store i32 [[ADD12]], ptr [[ARRAYIDX11]], align 4
+// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR: omp.body.continue:
// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// IR: omp.inner.for.inc:
-// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
-// IR-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP17]], 1
+// IR-NEXT: store i32 [[ADD13]], ptr [[DOTOMP_IV]], align 4
// IR-NEXT: br label [[OMP_INNER_FOR_COND]]
// IR: omp.inner.for.end:
// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// IR: omp.loop.exit:
-// IR-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP17]])
-// IR-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
-// IR-NEXT: br i1 [[TMP19]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
+// IR-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
+// IR-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
+// IR-NEXT: br i1 [[TMP21]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
// IR: .omp.lastprivate.then:
// IR-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-NEXT: [[TMP20:%.*]] = load i32, ptr [[J3]], align 4
-// IR-NEXT: store i32 [[TMP20]], ptr [[TMP0]], align 4
+// IR-NEXT: [[TMP22:%.*]] = load i32, ptr [[J3]], align 4
+// IR-NEXT: store i32 [[TMP22]], ptr [[TMP0]], align 4
// IR-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
// IR: .omp.lastprivate.done:
-// IR-NEXT: [[TMP21:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-NEXT: store ptr [[SUM1]], ptr [[TMP21]], align 8
-// IR-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// IR-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// IR-NEXT: switch i32 [[TMP24]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// IR-NEXT: [[TMP23:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
+// IR-NEXT: store ptr [[SUM1]], ptr [[TMP23]], align 8
+// IR-NEXT: [[TMP24:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-NEXT: [[TMP25:%.*]] = load i32, ptr [[TMP24]], align 4
+// IR-NEXT: [[TMP26:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2:[0-9]+]], i32 [[TMP25]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: switch i32 [[TMP26]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// IR-NEXT: ]
// IR: .omp.reduction.case1:
-// IR-NEXT: [[TMP25:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP25]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE10:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
+// IR-NEXT: [[TMP27:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
+// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP27]]
+// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE18:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
// IR: omp.arraycpy.body:
// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST6:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT8:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[TMP26:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP26]], [[TMP27]]
-// IR-NEXT: store i32 [[ADD7]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT8]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], i32 1
+// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST14:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT16:%.*]], [[OMP_ARRAYCPY_BODY]] ]
+// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], align 4
+// IR-NEXT: [[TMP29:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
+// IR-NEXT: [[ADD15:%.*]] = add nsw i32 [[TMP28]], [[TMP29]]
+// IR-NEXT: store i32 [[ADD15]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], align 4
+// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT16]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 1
// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE9:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT8]], [[TMP25]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE9]], label [[OMP_ARRAYCPY_DONE10]], label [[OMP_ARRAYCPY_BODY]]
-// IR: omp.arraycpy.done10:
-// IR-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
-// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR: .omp.reduction.case2:
-// IR-NEXT: [[TMP28:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY11:%.*]] = icmp eq ptr [[TMP1]], [[TMP28]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY11]], label [[OMP_ARRAYCPY_DONE18:%.*]], label [[OMP_ARRAYCPY_BODY12:%.*]]
-// IR: omp.arraycpy.body12:
-// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST13:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT16:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST14:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT15:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-NEXT: [[TMP29:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], align 4
-// IR-NEXT: [[TMP30:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 [[TMP29]] monotonic, align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT15]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT16]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP28]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY12]]
+// IR-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT16]], [[TMP27]]
+// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY]]
// IR: omp.arraycpy.done18:
-// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR: .omp.reduction.default:
-// IR-NEXT: ret void
-//
-//
-// IR-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp_outlined
-// IR-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1]] {
-// IR-NEXT: entry:
-// IR-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// IR-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// IR-NEXT: [[J_ADDR:%.*]] = alloca ptr, align 8
-// IR-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8
-// IR-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// IR-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// IR-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// IR-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// IR-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// IR-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// IR-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// IR-NEXT: [[J3:%.*]] = alloca i32, align 4
-// IR-NEXT: [[SUM4:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-NEXT: [[I:%.*]] = alloca i32, align 4
-// IR-NEXT: [[J5:%.*]] = alloca i32, align 4
-// IR-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// IR-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// IR-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-NEXT: store ptr [[J]], ptr [[J_ADDR]], align 8
-// IR-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR]], align 8
-// IR-NEXT: [[TMP0:%.*]] = load ptr, ptr [[J_ADDR]], align 8
-// IR-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SUM_ADDR]], align 8
-// IR-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// IR-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// IR-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-NEXT: [[CONV:%.*]] = trunc i64 [[TMP2]] to i32
-// IR-NEXT: [[TMP3:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP3]] to i32
-// IR-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// IR-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// IR-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// IR-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i32 0, i32 0, i32 0
-// IR-NEXT: [[TMP4:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// IR-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP4]]
-// IR-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// IR: omp.arrayinit.body:
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// IR-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP4]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// IR: omp.arrayinit.done:
-// IR-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4
-// IR-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// IR-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP7]], 99
-// IR-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// IR: cond.true:
-// IR-NEXT: br label [[COND_END:%.*]]
-// IR: cond.false:
-// IR-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-NEXT: br label [[COND_END]]
-// IR: cond.end:
-// IR-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP8]], [[COND_FALSE]] ]
-// IR-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// IR-NEXT: store i32 [[TMP9]], ptr [[DOTOMP_IV]], align 4
-// IR-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// IR: omp.inner.for.cond:
-// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3:![0-9]+]]
-// IR-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP10]], [[TMP11]]
-// IR-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// IR: omp.inner.for.body:
-// IR-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP12]], 10
-// IR-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
-// IR-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// IR-NEXT: store i32 [[ADD]], ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[DIV7:%.*]] = sdiv i32 [[TMP14]], 10
-// IR-NEXT: [[MUL8:%.*]] = mul nsw i32 [[DIV7]], 10
-// IR-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP13]], [[MUL8]]
-// IR-NEXT: [[MUL9:%.*]] = mul nsw i32 [[SUB]], 1
-// IR-NEXT: [[ADD10:%.*]] = add nsw i32 0, [[MUL9]]
-// IR-NEXT: store i32 [[ADD10]], ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[TMP15:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[TMP16:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP16]] to i64
-// IR-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i64 0, i64 [[IDXPROM]]
-// IR-NEXT: [[TMP17:%.*]] = load i32, ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP17]] to i64
-// IR-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM11]]
-// IR-NEXT: [[TMP18:%.*]] = load i32, ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP18]], [[TMP15]]
-// IR-NEXT: store i32 [[ADD13]], ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// IR: omp.body.continue:
-// IR-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// IR: omp.inner.for.inc:
-// IR-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP19]], 1
-// IR-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-NEXT: br label [[OMP_INNER_FOR_COND]], !llvm.loop [[LOOP4:![0-9]+]]
-// IR: omp.inner.for.end:
-// IR-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// IR: omp.loop.exit:
-// IR-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// IR-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
-// IR-NEXT: [[TMP22:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-NEXT: store ptr [[SUM4]], ptr [[TMP22]], align 8
-// IR-NEXT: [[TMP23:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
-// IR-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// IR-NEXT: switch i32 [[TMP25]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// IR-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// IR-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// IR-NEXT: ]
-// IR: .omp.reduction.case1:
-// IR-NEXT: [[TMP26:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP26]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE19:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR: omp.arraycpy.body:
-// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST15:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT17:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-NEXT: [[TMP28:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP27]], [[TMP28]]
-// IR-NEXT: store i32 [[ADD16]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT17]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP26]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
-// IR: omp.arraycpy.done19:
-// IR-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
+// IR-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP25]], ptr @.gomp_critical_user_.reduction.var)
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.case2:
-// IR-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY20:%.*]] = icmp eq ptr [[TMP1]], [[TMP29]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY20]], label [[OMP_ARRAYCPY_DONE27:%.*]], label [[OMP_ARRAYCPY_BODY21:%.*]]
-// IR: omp.arraycpy.body21:
-// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST22:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT25:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST23:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT24:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-NEXT: [[TMP30:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], align 4
-// IR-NEXT: [[TMP31:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 [[TMP30]] monotonic, align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT24]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT25]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE26:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT24]], [[TMP29]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_DONE27]], label [[OMP_ARRAYCPY_BODY21]]
-// IR: omp.arraycpy.done27:
+// IR-NEXT: [[TMP30:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
+// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY19:%.*]] = icmp eq ptr [[TMP1]], [[TMP30]]
+// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY19]], label [[OMP_ARRAYCPY_DONE26:%.*]], label [[OMP_ARRAYCPY_BODY20:%.*]]
+// IR: omp.arraycpy.body20:
+// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST21:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT24:%.*]], [[OMP_ARRAYCPY_BODY20]] ]
+// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST22:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT23:%.*]], [[OMP_ARRAYCPY_BODY20]] ]
+// IR-NEXT: [[TMP31:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST21]], align 4
+// IR-NEXT: [[TMP32:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST22]], i32 [[TMP31]] monotonic, align 4
+// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT23]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST22]], i32 1
+// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT24]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST21]], i32 1
+// IR-NEXT: [[OMP_ARRAYCPY_DONE25:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT23]], [[TMP30]]
+// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE25]], label [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_BODY20]]
+// IR: omp.arraycpy.done26:
// IR-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR: .omp.reduction.default:
-// IR-NEXT: [[TMP32:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-NEXT: [[TMP33:%.*]] = icmp ne i32 [[TMP32]], 0
-// IR-NEXT: br i1 [[TMP33]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// IR: .omp.lastprivate.then:
-// IR-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-NEXT: [[TMP34:%.*]] = load i32, ptr [[J3]], align 4
-// IR-NEXT: store i32 [[TMP34]], ptr [[TMP0]], align 4
-// IR-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// IR: .omp.lastprivate.done:
-// IR-NEXT: ret void
-//
-//
-// IR-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// IR-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
-// IR-NEXT: entry:
-// IR-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// IR-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// IR-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// IR-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// IR-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// IR-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// IR-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// IR-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// IR-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// IR-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// IR-NEXT: [[TMP8:%.*]] = getelementptr i32, ptr [[TMP7]], i64 100
-// IR-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP7]], [[TMP8]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE2:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR: omp.arraycpy.body:
-// IR-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[TMP5]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[TMP7]], [[ENTRY]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-NEXT: [[TMP9:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-NEXT: [[TMP10:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// IR-NEXT: store i32 [[ADD]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP8]]
-// IR-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYCPY_DONE2]], label [[OMP_ARRAYCPY_BODY]]
-// IR: omp.arraycpy.done2:
// IR-NEXT: ret void
//
//
// IR-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp.reduction.reduction_func
-// IR-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
+// IR-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
// IR-NEXT: entry:
// IR-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
// IR-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
@@ -402,7 +225,7 @@ int foo() {
// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
// IR-PCH-NEXT: [[J:%.*]] = alloca i32, align 4
// IR-PCH-NEXT: [[SUM:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4:[0-9]+]], i32 2, ptr @_Z3foov.omp_outlined, ptr [[J]], ptr [[SUM]])
+// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 2, ptr @_Z3foov.omp_outlined, ptr [[J]], ptr [[SUM]])
// IR-PCH-NEXT: ret i32 0
//
//
@@ -469,277 +292,100 @@ int foo() {
// IR-PCH-NEXT: [[CMP5:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
// IR-PCH-NEXT: br i1 [[CMP5]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// IR-PCH: omp.inner.for.body:
-// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// IR-PCH-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// IR-PCH-NEXT: [[TMP13:%.*]] = zext i32 [[TMP12]] to i64
-// IR-PCH-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 4, ptr @_Z3foov.omp_outlined.omp_outlined, i64 [[TMP11]], i64 [[TMP13]], ptr [[J3]], ptr [[SUM1]])
+// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 10
+// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
+// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
+// IR-PCH-NEXT: store i32 [[ADD]], ptr [[I]], align 4
+// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[DIV6:%.*]] = sdiv i32 [[TMP12]], 10
+// IR-PCH-NEXT: [[MUL7:%.*]] = mul nsw i32 [[DIV6]], 10
+// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL7]]
+// IR-PCH-NEXT: [[MUL8:%.*]] = mul nsw i32 [[SUB]], 1
+// IR-PCH-NEXT: [[ADD9:%.*]] = add nsw i32 0, [[MUL8]]
+// IR-PCH-NEXT: store i32 [[ADD9]], ptr [[J3]], align 4
+// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
+// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[I]], align 4
+// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP14]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM1]], i64 0, i64 [[IDXPROM]]
+// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[J3]], align 4
+// IR-PCH-NEXT: [[IDXPROM10:%.*]] = sext i32 [[TMP15]] to i64
+// IR-PCH-NEXT: [[ARRAYIDX11:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM10]]
+// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[ARRAYIDX11]], align 4
+// IR-PCH-NEXT: [[ADD12:%.*]] = add nsw i32 [[TMP16]], [[TMP13]]
+// IR-PCH-NEXT: store i32 [[ADD12]], ptr [[ARRAYIDX11]], align 4
+// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
+// IR-PCH: omp.body.continue:
// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// IR-PCH: omp.inner.for.inc:
-// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
-// IR-PCH-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// IR-PCH-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP17]], 1
+// IR-PCH-NEXT: store i32 [[ADD13]], ptr [[DOTOMP_IV]], align 4
// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]]
// IR-PCH: omp.inner.for.end:
// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// IR-PCH: omp.loop.exit:
-// IR-PCH-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP17]])
-// IR-PCH-NEXT: [[TMP18:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
-// IR-PCH-NEXT: br i1 [[TMP19]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
+// IR-PCH-NEXT: [[TMP18:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[TMP18]], align 4
+// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP19]])
+// IR-PCH-NEXT: [[TMP20:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
+// IR-PCH-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
+// IR-PCH-NEXT: br i1 [[TMP21]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
// IR-PCH: .omp.lastprivate.then:
// IR-PCH-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-PCH-NEXT: [[TMP20:%.*]] = load i32, ptr [[J3]], align 4
-// IR-PCH-NEXT: store i32 [[TMP20]], ptr [[TMP0]], align 4
+// IR-PCH-NEXT: [[TMP22:%.*]] = load i32, ptr [[J3]], align 4
+// IR-PCH-NEXT: store i32 [[TMP22]], ptr [[TMP0]], align 4
// IR-PCH-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
// IR-PCH: .omp.lastprivate.done:
-// IR-PCH-NEXT: [[TMP21:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-PCH-NEXT: store ptr [[SUM1]], ptr [[TMP21]], align 8
-// IR-PCH-NEXT: [[TMP22:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: [[TMP23:%.*]] = load i32, ptr [[TMP22]], align 4
-// IR-PCH-NEXT: [[TMP24:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP23]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-NEXT: switch i32 [[TMP24]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// IR-PCH-NEXT: [[TMP23:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
+// IR-PCH-NEXT: store ptr [[SUM1]], ptr [[TMP23]], align 8
+// IR-PCH-NEXT: [[TMP24:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// IR-PCH-NEXT: [[TMP25:%.*]] = load i32, ptr [[TMP24]], align 4
+// IR-PCH-NEXT: [[TMP26:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2:[0-9]+]], i32 [[TMP25]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: switch i32 [[TMP26]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// IR-PCH-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// IR-PCH-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// IR-PCH-NEXT: ]
// IR-PCH: .omp.reduction.case1:
-// IR-PCH-NEXT: [[TMP25:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP25]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE10:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
+// IR-PCH-NEXT: [[TMP27:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP27]]
+// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE18:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
// IR-PCH: omp.arraycpy.body:
// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST6:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT8:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[TMP26:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-PCH-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP26]], [[TMP27]]
-// IR-PCH-NEXT: store i32 [[ADD7]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT8]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST6]], i32 1
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST14:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT16:%.*]], [[OMP_ARRAYCPY_BODY]] ]
+// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], align 4
+// IR-PCH-NEXT: [[TMP29:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
+// IR-PCH-NEXT: [[ADD15:%.*]] = add nsw i32 [[TMP28]], [[TMP29]]
+// IR-PCH-NEXT: store i32 [[ADD15]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], align 4
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT16]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 1
// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE9:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT8]], [[TMP25]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE9]], label [[OMP_ARRAYCPY_DONE10]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH: omp.arraycpy.done10:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP23]], ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH: .omp.reduction.case2:
-// IR-PCH-NEXT: [[TMP28:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY11:%.*]] = icmp eq ptr [[TMP1]], [[TMP28]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY11]], label [[OMP_ARRAYCPY_DONE18:%.*]], label [[OMP_ARRAYCPY_BODY12:%.*]]
-// IR-PCH: omp.arraycpy.body12:
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST13:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT16:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST14:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT15:%.*]], [[OMP_ARRAYCPY_BODY12]] ]
-// IR-PCH-NEXT: [[TMP29:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], align 4
-// IR-PCH-NEXT: [[TMP30:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 [[TMP29]] monotonic, align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT15]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST14]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT16]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST13]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT15]], [[TMP28]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY12]]
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE17:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT16]], [[TMP27]]
+// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE17]], label [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_BODY]]
// IR-PCH: omp.arraycpy.done18:
-// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// IR-PCH: .omp.reduction.default:
-// IR-PCH-NEXT: ret void
-//
-//
-// IR-PCH-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp_outlined
-// IR-PCH-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[J:%.*]], ptr noundef nonnull align 4 dereferenceable(400) [[SUM:%.*]]) #[[ATTR1]] {
-// IR-PCH-NEXT: entry:
-// IR-PCH-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// IR-PCH-NEXT: [[J_ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: [[SUM_ADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[J3:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[SUM4:%.*]] = alloca [10 x [10 x i32]], align 16
-// IR-PCH-NEXT: [[I:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[J5:%.*]] = alloca i32, align 4
-// IR-PCH-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// IR-PCH-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-PCH-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-PCH-NEXT: store ptr [[J]], ptr [[J_ADDR]], align 8
-// IR-PCH-NEXT: store ptr [[SUM]], ptr [[SUM_ADDR]], align 8
-// IR-PCH-NEXT: [[TMP0:%.*]] = load ptr, ptr [[J_ADDR]], align 8
-// IR-PCH-NEXT: [[TMP1:%.*]] = load ptr, ptr [[SUM_ADDR]], align 8
-// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// IR-PCH-NEXT: store i32 99, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// IR-PCH-NEXT: [[CONV:%.*]] = trunc i64 [[TMP2]] to i32
-// IR-PCH-NEXT: [[TMP3:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// IR-PCH-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP3]] to i32
-// IR-PCH-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// IR-PCH-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// IR-PCH-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// IR-PCH-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i32 0, i32 0, i32 0
-// IR-PCH-NEXT: [[TMP4:%.*]] = getelementptr i32, ptr [[ARRAY_BEGIN]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYINIT_ISEMPTY:%.*]] = icmp eq ptr [[ARRAY_BEGIN]], [[TMP4]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYINIT_ISEMPTY]], label [[OMP_ARRAYINIT_DONE:%.*]], label [[OMP_ARRAYINIT_BODY:%.*]]
-// IR-PCH: omp.arrayinit.body:
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYINIT_BODY]] ]
-// IR-PCH-NEXT: store i32 0, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP4]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYINIT_DONE]], label [[OMP_ARRAYINIT_BODY]]
-// IR-PCH: omp.arrayinit.done:
-// IR-PCH-NEXT: [[TMP5:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP5]], align 4
-// IR-PCH-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP6]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// IR-PCH-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP7]], 99
-// IR-PCH-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// IR-PCH: cond.true:
-// IR-PCH-NEXT: br label [[COND_END:%.*]]
-// IR-PCH: cond.false:
-// IR-PCH-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// IR-PCH-NEXT: br label [[COND_END]]
-// IR-PCH: cond.end:
-// IR-PCH-NEXT: [[COND:%.*]] = phi i32 [ 99, [[COND_TRUE]] ], [ [[TMP8]], [[COND_FALSE]] ]
-// IR-PCH-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// IR-PCH-NEXT: store i32 [[TMP9]], ptr [[DOTOMP_IV]], align 4
-// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// IR-PCH: omp.inner.for.cond:
-// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3:![0-9]+]]
-// IR-PCH-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[CMP6:%.*]] = icmp sle i32 [[TMP10]], [[TMP11]]
-// IR-PCH-NEXT: br i1 [[CMP6]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// IR-PCH: omp.inner.for.body:
-// IR-PCH-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP12]], 10
-// IR-PCH-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
-// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
-// IR-PCH-NEXT: store i32 [[ADD]], ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[DIV7:%.*]] = sdiv i32 [[TMP14]], 10
-// IR-PCH-NEXT: [[MUL8:%.*]] = mul nsw i32 [[DIV7]], 10
-// IR-PCH-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP13]], [[MUL8]]
-// IR-PCH-NEXT: [[MUL9:%.*]] = mul nsw i32 [[SUB]], 1
-// IR-PCH-NEXT: [[ADD10:%.*]] = add nsw i32 0, [[MUL9]]
-// IR-PCH-NEXT: store i32 [[ADD10]], ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[TMP15:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[TMP16:%.*]] = load i32, ptr [[I]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP16]] to i64
-// IR-PCH-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [10 x i32]], ptr [[SUM4]], i64 0, i64 [[IDXPROM]]
-// IR-PCH-NEXT: [[TMP17:%.*]] = load i32, ptr [[J3]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[IDXPROM11:%.*]] = sext i32 [[TMP17]] to i64
-// IR-PCH-NEXT: [[ARRAYIDX12:%.*]] = getelementptr inbounds [10 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM11]]
-// IR-PCH-NEXT: [[TMP18:%.*]] = load i32, ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[ADD13:%.*]] = add nsw i32 [[TMP18]], [[TMP15]]
-// IR-PCH-NEXT: store i32 [[ADD13]], ptr [[ARRAYIDX12]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
-// IR-PCH: omp.body.continue:
-// IR-PCH-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// IR-PCH: omp.inner.for.inc:
-// IR-PCH-NEXT: [[TMP19:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: [[ADD14:%.*]] = add nsw i32 [[TMP19]], 1
-// IR-PCH-NEXT: store i32 [[ADD14]], ptr [[DOTOMP_IV]], align 4, !llvm.access.group [[ACC_GRP3]]
-// IR-PCH-NEXT: br label [[OMP_INNER_FOR_COND]], !llvm.loop [[LOOP4:![0-9]+]]
-// IR-PCH: omp.inner.for.end:
-// IR-PCH-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// IR-PCH: omp.loop.exit:
-// IR-PCH-NEXT: [[TMP20:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: [[TMP21:%.*]] = load i32, ptr [[TMP20]], align 4
-// IR-PCH-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP21]])
-// IR-PCH-NEXT: [[TMP22:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// IR-PCH-NEXT: store ptr [[SUM4]], ptr [[TMP22]], align 8
-// IR-PCH-NEXT: [[TMP23:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// IR-PCH-NEXT: [[TMP24:%.*]] = load i32, ptr [[TMP23]], align 4
-// IR-PCH-NEXT: [[TMP25:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @_Z3foov.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// IR-PCH-NEXT: switch i32 [[TMP25]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// IR-PCH-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// IR-PCH-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// IR-PCH-NEXT: ]
-// IR-PCH: .omp.reduction.case1:
-// IR-PCH-NEXT: [[TMP26:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP1]], [[TMP26]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE19:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH: omp.arraycpy.body:
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST15:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE1]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT17:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[TMP27:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-PCH-NEXT: [[TMP28:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[ADD16:%.*]] = add nsw i32 [[TMP27]], [[TMP28]]
-// IR-PCH-NEXT: store i32 [[ADD16]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT17]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST15]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE18:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT17]], [[TMP26]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE18]], label [[OMP_ARRAYCPY_DONE19]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH: omp.arraycpy.done19:
-// IR-PCH-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP24]], ptr @.gomp_critical_user_.reduction.var)
+// IR-PCH-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP25]], ptr @.gomp_critical_user_.reduction.var)
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.case2:
-// IR-PCH-NEXT: [[TMP29:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY20:%.*]] = icmp eq ptr [[TMP1]], [[TMP29]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY20]], label [[OMP_ARRAYCPY_DONE27:%.*]], label [[OMP_ARRAYCPY_BODY21:%.*]]
-// IR-PCH: omp.arraycpy.body21:
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST22:%.*]] = phi ptr [ [[SUM4]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT25:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST23:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT24:%.*]], [[OMP_ARRAYCPY_BODY21]] ]
-// IR-PCH-NEXT: [[TMP30:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], align 4
-// IR-PCH-NEXT: [[TMP31:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 [[TMP30]] monotonic, align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT24]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST23]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT25]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST22]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE26:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT24]], [[TMP29]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_DONE27]], label [[OMP_ARRAYCPY_BODY21]]
-// IR-PCH: omp.arraycpy.done27:
+// IR-PCH-NEXT: [[TMP30:%.*]] = getelementptr i32, ptr [[TMP1]], i64 100
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY19:%.*]] = icmp eq ptr [[TMP1]], [[TMP30]]
+// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY19]], label [[OMP_ARRAYCPY_DONE26:%.*]], label [[OMP_ARRAYCPY_BODY20:%.*]]
+// IR-PCH: omp.arraycpy.body20:
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST21:%.*]] = phi ptr [ [[SUM1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT24:%.*]], [[OMP_ARRAYCPY_BODY20]] ]
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST22:%.*]] = phi ptr [ [[TMP1]], [[DOTOMP_REDUCTION_CASE2]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT23:%.*]], [[OMP_ARRAYCPY_BODY20]] ]
+// IR-PCH-NEXT: [[TMP31:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST21]], align 4
+// IR-PCH-NEXT: [[TMP32:%.*]] = atomicrmw add ptr [[OMP_ARRAYCPY_DESTELEMENTPAST22]], i32 [[TMP31]] monotonic, align 4
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT23]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST22]], i32 1
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT24]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST21]], i32 1
+// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE25:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT23]], [[TMP30]]
+// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE25]], label [[OMP_ARRAYCPY_DONE26]], label [[OMP_ARRAYCPY_BODY20]]
+// IR-PCH: omp.arraycpy.done26:
// IR-PCH-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// IR-PCH: .omp.reduction.default:
-// IR-PCH-NEXT: [[TMP32:%.*]] = load i32, ptr [[DOTOMP_IS_LAST]], align 4
-// IR-PCH-NEXT: [[TMP33:%.*]] = icmp ne i32 [[TMP32]], 0
-// IR-PCH-NEXT: br i1 [[TMP33]], label [[DOTOMP_LASTPRIVATE_THEN:%.*]], label [[DOTOMP_LASTPRIVATE_DONE:%.*]]
-// IR-PCH: .omp.lastprivate.then:
-// IR-PCH-NEXT: store i32 10, ptr [[J3]], align 4
-// IR-PCH-NEXT: [[TMP34:%.*]] = load i32, ptr [[J3]], align 4
-// IR-PCH-NEXT: store i32 [[TMP34]], ptr [[TMP0]], align 4
-// IR-PCH-NEXT: br label [[DOTOMP_LASTPRIVATE_DONE]]
-// IR-PCH: .omp.lastprivate.done:
-// IR-PCH-NEXT: ret void
-//
-//
-// IR-PCH-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// IR-PCH-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
-// IR-PCH-NEXT: entry:
-// IR-PCH-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// IR-PCH-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// IR-PCH-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// IR-PCH-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// IR-PCH-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// IR-PCH-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// IR-PCH-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// IR-PCH-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// IR-PCH-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// IR-PCH-NEXT: [[TMP8:%.*]] = getelementptr i32, ptr [[TMP7]], i64 100
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_ISEMPTY:%.*]] = icmp eq ptr [[TMP7]], [[TMP8]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_ISEMPTY]], label [[OMP_ARRAYCPY_DONE2:%.*]], label [[OMP_ARRAYCPY_BODY:%.*]]
-// IR-PCH: omp.arraycpy.body:
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRCELEMENTPAST:%.*]] = phi ptr [ [[TMP5]], [[ENTRY:%.*]] ], [ [[OMP_ARRAYCPY_SRC_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DESTELEMENTPAST:%.*]] = phi ptr [ [[TMP7]], [[ENTRY]] ], [ [[OMP_ARRAYCPY_DEST_ELEMENT:%.*]], [[OMP_ARRAYCPY_BODY]] ]
-// IR-PCH-NEXT: [[TMP9:%.*]] = load i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[TMP10:%.*]] = load i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// IR-PCH-NEXT: store i32 [[ADD]], ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], align 4
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DEST_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_DESTELEMENTPAST]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_SRC_ELEMENT]] = getelementptr i32, ptr [[OMP_ARRAYCPY_SRCELEMENTPAST]], i32 1
-// IR-PCH-NEXT: [[OMP_ARRAYCPY_DONE:%.*]] = icmp eq ptr [[OMP_ARRAYCPY_DEST_ELEMENT]], [[TMP8]]
-// IR-PCH-NEXT: br i1 [[OMP_ARRAYCPY_DONE]], label [[OMP_ARRAYCPY_DONE2]], label [[OMP_ARRAYCPY_BODY]]
-// IR-PCH: omp.arraycpy.done2:
// IR-PCH-NEXT: ret void
//
//
// IR-PCH-LABEL: define {{[^@]+}}@_Z3foov.omp_outlined.omp.reduction.reduction_func
-// IR-PCH-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
+// IR-PCH-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
// IR-PCH-NEXT: entry:
// IR-PCH-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
// IR-PCH-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
diff --git a/clang/test/OpenMP/teams_generic_loop_collapse_codegen.cpp b/clang/test/OpenMP/teams_generic_loop_collapse_codegen.cpp
index c0c04986f147..901b6552a22b 100644
--- a/clang/test/OpenMP/teams_generic_loop_collapse_codegen.cpp
+++ b/clang/test/OpenMP/teams_generic_loop_collapse_codegen.cpp
@@ -157,7 +157,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK1-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK1-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK1-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -177,7 +177,7 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined, ptr [[TMP0]])
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined, ptr [[TMP0]])
// CHECK1-NEXT: ret void
//
//
@@ -227,114 +227,39 @@ int main (int argc, char **argv) {
// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[TMP0]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef [[THIS:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 56087, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 56087
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 56087, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK1-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 456
+// CHECK1-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP8]], 456
// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[DIV4:%.*]] = sdiv i32 [[TMP12]], 456
-// CHECK1-NEXT: [[MUL5:%.*]] = mul nsw i32 [[DIV4]], 456
-// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL5]]
-// CHECK1-NEXT: [[MUL6:%.*]] = mul nsw i32 [[SUB]], 1
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 0, [[MUL6]]
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[J]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP10]], 456
+// CHECK1-NEXT: [[MUL4:%.*]] = mul nsw i32 [[DIV3]], 456
+// CHECK1-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP9]], [[MUL4]]
+// CHECK1-NEXT: [[MUL5:%.*]] = mul nsw i32 [[SUB]], 1
+// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL5]]
+// CHECK1-NEXT: store i32 [[ADD6]], ptr [[J]], align 4
// CHECK1-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_SS:%.*]], ptr [[TMP0]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP13]] to i64
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x [456 x i32]], ptr [[A]], i64 0, i64 [[IDXPROM]]
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[J]], align 4
-// CHECK1-NEXT: [[IDXPROM8:%.*]] = sext i32 [[TMP14]] to i64
-// CHECK1-NEXT: [[ARRAYIDX9:%.*]] = getelementptr inbounds [456 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM8]]
-// CHECK1-NEXT: store i32 0, ptr [[ARRAYIDX9]], align 4
+// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[J]], align 4
+// CHECK1-NEXT: [[IDXPROM7:%.*]] = sext i32 [[TMP12]] to i64
+// CHECK1-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [456 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM7]]
+// CHECK1-NEXT: store i32 0, ptr [[ARRAYIDX8]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK1-NEXT: store i32 [[ADD10]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK1-NEXT: store i32 [[ADD9]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK1-NEXT: ret void
//
//
@@ -393,7 +318,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK3-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK3-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK3-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -413,7 +338,7 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
// CHECK3-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined, ptr [[TMP0]])
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined, ptr [[TMP0]])
// CHECK3-NEXT: ret void
//
//
@@ -463,108 +388,37 @@ int main (int argc, char **argv) {
// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[TMP0]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__ZN2SSIiLi123ELx456EE3fooEv_l28.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef [[THIS:%.*]]) #[[ATTR1]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[THIS_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[THIS]], ptr [[THIS_ADDR]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[THIS_ADDR]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 56087, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 56087
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 56087, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 456
+// CHECK3-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP8]], 456
// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP12]], 456
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP10]], 456
// CHECK3-NEXT: [[MUL4:%.*]] = mul nsw i32 [[DIV3]], 456
-// CHECK3-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL4]]
+// CHECK3-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP9]], [[MUL4]]
// CHECK3-NEXT: [[MUL5:%.*]] = mul nsw i32 [[SUB]], 1
// CHECK3-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL5]]
// CHECK3-NEXT: store i32 [[ADD6]], ptr [[J]], align 4
// CHECK3-NEXT: [[A:%.*]] = getelementptr inbounds [[STRUCT_SS:%.*]], ptr [[TMP0]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x [456 x i32]], ptr [[A]], i32 0, i32 [[TMP13]]
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[J]], align 4
-// CHECK3-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds [456 x i32], ptr [[ARRAYIDX]], i32 0, i32 [[TMP14]]
+// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [123 x [456 x i32]], ptr [[A]], i32 0, i32 [[TMP11]]
+// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[J]], align 4
+// CHECK3-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds [456 x i32], ptr [[ARRAYIDX]], i32 0, i32 [[TMP12]]
// CHECK3-NEXT: store i32 0, ptr [[ARRAYIDX7]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP13]], 1
// CHECK3-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK3-NEXT: ret void
//
//
@@ -693,7 +547,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP47]], align 4
// CHECK9-NEXT: [[TMP48:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK9-NEXT: store i32 0, ptr [[TMP48]], align 4
-// CHECK9-NEXT: [[TMP49:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.region_id, ptr [[KERNEL_ARGS]])
+// CHECK9-NEXT: [[TMP49:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.region_id, ptr [[KERNEL_ARGS]])
// CHECK9-NEXT: [[TMP50:%.*]] = icmp ne i32 [[TMP49]], 0
// CHECK9-NEXT: br i1 [[TMP50]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK9: omp_offload.failed:
@@ -725,7 +579,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: [[TMP0:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
// CHECK9-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined, ptr [[N_ADDR]], ptr [[M_ADDR]], i64 [[TMP0]], i64 [[TMP1]], ptr [[TMP2]])
+// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined, ptr [[N_ADDR]], ptr [[M_ADDR]], i64 [[TMP0]], i64 [[TMP1]], ptr [[TMP2]])
// CHECK9-NEXT: ret void
//
//
@@ -820,178 +674,58 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP19]], [[TMP20]]
// CHECK9-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
-// CHECK9-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined, i64 [[TMP21]], i64 [[TMP22]], ptr [[TMP0]], ptr [[TMP1]], i64 [[TMP2]], i64 [[TMP3]], ptr [[TMP4]])
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP23:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP23]], [[TMP24]]
-// CHECK9-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK9: omp.inner.for.end:
-// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: [[TMP25:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP26:%.*]] = load i32, ptr [[TMP25]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP26]])
-// CHECK9-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK9: omp.precond.end:
-// CHECK9-NEXT: ret void
-//
-//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined
-// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[M:%.*]], i64 noundef [[VLA:%.*]], i64 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[VLA_ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[VLA_ADDR2:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I11:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[J12:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 8
-// CHECK9-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 8
-// CHECK9-NEXT: store i64 [[VLA]], ptr [[VLA_ADDR]], align 8
-// CHECK9-NEXT: store i64 [[VLA1]], ptr [[VLA_ADDR2]], align 8
-// CHECK9-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 8
-// CHECK9-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 8
-// CHECK9-NEXT: [[TMP2:%.*]] = load i64, ptr [[VLA_ADDR]], align 8
-// CHECK9-NEXT: [[TMP3:%.*]] = load i64, ptr [[VLA_ADDR2]], align 8
-// CHECK9-NEXT: [[TMP4:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK9-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP1]], align 4
-// CHECK9-NEXT: store i32 [[TMP6]], ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP7]], 0
-// CHECK9-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK9-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
-// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP8]], 0
-// CHECK9-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
-// CHECK9-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
-// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
-// CHECK9-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
-// CHECK9-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK9-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[J]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK9-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP9]]
-// CHECK9-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK9: land.lhs.true:
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP10]]
-// CHECK9-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
-// CHECK9: omp.precond.then:
-// CHECK9-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
-// CHECK9-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK9-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: [[TMP12:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: [[TMP13:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[TMP12]], ptr [[DOTOMP_LB]], align 8
-// CHECK9-NEXT: store i64 [[TMP13]], ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK9-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2:[0-9]+]], i32 [[TMP15]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
-// CHECK9-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK9-NEXT: [[CMP13:%.*]] = icmp sgt i64 [[TMP16]], [[TMP17]]
-// CHECK9-NEXT: br i1 [[CMP13]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK9: cond.true:
-// CHECK9-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK9-NEXT: br label [[COND_END:%.*]]
-// CHECK9: cond.false:
-// CHECK9-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: br label [[COND_END]]
-// CHECK9: cond.end:
-// CHECK9-NEXT: [[COND:%.*]] = phi i64 [ [[TMP18]], [[COND_TRUE]] ], [ [[TMP19]], [[COND_FALSE]] ]
-// CHECK9-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
-// CHECK9-NEXT: store i64 [[TMP20]], ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK9: omp.inner.for.cond:
// CHECK9-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK9-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP21]], [[TMP22]]
-// CHECK9-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP23:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[TMP24:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP24]], 0
+// CHECK9-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK9-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP22]], 0
// CHECK9-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
// CHECK9-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
// CHECK9-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
-// CHECK9-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP23]], [[CONV18]]
+// CHECK9-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP21]], [[CONV18]]
// CHECK9-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
// CHECK9-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
// CHECK9-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
// CHECK9-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
-// CHECK9-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[TMP26:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP27]], 0
+// CHECK9-NEXT: [[TMP23:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// CHECK9-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// CHECK9-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK9-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP25]], 0
// CHECK9-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
// CHECK9-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
// CHECK9-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
-// CHECK9-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP26]], [[CONV25]]
-// CHECK9-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK9-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP28]], 0
+// CHECK9-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP24]], [[CONV25]]
+// CHECK9-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK9-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP26]], 0
// CHECK9-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
// CHECK9-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
// CHECK9-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
// CHECK9-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
-// CHECK9-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP25]], [[MUL31]]
+// CHECK9-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP23]], [[MUL31]]
// CHECK9-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
// CHECK9-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
// CHECK9-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
// CHECK9-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
-// CHECK9-NEXT: [[TMP29:%.*]] = load i32, ptr [[I11]], align 4
-// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP29]] to i64
-// CHECK9-NEXT: [[TMP30:%.*]] = mul nsw i64 [[IDXPROM]], [[TMP3]]
-// CHECK9-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i64 [[TMP30]]
-// CHECK9-NEXT: [[TMP31:%.*]] = load i32, ptr [[J12]], align 4
-// CHECK9-NEXT: [[IDXPROM36:%.*]] = sext i32 [[TMP31]] to i64
+// CHECK9-NEXT: [[TMP27:%.*]] = load i32, ptr [[I11]], align 4
+// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP27]] to i64
+// CHECK9-NEXT: [[TMP28:%.*]] = mul nsw i64 [[IDXPROM]], [[TMP3]]
+// CHECK9-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i64 [[TMP28]]
+// CHECK9-NEXT: [[TMP29:%.*]] = load i32, ptr [[J12]], align 4
+// CHECK9-NEXT: [[IDXPROM36:%.*]] = sext i32 [[TMP29]] to i64
// CHECK9-NEXT: [[ARRAYIDX37:%.*]] = getelementptr inbounds i32, ptr [[ARRAYIDX]], i64 [[IDXPROM36]]
// CHECK9-NEXT: store i32 0, ptr [[ARRAYIDX37]], align 4
// CHECK9-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK9: omp.body.continue:
// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP32:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK9-NEXT: [[ADD38:%.*]] = add nsw i64 [[TMP32]], 1
+// CHECK9-NEXT: [[TMP30:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// CHECK9-NEXT: [[ADD38:%.*]] = add nsw i64 [[TMP30]], 1
// CHECK9-NEXT: store i64 [[ADD38]], ptr [[DOTOMP_IV]], align 8
// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK9: omp.inner.for.end:
// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: [[TMP33:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP34:%.*]] = load i32, ptr [[TMP33]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP34]])
+// CHECK9-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK9-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4
+// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP32]])
// CHECK9-NEXT: br label [[OMP_PRECOND_END]]
// CHECK9: omp.precond.end:
// CHECK9-NEXT: ret void
@@ -1043,7 +777,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK9-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK9-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK9-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.region_id, ptr [[KERNEL_ARGS]])
+// CHECK9-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.region_id, ptr [[KERNEL_ARGS]])
// CHECK9-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK9-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK9: omp_offload.failed:
@@ -1059,7 +793,7 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
// CHECK9-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
// CHECK9-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined, ptr [[TMP0]])
+// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined, ptr [[TMP0]])
// CHECK9-NEXT: ret void
//
//
@@ -1109,113 +843,38 @@ int main (int argc, char **argv) {
// CHECK9-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK9-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK9-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[TMP0]])
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK9: omp.inner.for.end:
-// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK9-NEXT: ret void
-//
-//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined.omp_outlined
-// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(80) [[A:%.*]]) #[[ATTR2]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 8
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 19, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK9-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK9-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK9-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK9-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 19
-// CHECK9-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK9: cond.true:
-// CHECK9-NEXT: br label [[COND_END:%.*]]
-// CHECK9: cond.false:
-// CHECK9-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: br label [[COND_END]]
-// CHECK9: cond.end:
-// CHECK9-NEXT: [[COND:%.*]] = phi i32 [ 19, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK9-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK9: omp.inner.for.cond:
// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK9-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 2
+// CHECK9-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP8]], 2
// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK9-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK9-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[DIV4:%.*]] = sdiv i32 [[TMP12]], 2
-// CHECK9-NEXT: [[MUL5:%.*]] = mul nsw i32 [[DIV4]], 2
-// CHECK9-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL5]]
-// CHECK9-NEXT: [[MUL6:%.*]] = mul nsw i32 [[SUB]], 1
-// CHECK9-NEXT: [[ADD7:%.*]] = add nsw i32 0, [[MUL6]]
-// CHECK9-NEXT: store i32 [[ADD7]], ptr [[J]], align 4
-// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP13]] to i64
+// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP10]], 2
+// CHECK9-NEXT: [[MUL4:%.*]] = mul nsw i32 [[DIV3]], 2
+// CHECK9-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP9]], [[MUL4]]
+// CHECK9-NEXT: [[MUL5:%.*]] = mul nsw i32 [[SUB]], 1
+// CHECK9-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL5]]
+// CHECK9-NEXT: store i32 [[ADD6]], ptr [[J]], align 4
+// CHECK9-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK9-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
// CHECK9-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [2 x i32]], ptr [[TMP0]], i64 0, i64 [[IDXPROM]]
-// CHECK9-NEXT: [[TMP14:%.*]] = load i32, ptr [[J]], align 4
-// CHECK9-NEXT: [[IDXPROM8:%.*]] = sext i32 [[TMP14]] to i64
-// CHECK9-NEXT: [[ARRAYIDX9:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM8]]
-// CHECK9-NEXT: store i32 0, ptr [[ARRAYIDX9]], align 4
+// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[J]], align 4
+// CHECK9-NEXT: [[IDXPROM7:%.*]] = sext i32 [[TMP12]] to i64
+// CHECK9-NEXT: [[ARRAYIDX8:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARRAYIDX]], i64 0, i64 [[IDXPROM7]]
+// CHECK9-NEXT: store i32 0, ptr [[ARRAYIDX8]], align 4
// CHECK9-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK9: omp.body.continue:
// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[ADD10:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK9-NEXT: store i32 [[ADD10]], ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[ADD9:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK9-NEXT: store i32 [[ADD9]], ptr [[DOTOMP_IV]], align 4
// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK9: omp.inner.for.end:
// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK9-NEXT: ret void
//
//
@@ -1343,7 +1002,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP46]], align 4
// CHECK11-NEXT: [[TMP47:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK11-NEXT: store i32 0, ptr [[TMP47]], align 4
-// CHECK11-NEXT: [[TMP48:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.region_id, ptr [[KERNEL_ARGS]])
+// CHECK11-NEXT: [[TMP48:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.region_id, ptr [[KERNEL_ARGS]])
// CHECK11-NEXT: [[TMP49:%.*]] = icmp ne i32 [[TMP48]], 0
// CHECK11-NEXT: br i1 [[TMP49]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK11: omp_offload.failed:
@@ -1375,7 +1034,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: [[TMP0:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
// CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[VLA_ADDR2]], align 4
// CHECK11-NEXT: [[TMP2:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined, ptr [[N_ADDR]], ptr [[M_ADDR]], i32 [[TMP0]], i32 [[TMP1]], ptr [[TMP2]])
+// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 5, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined, ptr [[N_ADDR]], ptr [[M_ADDR]], i32 [[TMP0]], i32 [[TMP1]], ptr [[TMP2]])
// CHECK11-NEXT: ret void
//
//
@@ -1470,180 +1129,56 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: [[CMP14:%.*]] = icmp sle i64 [[TMP19]], [[TMP20]]
// CHECK11-NEXT: br i1 [[CMP14]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK11: omp.inner.for.body:
-// CHECK11-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_COMB_LB]], align 8
-// CHECK11-NEXT: [[TMP22:%.*]] = trunc i64 [[TMP21]] to i32
-// CHECK11-NEXT: [[TMP23:%.*]] = load i64, ptr [[DOTOMP_COMB_UB]], align 8
-// CHECK11-NEXT: [[TMP24:%.*]] = trunc i64 [[TMP23]] to i32
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 7, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined, i32 [[TMP22]], i32 [[TMP24]], ptr [[TMP0]], ptr [[TMP1]], i32 [[TMP2]], i32 [[TMP3]], ptr [[TMP4]])
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[TMP26:%.*]] = load i64, ptr [[DOTOMP_STRIDE]], align 8
-// CHECK11-NEXT: [[ADD:%.*]] = add nsw i64 [[TMP25]], [[TMP26]]
-// CHECK11-NEXT: store i64 [[ADD]], ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK11: omp.inner.for.end:
-// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: [[TMP27:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP28:%.*]] = load i32, ptr [[TMP27]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP28]])
-// CHECK11-NEXT: br label [[OMP_PRECOND_END]]
-// CHECK11: omp.precond.end:
-// CHECK11-NEXT: ret void
-//
-//
-// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l83.omp_outlined.omp_outlined
-// CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[N:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[M:%.*]], i32 noundef [[VLA:%.*]], i32 noundef [[VLA1:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[A:%.*]]) #[[ATTR2]] {
-// CHECK11-NEXT: entry:
-// CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[N_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[M_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[VLA_ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[VLA_ADDR2:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTOMP_IV:%.*]] = alloca i64, align 8
-// CHECK11-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[_TMP3:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTCAPTURE_EXPR_:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTCAPTURE_EXPR_4:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTCAPTURE_EXPR_5:%.*]] = alloca i64, align 8
-// CHECK11-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_LB:%.*]] = alloca i64, align 8
-// CHECK11-NEXT: [[DOTOMP_UB:%.*]] = alloca i64, align 8
-// CHECK11-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i64, align 8
-// CHECK11-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[I13:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[J14:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[N]], ptr [[N_ADDR]], align 4
-// CHECK11-NEXT: store ptr [[M]], ptr [[M_ADDR]], align 4
-// CHECK11-NEXT: store i32 [[VLA]], ptr [[VLA_ADDR]], align 4
-// CHECK11-NEXT: store i32 [[VLA1]], ptr [[VLA_ADDR2]], align 4
-// CHECK11-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: [[TMP0:%.*]] = load ptr, ptr [[N_ADDR]], align 4
-// CHECK11-NEXT: [[TMP1:%.*]] = load ptr, ptr [[M_ADDR]], align 4
-// CHECK11-NEXT: [[TMP2:%.*]] = load i32, ptr [[VLA_ADDR]], align 4
-// CHECK11-NEXT: [[TMP3:%.*]] = load i32, ptr [[VLA_ADDR2]], align 4
-// CHECK11-NEXT: [[TMP4:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: [[TMP5:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK11-NEXT: store i32 [[TMP5]], ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[TMP6:%.*]] = load i32, ptr [[TMP1]], align 4
-// CHECK11-NEXT: store i32 [[TMP6]], ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP7]], 0
-// CHECK11-NEXT: [[DIV:%.*]] = sdiv i32 [[SUB]], 1
-// CHECK11-NEXT: [[CONV:%.*]] = sext i32 [[DIV]] to i64
-// CHECK11-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[SUB6:%.*]] = sub nsw i32 [[TMP8]], 0
-// CHECK11-NEXT: [[DIV7:%.*]] = sdiv i32 [[SUB6]], 1
-// CHECK11-NEXT: [[CONV8:%.*]] = sext i32 [[DIV7]] to i64
-// CHECK11-NEXT: [[MUL:%.*]] = mul nsw i64 [[CONV]], [[CONV8]]
-// CHECK11-NEXT: [[SUB9:%.*]] = sub nsw i64 [[MUL]], 1
-// CHECK11-NEXT: store i64 [[SUB9]], ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK11-NEXT: store i32 0, ptr [[I]], align 4
-// CHECK11-NEXT: store i32 0, ptr [[J]], align 4
-// CHECK11-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_]], align 4
-// CHECK11-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP9]]
-// CHECK11-NEXT: br i1 [[CMP]], label [[LAND_LHS_TRUE:%.*]], label [[OMP_PRECOND_END:%.*]]
-// CHECK11: land.lhs.true:
-// CHECK11-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[CMP10:%.*]] = icmp slt i32 0, [[TMP10]]
-// CHECK11-NEXT: br i1 [[CMP10]], label [[OMP_PRECOND_THEN:%.*]], label [[OMP_PRECOND_END]]
-// CHECK11: omp.precond.then:
-// CHECK11-NEXT: store i64 0, ptr [[DOTOMP_LB]], align 8
-// CHECK11-NEXT: [[TMP11:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK11-NEXT: store i64 [[TMP11]], ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: [[CONV11:%.*]] = zext i32 [[TMP12]] to i64
-// CHECK11-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: [[CONV12:%.*]] = zext i32 [[TMP13]] to i64
-// CHECK11-NEXT: store i64 [[CONV11]], ptr [[DOTOMP_LB]], align 8
-// CHECK11-NEXT: store i64 [[CONV12]], ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: store i64 1, ptr [[DOTOMP_STRIDE]], align 8
-// CHECK11-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK11-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_init_8(ptr @[[GLOB2:[0-9]+]], i32 [[TMP15]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i64 1, i64 1)
-// CHECK11-NEXT: [[TMP16:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: [[TMP17:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK11-NEXT: [[CMP15:%.*]] = icmp sgt i64 [[TMP16]], [[TMP17]]
-// CHECK11-NEXT: br i1 [[CMP15]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK11: cond.true:
-// CHECK11-NEXT: [[TMP18:%.*]] = load i64, ptr [[DOTCAPTURE_EXPR_5]], align 8
-// CHECK11-NEXT: br label [[COND_END:%.*]]
-// CHECK11: cond.false:
-// CHECK11-NEXT: [[TMP19:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: br label [[COND_END]]
-// CHECK11: cond.end:
-// CHECK11-NEXT: [[COND:%.*]] = phi i64 [ [[TMP18]], [[COND_TRUE]] ], [ [[TMP19]], [[COND_FALSE]] ]
-// CHECK11-NEXT: store i64 [[COND]], ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: [[TMP20:%.*]] = load i64, ptr [[DOTOMP_LB]], align 8
-// CHECK11-NEXT: store i64 [[TMP20]], ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK11: omp.inner.for.cond:
// CHECK11-NEXT: [[TMP21:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[TMP22:%.*]] = load i64, ptr [[DOTOMP_UB]], align 8
-// CHECK11-NEXT: [[CMP16:%.*]] = icmp sle i64 [[TMP21]], [[TMP22]]
-// CHECK11-NEXT: br i1 [[CMP16]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK11: omp.inner.for.body:
+// CHECK11-NEXT: [[TMP22:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK11-NEXT: [[SUB15:%.*]] = sub nsw i32 [[TMP22]], 0
+// CHECK11-NEXT: [[DIV16:%.*]] = sdiv i32 [[SUB15]], 1
+// CHECK11-NEXT: [[MUL17:%.*]] = mul nsw i32 1, [[DIV16]]
+// CHECK11-NEXT: [[CONV18:%.*]] = sext i32 [[MUL17]] to i64
+// CHECK11-NEXT: [[DIV19:%.*]] = sdiv i64 [[TMP21]], [[CONV18]]
+// CHECK11-NEXT: [[MUL20:%.*]] = mul nsw i64 [[DIV19]], 1
+// CHECK11-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL20]]
+// CHECK11-NEXT: [[CONV21:%.*]] = trunc i64 [[ADD]] to i32
+// CHECK11-NEXT: store i32 [[CONV21]], ptr [[I11]], align 4
// CHECK11-NEXT: [[TMP23:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[TMP24:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[SUB17:%.*]] = sub nsw i32 [[TMP24]], 0
-// CHECK11-NEXT: [[DIV18:%.*]] = sdiv i32 [[SUB17]], 1
-// CHECK11-NEXT: [[MUL19:%.*]] = mul nsw i32 1, [[DIV18]]
-// CHECK11-NEXT: [[CONV20:%.*]] = sext i32 [[MUL19]] to i64
-// CHECK11-NEXT: [[DIV21:%.*]] = sdiv i64 [[TMP23]], [[CONV20]]
-// CHECK11-NEXT: [[MUL22:%.*]] = mul nsw i64 [[DIV21]], 1
-// CHECK11-NEXT: [[ADD:%.*]] = add nsw i64 0, [[MUL22]]
-// CHECK11-NEXT: [[CONV23:%.*]] = trunc i64 [[ADD]] to i32
-// CHECK11-NEXT: store i32 [[CONV23]], ptr [[I13]], align 4
-// CHECK11-NEXT: [[TMP25:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[TMP26:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[TMP27:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[SUB24:%.*]] = sub nsw i32 [[TMP27]], 0
-// CHECK11-NEXT: [[DIV25:%.*]] = sdiv i32 [[SUB24]], 1
-// CHECK11-NEXT: [[MUL26:%.*]] = mul nsw i32 1, [[DIV25]]
-// CHECK11-NEXT: [[CONV27:%.*]] = sext i32 [[MUL26]] to i64
-// CHECK11-NEXT: [[DIV28:%.*]] = sdiv i64 [[TMP26]], [[CONV27]]
-// CHECK11-NEXT: [[TMP28:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
-// CHECK11-NEXT: [[SUB29:%.*]] = sub nsw i32 [[TMP28]], 0
-// CHECK11-NEXT: [[DIV30:%.*]] = sdiv i32 [[SUB29]], 1
-// CHECK11-NEXT: [[MUL31:%.*]] = mul nsw i32 1, [[DIV30]]
-// CHECK11-NEXT: [[CONV32:%.*]] = sext i32 [[MUL31]] to i64
-// CHECK11-NEXT: [[MUL33:%.*]] = mul nsw i64 [[DIV28]], [[CONV32]]
-// CHECK11-NEXT: [[SUB34:%.*]] = sub nsw i64 [[TMP25]], [[MUL33]]
-// CHECK11-NEXT: [[MUL35:%.*]] = mul nsw i64 [[SUB34]], 1
-// CHECK11-NEXT: [[ADD36:%.*]] = add nsw i64 0, [[MUL35]]
-// CHECK11-NEXT: [[CONV37:%.*]] = trunc i64 [[ADD36]] to i32
-// CHECK11-NEXT: store i32 [[CONV37]], ptr [[J14]], align 4
-// CHECK11-NEXT: [[TMP29:%.*]] = load i32, ptr [[I13]], align 4
-// CHECK11-NEXT: [[TMP30:%.*]] = mul nsw i32 [[TMP29]], [[TMP3]]
-// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i32 [[TMP30]]
-// CHECK11-NEXT: [[TMP31:%.*]] = load i32, ptr [[J14]], align 4
-// CHECK11-NEXT: [[ARRAYIDX38:%.*]] = getelementptr inbounds i32, ptr [[ARRAYIDX]], i32 [[TMP31]]
-// CHECK11-NEXT: store i32 0, ptr [[ARRAYIDX38]], align 4
+// CHECK11-NEXT: [[TMP24:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// CHECK11-NEXT: [[TMP25:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK11-NEXT: [[SUB22:%.*]] = sub nsw i32 [[TMP25]], 0
+// CHECK11-NEXT: [[DIV23:%.*]] = sdiv i32 [[SUB22]], 1
+// CHECK11-NEXT: [[MUL24:%.*]] = mul nsw i32 1, [[DIV23]]
+// CHECK11-NEXT: [[CONV25:%.*]] = sext i32 [[MUL24]] to i64
+// CHECK11-NEXT: [[DIV26:%.*]] = sdiv i64 [[TMP24]], [[CONV25]]
+// CHECK11-NEXT: [[TMP26:%.*]] = load i32, ptr [[DOTCAPTURE_EXPR_4]], align 4
+// CHECK11-NEXT: [[SUB27:%.*]] = sub nsw i32 [[TMP26]], 0
+// CHECK11-NEXT: [[DIV28:%.*]] = sdiv i32 [[SUB27]], 1
+// CHECK11-NEXT: [[MUL29:%.*]] = mul nsw i32 1, [[DIV28]]
+// CHECK11-NEXT: [[CONV30:%.*]] = sext i32 [[MUL29]] to i64
+// CHECK11-NEXT: [[MUL31:%.*]] = mul nsw i64 [[DIV26]], [[CONV30]]
+// CHECK11-NEXT: [[SUB32:%.*]] = sub nsw i64 [[TMP23]], [[MUL31]]
+// CHECK11-NEXT: [[MUL33:%.*]] = mul nsw i64 [[SUB32]], 1
+// CHECK11-NEXT: [[ADD34:%.*]] = add nsw i64 0, [[MUL33]]
+// CHECK11-NEXT: [[CONV35:%.*]] = trunc i64 [[ADD34]] to i32
+// CHECK11-NEXT: store i32 [[CONV35]], ptr [[J12]], align 4
+// CHECK11-NEXT: [[TMP27:%.*]] = load i32, ptr [[I11]], align 4
+// CHECK11-NEXT: [[TMP28:%.*]] = mul nsw i32 [[TMP27]], [[TMP3]]
+// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP4]], i32 [[TMP28]]
+// CHECK11-NEXT: [[TMP29:%.*]] = load i32, ptr [[J12]], align 4
+// CHECK11-NEXT: [[ARRAYIDX36:%.*]] = getelementptr inbounds i32, ptr [[ARRAYIDX]], i32 [[TMP29]]
+// CHECK11-NEXT: store i32 0, ptr [[ARRAYIDX36]], align 4
// CHECK11-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK11: omp.body.continue:
// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP32:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
-// CHECK11-NEXT: [[ADD39:%.*]] = add nsw i64 [[TMP32]], 1
-// CHECK11-NEXT: store i64 [[ADD39]], ptr [[DOTOMP_IV]], align 8
+// CHECK11-NEXT: [[TMP30:%.*]] = load i64, ptr [[DOTOMP_IV]], align 8
+// CHECK11-NEXT: [[ADD37:%.*]] = add nsw i64 [[TMP30]], 1
+// CHECK11-NEXT: store i64 [[ADD37]], ptr [[DOTOMP_IV]], align 8
// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK11: omp.inner.for.end:
// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: [[TMP33:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP34:%.*]] = load i32, ptr [[TMP33]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP34]])
+// CHECK11-NEXT: [[TMP31:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK11-NEXT: [[TMP32:%.*]] = load i32, ptr [[TMP31]], align 4
+// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP32]])
// CHECK11-NEXT: br label [[OMP_PRECOND_END]]
// CHECK11: omp.precond.end:
// CHECK11-NEXT: ret void
@@ -1695,7 +1230,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP16]], align 4
// CHECK11-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK11-NEXT: store i32 0, ptr [[TMP17]], align 4
-// CHECK11-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.region_id, ptr [[KERNEL_ARGS]])
+// CHECK11-NEXT: [[TMP18:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.region_id, ptr [[KERNEL_ARGS]])
// CHECK11-NEXT: [[TMP19:%.*]] = icmp ne i32 [[TMP18]], 0
// CHECK11-NEXT: br i1 [[TMP19]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK11: omp_offload.failed:
@@ -1711,7 +1246,7 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
// CHECK11-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
// CHECK11-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined, ptr [[TMP0]])
+// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined, ptr [[TMP0]])
// CHECK11-NEXT: ret void
//
//
@@ -1761,106 +1296,35 @@ int main (int argc, char **argv) {
// CHECK11-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK11-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK11: omp.inner.for.body:
-// CHECK11-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK11-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK11-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[TMP0]])
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK11-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK11-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK11: omp.inner.for.end:
-// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK11-NEXT: ret void
-//
-//
-// CHECK11-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiLi10ELi2EEiT__l69.omp_outlined.omp_outlined
-// CHECK11-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(80) [[A:%.*]]) #[[ATTR2]] {
-// CHECK11-NEXT: entry:
-// CHECK11-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[A_ADDR:%.*]] = alloca ptr, align 4
-// CHECK11-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[_TMP1:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: [[J:%.*]] = alloca i32, align 4
-// CHECK11-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: store ptr [[A]], ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: [[TMP0:%.*]] = load ptr, ptr [[A_ADDR]], align 4
-// CHECK11-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: store i32 19, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK11-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK11-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK11-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK11-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK11-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK11-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK11-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 19
-// CHECK11-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK11: cond.true:
-// CHECK11-NEXT: br label [[COND_END:%.*]]
-// CHECK11: cond.false:
-// CHECK11-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: br label [[COND_END]]
-// CHECK11: cond.end:
-// CHECK11-NEXT: [[COND:%.*]] = phi i32 [ 19, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK11-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK11-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK11: omp.inner.for.cond:
// CHECK11-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK11-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK11-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK11: omp.inner.for.body:
-// CHECK11-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP10]], 2
+// CHECK11-NEXT: [[DIV:%.*]] = sdiv i32 [[TMP8]], 2
// CHECK11-NEXT: [[MUL:%.*]] = mul nsw i32 [[DIV]], 1
// CHECK11-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK11-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK11-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP12]], 2
+// CHECK11-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK11-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK11-NEXT: [[DIV3:%.*]] = sdiv i32 [[TMP10]], 2
// CHECK11-NEXT: [[MUL4:%.*]] = mul nsw i32 [[DIV3]], 2
-// CHECK11-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP11]], [[MUL4]]
+// CHECK11-NEXT: [[SUB:%.*]] = sub nsw i32 [[TMP9]], [[MUL4]]
// CHECK11-NEXT: [[MUL5:%.*]] = mul nsw i32 [[SUB]], 1
// CHECK11-NEXT: [[ADD6:%.*]] = add nsw i32 0, [[MUL5]]
// CHECK11-NEXT: store i32 [[ADD6]], ptr [[J]], align 4
-// CHECK11-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [2 x i32]], ptr [[TMP0]], i32 0, i32 [[TMP13]]
-// CHECK11-NEXT: [[TMP14:%.*]] = load i32, ptr [[J]], align 4
-// CHECK11-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARRAYIDX]], i32 0, i32 [[TMP14]]
+// CHECK11-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK11-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [10 x [2 x i32]], ptr [[TMP0]], i32 0, i32 [[TMP11]]
+// CHECK11-NEXT: [[TMP12:%.*]] = load i32, ptr [[J]], align 4
+// CHECK11-NEXT: [[ARRAYIDX7:%.*]] = getelementptr inbounds [2 x i32], ptr [[ARRAYIDX]], i32 0, i32 [[TMP12]]
// CHECK11-NEXT: store i32 0, ptr [[ARRAYIDX7]], align 4
// CHECK11-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK11: omp.body.continue:
// CHECK11-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK11: omp.inner.for.inc:
-// CHECK11-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK11-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK11-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK11-NEXT: [[ADD8:%.*]] = add nsw i32 [[TMP13]], 1
// CHECK11-NEXT: store i32 [[ADD8]], ptr [[DOTOMP_IV]], align 4
// CHECK11-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK11: omp.inner.for.end:
// CHECK11-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK11: omp.loop.exit:
-// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
+// CHECK11-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
// CHECK11-NEXT: ret void
//
diff --git a/clang/test/OpenMP/teams_generic_loop_private_codegen.cpp b/clang/test/OpenMP/teams_generic_loop_private_codegen.cpp
index 303bce8c648c..e955db129d1d 100644
--- a/clang/test/OpenMP/teams_generic_loop_private_codegen.cpp
+++ b/clang/test/OpenMP/teams_generic_loop_private_codegen.cpp
@@ -288,7 +288,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK1-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -302,7 +302,7 @@ int main() {
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96
// CHECK1-SAME: () #[[ATTR4:[0-9]+]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined)
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined)
// CHECK1-NEXT: ret void
//
//
@@ -365,149 +365,48 @@ int main() {
// CHECK1: omp.inner.for.cond.cleanup:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
-// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i64 2
-// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done3:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK1-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK1-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK1-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK1: arrayctor.loop:
-// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK1-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK1: arrayctor.cont:
-// CHECK1-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK1: omp.inner.for.cond.cleanup:
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK1-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM3:%.*]] = sext i32 [[TMP12]] to i64
-// CHECK1-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM3]]
-// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[VAR]], i64 4, i1 false)
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD5]], ptr [[SIVAR]], align 4
+// CHECK1-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM2:%.*]] = sext i32 [[TMP10]] to i64
+// CHECK1-NEXT: [[ARRAYIDX3:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i64 0, i64 [[IDXPROM2]]
+// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX3]], ptr align 4 [[VAR]], i64 4, i1 false)
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
+// CHECK1-NEXT: store i32 [[ADD4]], ptr [[SIVAR]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK1-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
+// CHECK1-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN7]], i64 2
+// CHECK1-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN6]], i64 2
// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK1-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done8:
+// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
+// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE7:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK1: arraydestroy.done7:
// CHECK1-NEXT: ret void
//
//
@@ -558,7 +457,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK1-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -607,7 +506,7 @@ int main() {
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56
// CHECK1-SAME: () #[[ATTR4]] {
// CHECK1-NEXT: entry:
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined)
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined)
// CHECK1-NEXT: ret void
//
//
@@ -673,149 +572,45 @@ int main() {
// CHECK1: omp.inner.for.cond.cleanup:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
-// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i64 2
-// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
-// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done5:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK1-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK1-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK1-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i64 2
-// CHECK1-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK1: arrayctor.loop:
-// CHECK1-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK1-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK1-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i64 1
-// CHECK1-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK1-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK1: arrayctor.cont:
-// CHECK1-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK1-NEXT: store ptr [[VAR]], ptr [[_TMP3]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK1-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK1: omp.inner.for.cond.cleanup:
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM:%.*]] = sext i32 [[TMP9]] to i64
// CHECK1-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i64 0, i64 [[IDXPROM]]
-// CHECK1-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[IDXPROM5:%.*]] = sext i32 [[TMP13]] to i64
-// CHECK1-NEXT: [[ARRAYIDX6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM5]]
-// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX6]], ptr align 4 [[TMP12]], i64 4, i1 false)
+// CHECK1-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[IDXPROM4:%.*]] = sext i32 [[TMP11]] to i64
+// CHECK1-NEXT: [[ARRAYIDX5:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i64 0, i64 [[IDXPROM4]]
+// CHECK1-NEXT: call void @llvm.memcpy.p0.p0.i64(ptr align 4 [[ARRAYIDX5]], ptr align 4 [[TMP10]], i64 4, i1 false)
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD7:%.*]] = add nsw i32 [[TMP14]], 1
-// CHECK1-NEXT: store i32 [[ADD7]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK1-NEXT: store i32 [[ADD6]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
+// CHECK1-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
+// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAY_BEGIN8:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK1-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN8]], i64 2
+// CHECK1-NEXT: [[ARRAY_BEGIN7:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
+// CHECK1-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN7]], i64 2
// CHECK1-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK1: arraydestroy.body:
-// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK1-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i64 -1
// CHECK1-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN8]]
-// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE9:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK1: arraydestroy.done9:
+// CHECK1-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN7]]
+// CHECK1-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE8:%.*]], label [[ARRAYDESTROY_BODY]]
+// CHECK1: arraydestroy.done8:
// CHECK1-NEXT: ret void
//
//
@@ -1021,7 +816,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK3-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -1035,7 +830,7 @@ int main() {
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96
// CHECK3-SAME: () #[[ATTR4:[0-9]+]] {
// CHECK3-NEXT: entry:
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined)
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined)
// CHECK3-NEXT: ret void
//
//
@@ -1098,138 +893,41 @@ int main() {
// CHECK3: omp.inner.for.cond.cleanup:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAY_BEGIN2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN2]], i32 2
-// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN2]]
-// CHECK3-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE3:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK3: arraydestroy.done3:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l96.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK3-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S], align 4
-// CHECK3-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S:%.*]], align 4
-// CHECK3-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK3-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK3: arrayctor.loop:
-// CHECK3-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK3-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK3-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK3-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK3-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK3: arrayctor.cont:
-// CHECK3-NEXT: call void @_ZN1SIfEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP1:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK3-NEXT: br i1 [[CMP1]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK3: omp.inner.for.cond.cleanup:
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK3-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP12]]
+// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK3-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX2:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 [[TMP10]]
// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX2]], ptr align 4 [[VAR]], i32 4, i1 false)
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[SIVAR]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP14]], [[TMP13]]
+// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR]], align 4
+// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
// CHECK3-NEXT: store i32 [[ADD3]], ptr [[SIVAR]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP15]], 1
+// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
// CHECK3-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP16:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP16]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP17]])
+// CHECK3-NEXT: [[TMP14:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP14]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP15]])
// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAY_BEGIN5:%.*]] = getelementptr inbounds [2 x %struct.S], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP18:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
+// CHECK3-NEXT: [[TMP16:%.*]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAY_BEGIN5]], i32 2
// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP18]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP16]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK3-NEXT: call void @_ZN1SIfED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN5]]
@@ -1285,7 +983,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP11]], align 4
// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB2]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP14:%.*]] = icmp ne i32 [[TMP13]], 0
// CHECK3-NEXT: br i1 [[TMP14]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -1334,7 +1032,7 @@ int main() {
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56
// CHECK3-SAME: () #[[ATTR4]] {
// CHECK3-NEXT: entry:
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined)
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined)
// CHECK3-NEXT: ret void
//
//
@@ -1400,138 +1098,38 @@ int main() {
// CHECK3: omp.inner.for.cond.cleanup:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined.omp_outlined, i32 [[TMP7]], i32 [[TMP8]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP9]], [[TMP10]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP11:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[TMP11]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP12]])
-// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAY_BEGIN4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN4]], i32 2
-// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
-// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP13]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
-// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
-// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN4]]
-// CHECK3-NEXT: br i1 [[ARRAYDESTROY_DONE]], label [[ARRAYDESTROY_DONE5:%.*]], label [[ARRAYDESTROY_BODY]]
-// CHECK3: arraydestroy.done5:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l56.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[_TMP1:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[VEC:%.*]] = alloca [2 x i32], align 4
-// CHECK3-NEXT: [[S_ARR:%.*]] = alloca [2 x %struct.S.0], align 4
-// CHECK3-NEXT: [[VAR:%.*]] = alloca [[STRUCT_S_0:%.*]], align 4
-// CHECK3-NEXT: [[_TMP2:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr undef, ptr [[_TMP1]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP0]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: [[ARRAY_BEGIN:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[ARRAYCTOR_END:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN]], i32 2
-// CHECK3-NEXT: br label [[ARRAYCTOR_LOOP:%.*]]
-// CHECK3: arrayctor.loop:
-// CHECK3-NEXT: [[ARRAYCTOR_CUR:%.*]] = phi ptr [ [[ARRAY_BEGIN]], [[ENTRY:%.*]] ], [ [[ARRAYCTOR_NEXT:%.*]], [[ARRAYCTOR_LOOP]] ]
-// CHECK3-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYCTOR_CUR]])
-// CHECK3-NEXT: [[ARRAYCTOR_NEXT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYCTOR_CUR]], i32 1
-// CHECK3-NEXT: [[ARRAYCTOR_DONE:%.*]] = icmp eq ptr [[ARRAYCTOR_NEXT]], [[ARRAYCTOR_END]]
-// CHECK3-NEXT: br i1 [[ARRAYCTOR_DONE]], label [[ARRAYCTOR_CONT:%.*]], label [[ARRAYCTOR_LOOP]]
-// CHECK3: arrayctor.cont:
-// CHECK3-NEXT: call void @_ZN1SIiEC1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]])
-// CHECK3-NEXT: store ptr [[VAR]], ptr [[_TMP2]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK3-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_COND_CLEANUP:%.*]]
-// CHECK3: omp.inner.for.cond.cleanup:
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[T_VAR]], align 4
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP9]]
+// CHECK3-NEXT: store i32 [[TMP8]], ptr [[ARRAYIDX]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP2]], align 4
// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds [2 x i32], ptr [[VEC]], i32 0, i32 [[TMP11]]
-// CHECK3-NEXT: store i32 [[TMP10]], ptr [[ARRAYIDX]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load ptr, ptr [[_TMP2]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP13]]
-// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP12]], i32 4, i1 false)
+// CHECK3-NEXT: [[ARRAYIDX4:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 [[TMP11]]
+// CHECK3-NEXT: call void @llvm.memcpy.p0.p0.i32(ptr align 4 [[ARRAYIDX4]], ptr align 4 [[TMP10]], i32 4, i1 false)
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], 1
+// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP12]], 1
// CHECK3-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: [[TMP15:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP15]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP16]])
+// CHECK3-NEXT: [[TMP13:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
+// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP13]], align 4
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP14]])
// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[VAR]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAY_BEGIN6:%.*]] = getelementptr inbounds [2 x %struct.S.0], ptr [[S_ARR]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP17:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
+// CHECK3-NEXT: [[TMP15:%.*]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAY_BEGIN6]], i32 2
// CHECK3-NEXT: br label [[ARRAYDESTROY_BODY:%.*]]
// CHECK3: arraydestroy.body:
-// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP17]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
+// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENTPAST:%.*]] = phi ptr [ [[TMP15]], [[OMP_LOOP_EXIT]] ], [ [[ARRAYDESTROY_ELEMENT:%.*]], [[ARRAYDESTROY_BODY]] ]
// CHECK3-NEXT: [[ARRAYDESTROY_ELEMENT]] = getelementptr inbounds [[STRUCT_S_0]], ptr [[ARRAYDESTROY_ELEMENTPAST]], i32 -1
// CHECK3-NEXT: call void @_ZN1SIiED1Ev(ptr noundef nonnull align 4 dereferenceable(4) [[ARRAYDESTROY_ELEMENT]]) #[[ATTR2]]
// CHECK3-NEXT: [[ARRAYDESTROY_DONE:%.*]] = icmp eq ptr [[ARRAYDESTROY_ELEMENT]], [[ARRAY_BEGIN6]]
@@ -1726,7 +1324,7 @@ int main() {
// CHECK9-NEXT: [[TMP:%.*]] = alloca ptr, align 8
// CHECK9-NEXT: store i64 [[G1]], ptr [[G1_ADDR]], align 8
// CHECK9-NEXT: store ptr [[G1_ADDR]], ptr [[TMP]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l75.omp_outlined)
+// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB2:[0-9]+]], i32 0, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l75.omp_outlined)
// CHECK9-NEXT: ret void
//
//
@@ -1747,6 +1345,7 @@ int main() {
// CHECK9-NEXT: [[_TMP2:%.*]] = alloca ptr, align 8
// CHECK9-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
+// CHECK9-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
// CHECK9-NEXT: store ptr undef, ptr [[_TMP1]], align 8
@@ -1778,112 +1377,34 @@ int main() {
// CHECK9-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP5]], [[TMP6]]
// CHECK9-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK9-NEXT: [[TMP8:%.*]] = zext i32 [[TMP7]] to i64
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK9-NEXT: [[TMP10:%.*]] = zext i32 [[TMP9]] to i64
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB3]], i32 2, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l75.omp_outlined.omp_outlined, i64 [[TMP8]], i64 [[TMP10]])
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP11]], [[TMP12]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK9: omp.inner.for.end:
-// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
-// CHECK9-NEXT: ret void
-//
-//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l75.omp_outlined.omp_outlined
-// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]]) #[[ATTR4]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[_TMP1:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[G:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[G1:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[_TMP3:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[SIVAR:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
-// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store ptr undef, ptr [[_TMP1]], align 8
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP0:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV:%.*]] = trunc i64 [[TMP0]] to i32
-// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV2:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK9-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[CONV2]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK9-NEXT: store ptr [[G1]], ptr [[_TMP3]], align 8
-// CHECK9-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP3:%.*]] = load i32, ptr [[TMP2]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP3]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK9-NEXT: [[TMP4:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP4]], 1
-// CHECK9-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK9: cond.true:
-// CHECK9-NEXT: br label [[COND_END:%.*]]
-// CHECK9: cond.false:
-// CHECK9-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: br label [[COND_END]]
-// CHECK9: cond.end:
-// CHECK9-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP5]], [[COND_FALSE]] ]
-// CHECK9-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[TMP6]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK9: omp.inner.for.cond:
// CHECK9-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP4:%.*]] = icmp sle i32 [[TMP7]], [[TMP8]]
-// CHECK9-NEXT: br i1 [[CMP4]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP9]], 1
+// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP7]], 1
// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK9-NEXT: store i32 [[ADD]], ptr [[I]], align 4
// CHECK9-NEXT: store i32 1, ptr [[G]], align 4
-// CHECK9-NEXT: [[TMP10:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK9-NEXT: store volatile i32 1, ptr [[TMP10]], align 4
+// CHECK9-NEXT: [[TMP8:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK9-NEXT: store volatile i32 1, ptr [[TMP8]], align 4
// CHECK9-NEXT: store i32 2, ptr [[SIVAR]], align 4
-// CHECK9-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
-// CHECK9-NEXT: store ptr [[G]], ptr [[TMP11]], align 8
-// CHECK9-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 1
-// CHECK9-NEXT: [[TMP13:%.*]] = load ptr, ptr [[_TMP3]], align 8
-// CHECK9-NEXT: store ptr [[TMP13]], ptr [[TMP12]], align 8
-// CHECK9-NEXT: [[TMP14:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 2
-// CHECK9-NEXT: store ptr [[SIVAR]], ptr [[TMP14]], align 8
+// CHECK9-NEXT: [[TMP9:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK9-NEXT: store ptr [[G]], ptr [[TMP9]], align 8
+// CHECK9-NEXT: [[TMP10:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 1
+// CHECK9-NEXT: [[TMP11:%.*]] = load ptr, ptr [[_TMP2]], align 8
+// CHECK9-NEXT: store ptr [[TMP11]], ptr [[TMP10]], align 8
+// CHECK9-NEXT: [[TMP12:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 2
+// CHECK9-NEXT: store ptr [[SIVAR]], ptr [[TMP12]], align 8
// CHECK9-NEXT: call void @"_ZZZ4mainENK3$_0clEvENKUlvE_clEv"(ptr noundef nonnull align 8 dereferenceable(24) [[REF_TMP]])
// CHECK9-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK9: omp.body.continue:
// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP15:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP15]], 1
-// CHECK9-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK9-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK9: omp.inner.for.end:
// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP3]])
+// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP1]])
// CHECK9-NEXT: ret void
//
//
diff --git a/clang/test/OpenMP/teams_generic_loop_reduction_codegen.cpp b/clang/test/OpenMP/teams_generic_loop_reduction_codegen.cpp
index d80c003c0109..f0067cb93d9b 100644
--- a/clang/test/OpenMP/teams_generic_loop_reduction_codegen.cpp
+++ b/clang/test/OpenMP/teams_generic_loop_reduction_codegen.cpp
@@ -141,7 +141,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4
// CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP19]], align 4
-// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB4:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
// CHECK1-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -157,7 +157,7 @@ int main() {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[SIVAR_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: store i64 [[SIVAR]], ptr [[SIVAR_ADDR]], align 8
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined, ptr [[SIVAR_ADDR]])
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined, ptr [[SIVAR_ADDR]])
// CHECK1-NEXT: ret void
//
//
@@ -208,165 +208,50 @@ int main() {
// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[SIVAR1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK1-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK1-NEXT: store ptr [[SIVAR1]], ptr [[TMP14]], align 8
-// CHECK1-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// CHECK1-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// CHECK1-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// CHECK1-NEXT: ]
-// CHECK1: .omp.reduction.case1:
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[TMP0]], align 4
-// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK1: .omp.reduction.case2:
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK1-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
-// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK1: .omp.reduction.default:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[SIVAR:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[SIVAR_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[SIVAR2:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[SIVAR]], ptr [[SIVAR_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SIVAR_ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[SIVAR2]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK1-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
-// CHECK1-NEXT: store i32 [[ADD4]], ptr [[SIVAR2]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], [[TMP9]]
+// CHECK1-NEXT: store i32 [[ADD3]], ptr [[SIVAR1]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP13]], 1
-// CHECK1-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP11]], 1
+// CHECK1-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
-// CHECK1-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK1-NEXT: store ptr [[SIVAR2]], ptr [[TMP14]], align 8
-// CHECK1-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
+// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
+// CHECK1-NEXT: store ptr [[SIVAR1]], ptr [[TMP12]], align 8
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// CHECK1-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// CHECK1-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// CHECK1-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// CHECK1-NEXT: ]
// CHECK1: .omp.reduction.case1:
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK1-NEXT: store i32 [[ADD6]], ptr [[TMP0]], align 4
-// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], ptr @.gomp_critical_user_.reduction.var)
+// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
+// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
+// CHECK1-NEXT: store i32 [[ADD5]], ptr [[TMP0]], align 4
+// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK1: .omp.reduction.case2:
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK1-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
+// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK1-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK1: .omp.reduction.default:
// CHECK1-NEXT: ret void
//
//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// CHECK1-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// CHECK1-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP8]], [[TMP9]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[TMP7]], align 4
-// CHECK1-NEXT: ret void
-//
-//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func
-// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
+// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
// CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
@@ -435,7 +320,7 @@ int main() {
// CHECK1-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4
// CHECK1-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK1-NEXT: store i32 0, ptr [[TMP19]], align 4
-// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB4]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.region_id, ptr [[KERNEL_ARGS]])
+// CHECK1-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.region_id, ptr [[KERNEL_ARGS]])
// CHECK1-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
// CHECK1-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK1: omp_offload.failed:
@@ -450,7 +335,7 @@ int main() {
// CHECK1-NEXT: entry:
// CHECK1-NEXT: [[T_VAR_ADDR:%.*]] = alloca i64, align 8
// CHECK1-NEXT: store i64 [[T_VAR]], ptr [[T_VAR_ADDR]], align 8
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined, ptr [[T_VAR_ADDR]])
+// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined, ptr [[T_VAR_ADDR]])
// CHECK1-NEXT: ret void
//
//
@@ -501,163 +386,48 @@ int main() {
// CHECK1-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK1-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK1-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[T_VAR1]])
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK1: omp.inner.for.end:
-// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK1-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK1-NEXT: store ptr [[T_VAR1]], ptr [[TMP14]], align 8
-// CHECK1-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// CHECK1-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// CHECK1-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// CHECK1-NEXT: ]
-// CHECK1: .omp.reduction.case1:
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK1-NEXT: store i32 [[ADD3]], ptr [[TMP0]], align 4
-// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK1: .omp.reduction.case2:
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK1-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
-// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK1: .omp.reduction.default:
-// CHECK1-NEXT: ret void
-//
-//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined
-// CHECK1-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[T_VAR:%.*]]) #[[ATTR1]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK1-NEXT: [[T_VAR_ADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[T_VAR2:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK1-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// CHECK1-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: store ptr [[T_VAR]], ptr [[T_VAR_ADDR]], align 8
-// CHECK1-NEXT: [[TMP0:%.*]] = load ptr, ptr [[T_VAR_ADDR]], align 8
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK1-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK1-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK1-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK1-NEXT: store i32 0, ptr [[T_VAR2]], align 4
-// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK1-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK1-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK1-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 1
-// CHECK1-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK1: cond.true:
-// CHECK1-NEXT: br label [[COND_END:%.*]]
-// CHECK1: cond.false:
-// CHECK1-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: br label [[COND_END]]
-// CHECK1: cond.end:
-// CHECK1-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK1-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK1-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK1: omp.inner.for.cond:
// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK1-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK1-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK1: omp.inner.for.body:
-// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK1-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK1-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK1-NEXT: [[TMP12:%.*]] = load i32, ptr [[T_VAR2]], align 4
-// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
-// CHECK1-NEXT: store i32 [[ADD4]], ptr [[T_VAR2]], align 4
+// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK1-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK1-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], [[TMP9]]
+// CHECK1-NEXT: store i32 [[ADD3]], ptr [[T_VAR1]], align 4
// CHECK1-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK1: omp.body.continue:
// CHECK1-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK1: omp.inner.for.inc:
-// CHECK1-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP13]], 1
-// CHECK1-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK1-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP11]], 1
+// CHECK1-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK1-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK1: omp.inner.for.end:
// CHECK1-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK1: omp.loop.exit:
-// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
-// CHECK1-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK1-NEXT: store ptr [[T_VAR2]], ptr [[TMP14]], align 8
-// CHECK1-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK1-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// CHECK1-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
+// CHECK1-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
+// CHECK1-NEXT: store ptr [[T_VAR1]], ptr [[TMP12]], align 8
+// CHECK1-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// CHECK1-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// CHECK1-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// CHECK1-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// CHECK1-NEXT: ]
// CHECK1: .omp.reduction.case1:
-// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK1-NEXT: [[TMP17:%.*]] = load i32, ptr [[T_VAR2]], align 4
-// CHECK1-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK1-NEXT: store i32 [[ADD6]], ptr [[TMP0]], align 4
-// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], ptr @.gomp_critical_user_.reduction.var)
+// CHECK1-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
+// CHECK1-NEXT: [[TMP15:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK1-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
+// CHECK1-NEXT: store i32 [[ADD5]], ptr [[TMP0]], align 4
+// CHECK1-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK1: .omp.reduction.case2:
-// CHECK1-NEXT: [[TMP18:%.*]] = load i32, ptr [[T_VAR2]], align 4
-// CHECK1-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
+// CHECK1-NEXT: [[TMP16:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK1-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
// CHECK1-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK1: .omp.reduction.default:
// CHECK1-NEXT: ret void
//
//
-// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
-// CHECK1-NEXT: entry:
-// CHECK1-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// CHECK1-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// CHECK1-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// CHECK1-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// CHECK1-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// CHECK1-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// CHECK1-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// CHECK1-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// CHECK1-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// CHECK1-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK1-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK1-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP8]], [[TMP9]]
-// CHECK1-NEXT: store i32 [[ADD]], ptr [[TMP7]], align 4
-// CHECK1-NEXT: ret void
-//
-//
// CHECK1-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func
// CHECK1-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
// CHECK1-NEXT: entry:
@@ -726,7 +496,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4
// CHECK3-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP19]], align 4
-// CHECK3-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB4:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3:[0-9]+]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
// CHECK3-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -742,7 +512,7 @@ int main() {
// CHECK3-NEXT: entry:
// CHECK3-NEXT: [[SIVAR_ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: store i32 [[SIVAR]], ptr [[SIVAR_ADDR]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined, ptr [[SIVAR_ADDR]])
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined, ptr [[SIVAR_ADDR]])
// CHECK3-NEXT: ret void
//
//
@@ -793,161 +563,50 @@ int main() {
// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[SIVAR1]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
-// CHECK3-NEXT: store ptr [[SIVAR1]], ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP2]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// CHECK3-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// CHECK3-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// CHECK3-NEXT: ]
-// CHECK3: .omp.reduction.case1:
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
-// CHECK3-NEXT: store i32 [[ADD3]], ptr [[TMP0]], align 4
-// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK3: .omp.reduction.case2:
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
-// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK3: .omp.reduction.default:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[SIVAR:%.*]]) #[[ATTR1]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[SIVAR_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[SIVAR1:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[SIVAR]], ptr [[SIVAR_ADDR]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SIVAR_ADDR]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], [[TMP9]]
// CHECK3-NEXT: store i32 [[ADD3]], ptr [[SIVAR1]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP11]], 1
// CHECK3-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
-// CHECK3-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
-// CHECK3-NEXT: store ptr [[SIVAR1]], ptr [[TMP14]], align 4
-// CHECK3-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
+// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
+// CHECK3-NEXT: store ptr [[SIVAR1]], ptr [[TMP12]], align 4
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// CHECK3-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// CHECK3-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// CHECK3-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// CHECK3-NEXT: ]
// CHECK3: .omp.reduction.case1:
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
+// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
+// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
// CHECK3-NEXT: store i32 [[ADD5]], ptr [[TMP0]], align 4
-// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], ptr @.gomp_critical_user_.reduction.var)
+// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK3: .omp.reduction.case2:
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK3-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
+// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK3-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK3: .omp.reduction.default:
// CHECK3-NEXT: ret void
//
//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// CHECK3-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4
-// CHECK3-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP8]], [[TMP9]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[TMP7]], align 4
-// CHECK3-NEXT: ret void
-//
-//
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l68.omp_outlined.omp.reduction.reduction_func
-// CHECK3-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
+// CHECK3-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3:[0-9]+]] {
// CHECK3-NEXT: entry:
// CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4
// CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 4
@@ -1016,7 +675,7 @@ int main() {
// CHECK3-NEXT: store [3 x i32] zeroinitializer, ptr [[TMP18]], align 4
// CHECK3-NEXT: [[TMP19:%.*]] = getelementptr inbounds [[STRUCT___TGT_KERNEL_ARGUMENTS]], ptr [[KERNEL_ARGS]], i32 0, i32 12
// CHECK3-NEXT: store i32 0, ptr [[TMP19]], align 4
-// CHECK3-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB4]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.region_id, ptr [[KERNEL_ARGS]])
+// CHECK3-NEXT: [[TMP20:%.*]] = call i32 @__tgt_target_kernel(ptr @[[GLOB3]], i64 -1, i32 0, i32 0, ptr @.{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.region_id, ptr [[KERNEL_ARGS]])
// CHECK3-NEXT: [[TMP21:%.*]] = icmp ne i32 [[TMP20]], 0
// CHECK3-NEXT: br i1 [[TMP21]], label [[OMP_OFFLOAD_FAILED:%.*]], label [[OMP_OFFLOAD_CONT:%.*]]
// CHECK3: omp_offload.failed:
@@ -1031,7 +690,7 @@ int main() {
// CHECK3-NEXT: entry:
// CHECK3-NEXT: [[T_VAR_ADDR:%.*]] = alloca i32, align 4
// CHECK3-NEXT: store i32 [[T_VAR]], ptr [[T_VAR_ADDR]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined, ptr [[T_VAR_ADDR]])
+// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined, ptr [[T_VAR_ADDR]])
// CHECK3-NEXT: ret void
//
//
@@ -1082,159 +741,48 @@ int main() {
// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK3-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined, i32 [[TMP8]], i32 [[TMP9]], ptr [[T_VAR1]])
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP10]], [[TMP11]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK3: omp.inner.for.end:
-// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
-// CHECK3-NEXT: store ptr [[T_VAR1]], ptr [[TMP12]], align 4
-// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// CHECK3-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// CHECK3-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// CHECK3-NEXT: ]
-// CHECK3: .omp.reduction.case1:
-// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
-// CHECK3-NEXT: store i32 [[ADD3]], ptr [[TMP0]], align 4
-// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK3: .omp.reduction.case2:
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
-// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK3: .omp.reduction.default:
-// CHECK3-NEXT: ret void
-//
-//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined
-// CHECK3-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i32 noundef [[DOTPREVIOUS_LB_:%.*]], i32 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[T_VAR:%.*]]) #[[ATTR1]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR_ADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[T_VAR1:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK3-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 4
-// CHECK3-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store ptr [[T_VAR]], ptr [[T_VAR_ADDR]], align 4
-// CHECK3-NEXT: [[TMP0:%.*]] = load ptr, ptr [[T_VAR_ADDR]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP1:%.*]] = load i32, ptr [[DOTPREVIOUS_LB__ADDR]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load i32, ptr [[DOTPREVIOUS_UB__ADDR]], align 4
-// CHECK3-NEXT: store i32 [[TMP1]], ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP2]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK3-NEXT: store i32 0, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK3-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK3-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 1
-// CHECK3-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK3: cond.true:
-// CHECK3-NEXT: br label [[COND_END:%.*]]
-// CHECK3: cond.false:
-// CHECK3-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: br label [[COND_END]]
-// CHECK3: cond.end:
-// CHECK3-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK3-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK3-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK3: omp.inner.for.cond:
// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK3-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK3-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK3: omp.inner.for.body:
-// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK3-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK3-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK3-NEXT: [[TMP12:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
+// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK3-NEXT: [[TMP10:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK3-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], [[TMP9]]
// CHECK3-NEXT: store i32 [[ADD3]], ptr [[T_VAR1]], align 4
// CHECK3-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK3: omp.body.continue:
// CHECK3-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK3: omp.inner.for.inc:
-// CHECK3-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP13]], 1
+// CHECK3-NEXT: [[TMP11:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK3-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP11]], 1
// CHECK3-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK3-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK3: omp.inner.for.end:
// CHECK3-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK3: omp.loop.exit:
-// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
-// CHECK3-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
-// CHECK3-NEXT: store ptr [[T_VAR1]], ptr [[TMP14]], align 4
-// CHECK3-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK3-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// CHECK3-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
+// CHECK3-NEXT: [[TMP12:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i32 0, i32 0
+// CHECK3-NEXT: store ptr [[T_VAR1]], ptr [[TMP12]], align 4
+// CHECK3-NEXT: [[TMP13:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], i32 1, i32 4, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// CHECK3-NEXT: switch i32 [[TMP13]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// CHECK3-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// CHECK3-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// CHECK3-NEXT: ]
// CHECK3: .omp.reduction.case1:
-// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK3-NEXT: [[TMP17:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
+// CHECK3-NEXT: [[TMP14:%.*]] = load i32, ptr [[TMP0]], align 4
+// CHECK3-NEXT: [[TMP15:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK3-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], [[TMP15]]
// CHECK3-NEXT: store i32 [[ADD5]], ptr [[TMP0]], align 4
-// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], ptr @.gomp_critical_user_.reduction.var)
+// CHECK3-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK3: .omp.reduction.case2:
-// CHECK3-NEXT: [[TMP18:%.*]] = load i32, ptr [[T_VAR1]], align 4
-// CHECK3-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
+// CHECK3-NEXT: [[TMP16:%.*]] = load i32, ptr [[T_VAR1]], align 4
+// CHECK3-NEXT: [[TMP17:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP16]] monotonic, align 4
// CHECK3-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK3: .omp.reduction.default:
// CHECK3-NEXT: ret void
//
//
-// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// CHECK3-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
-// CHECK3-NEXT: entry:
-// CHECK3-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 4
-// CHECK3-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 4
-// CHECK3-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 4
-// CHECK3-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 4
-// CHECK3-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 4
-// CHECK3-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 4
-// CHECK3-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i32 0, i32 0
-// CHECK3-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 4
-// CHECK3-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK3-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK3-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP8]], [[TMP9]]
-// CHECK3-NEXT: store i32 [[ADD]], ptr [[TMP7]], align 4
-// CHECK3-NEXT: ret void
-//
-//
// CHECK3-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}__Z5tmainIiET_v_l32.omp_outlined.omp.reduction.reduction_func
// CHECK3-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR3]] {
// CHECK3-NEXT: entry:
@@ -1270,7 +818,7 @@ int main() {
// CHECK9-NEXT: entry:
// CHECK9-NEXT: [[SIVAR_ADDR:%.*]] = alloca i64, align 8
// CHECK9-NEXT: store i64 [[SIVAR]], ptr [[SIVAR_ADDR]], align 8
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB4:[0-9]+]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined, ptr [[SIVAR_ADDR]])
+// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_teams(ptr @[[GLOB3:[0-9]+]], i32 1, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined, ptr [[SIVAR_ADDR]])
// CHECK9-NEXT: ret void
//
//
@@ -1288,6 +836,7 @@ int main() {
// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
+// CHECK9-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
// CHECK9-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
@@ -1321,169 +870,53 @@ int main() {
// CHECK9-NEXT: [[CMP2:%.*]] = icmp sle i32 [[TMP6]], [[TMP7]]
// CHECK9-NEXT: br i1 [[CMP2]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_COMB_LB]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_COMB_UB]], align 4
-// CHECK9-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64
-// CHECK9-NEXT: call void (ptr, i32, ptr, ...) @__kmpc_fork_call(ptr @[[GLOB4]], i32 3, ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp_outlined, i64 [[TMP9]], i64 [[TMP11]], ptr [[SIVAR1]])
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
-// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP13:%.*]] = load i32, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP12]], [[TMP13]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
-// CHECK9: omp.inner.for.end:
-// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
-// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
-// CHECK9-NEXT: [[TMP14:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK9-NEXT: store ptr [[SIVAR1]], ptr [[TMP14]], align 8
-// CHECK9-NEXT: [[TMP15:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3:[0-9]+]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK9-NEXT: switch i32 [[TMP15]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
-// CHECK9-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
-// CHECK9-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
-// CHECK9-NEXT: ]
-// CHECK9: .omp.reduction.case1:
-// CHECK9-NEXT: [[TMP16:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK9-NEXT: [[TMP17:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK9-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP16]], [[TMP17]]
-// CHECK9-NEXT: store i32 [[ADD3]], ptr [[TMP0]], align 4
-// CHECK9-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
-// CHECK9-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK9: .omp.reduction.case2:
-// CHECK9-NEXT: [[TMP18:%.*]] = load i32, ptr [[SIVAR1]], align 4
-// CHECK9-NEXT: [[TMP19:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP18]] monotonic, align 4
-// CHECK9-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
-// CHECK9: .omp.reduction.default:
-// CHECK9-NEXT: ret void
-//
-//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp_outlined
-// CHECK9-SAME: (ptr noalias noundef [[DOTGLOBAL_TID_:%.*]], ptr noalias noundef [[DOTBOUND_TID_:%.*]], i64 noundef [[DOTPREVIOUS_LB_:%.*]], i64 noundef [[DOTPREVIOUS_UB_:%.*]], ptr noundef nonnull align 4 dereferenceable(4) [[SIVAR:%.*]]) #[[ATTR2]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTGLOBAL_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTBOUND_TID__ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_LB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[DOTPREVIOUS_UB__ADDR:%.*]] = alloca i64, align 8
-// CHECK9-NEXT: [[SIVAR_ADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTOMP_IV:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[TMP:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_LB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_UB:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_STRIDE:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[DOTOMP_IS_LAST:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[SIVAR2:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[I:%.*]] = alloca i32, align 4
-// CHECK9-NEXT: [[REF_TMP:%.*]] = alloca [[CLASS_ANON_0:%.*]], align 8
-// CHECK9-NEXT: [[DOTOMP_REDUCTION_RED_LIST:%.*]] = alloca [1 x ptr], align 8
-// CHECK9-NEXT: store ptr [[DOTGLOBAL_TID_]], ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[DOTBOUND_TID_]], ptr [[DOTBOUND_TID__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_LB_]], ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: store i64 [[DOTPREVIOUS_UB_]], ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: store ptr [[SIVAR]], ptr [[SIVAR_ADDR]], align 8
-// CHECK9-NEXT: [[TMP0:%.*]] = load ptr, ptr [[SIVAR_ADDR]], align 8
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP1:%.*]] = load i64, ptr [[DOTPREVIOUS_LB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV:%.*]] = trunc i64 [[TMP1]] to i32
-// CHECK9-NEXT: [[TMP2:%.*]] = load i64, ptr [[DOTPREVIOUS_UB__ADDR]], align 8
-// CHECK9-NEXT: [[CONV1:%.*]] = trunc i64 [[TMP2]] to i32
-// CHECK9-NEXT: store i32 [[CONV]], ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[CONV1]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: store i32 1, ptr [[DOTOMP_STRIDE]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[DOTOMP_IS_LAST]], align 4
-// CHECK9-NEXT: store i32 0, ptr [[SIVAR2]], align 4
-// CHECK9-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTGLOBAL_TID__ADDR]], align 8
-// CHECK9-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP3]], align 4
-// CHECK9-NEXT: call void @__kmpc_for_static_init_4(ptr @[[GLOB2:[0-9]+]], i32 [[TMP4]], i32 34, ptr [[DOTOMP_IS_LAST]], ptr [[DOTOMP_LB]], ptr [[DOTOMP_UB]], ptr [[DOTOMP_STRIDE]], i32 1, i32 1)
-// CHECK9-NEXT: [[TMP5:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP:%.*]] = icmp sgt i32 [[TMP5]], 1
-// CHECK9-NEXT: br i1 [[CMP]], label [[COND_TRUE:%.*]], label [[COND_FALSE:%.*]]
-// CHECK9: cond.true:
-// CHECK9-NEXT: br label [[COND_END:%.*]]
-// CHECK9: cond.false:
-// CHECK9-NEXT: [[TMP6:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: br label [[COND_END]]
-// CHECK9: cond.end:
-// CHECK9-NEXT: [[COND:%.*]] = phi i32 [ 1, [[COND_TRUE]] ], [ [[TMP6]], [[COND_FALSE]] ]
-// CHECK9-NEXT: store i32 [[COND]], ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[TMP7:%.*]] = load i32, ptr [[DOTOMP_LB]], align 4
-// CHECK9-NEXT: store i32 [[TMP7]], ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND:%.*]]
-// CHECK9: omp.inner.for.cond:
// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[DOTOMP_UB]], align 4
-// CHECK9-NEXT: [[CMP3:%.*]] = icmp sle i32 [[TMP8]], [[TMP9]]
-// CHECK9-NEXT: br i1 [[CMP3]], label [[OMP_INNER_FOR_BODY:%.*]], label [[OMP_INNER_FOR_END:%.*]]
-// CHECK9: omp.inner.for.body:
-// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP10]], 1
+// CHECK9-NEXT: [[MUL:%.*]] = mul nsw i32 [[TMP8]], 1
// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 0, [[MUL]]
// CHECK9-NEXT: store i32 [[ADD]], ptr [[I]], align 4
-// CHECK9-NEXT: [[TMP11:%.*]] = load i32, ptr [[I]], align 4
-// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK9-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], [[TMP11]]
-// CHECK9-NEXT: store i32 [[ADD4]], ptr [[SIVAR2]], align 4
-// CHECK9-NEXT: [[TMP13:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
-// CHECK9-NEXT: store ptr [[SIVAR2]], ptr [[TMP13]], align 8
+// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[I]], align 4
+// CHECK9-NEXT: [[TMP10:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK9-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP10]], [[TMP9]]
+// CHECK9-NEXT: store i32 [[ADD3]], ptr [[SIVAR1]], align 4
+// CHECK9-NEXT: [[TMP11:%.*]] = getelementptr inbounds [[CLASS_ANON_0]], ptr [[REF_TMP]], i32 0, i32 0
+// CHECK9-NEXT: store ptr [[SIVAR1]], ptr [[TMP11]], align 8
// CHECK9-NEXT: call void @"_ZZZ4mainENK3$_0clEvENKUlvE_clEv"(ptr noundef nonnull align 8 dereferenceable(8) [[REF_TMP]])
// CHECK9-NEXT: br label [[OMP_BODY_CONTINUE:%.*]]
// CHECK9: omp.body.continue:
// CHECK9-NEXT: br label [[OMP_INNER_FOR_INC:%.*]]
// CHECK9: omp.inner.for.inc:
-// CHECK9-NEXT: [[TMP14:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
-// CHECK9-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP14]], 1
-// CHECK9-NEXT: store i32 [[ADD5]], ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[TMP12:%.*]] = load i32, ptr [[DOTOMP_IV]], align 4
+// CHECK9-NEXT: [[ADD4:%.*]] = add nsw i32 [[TMP12]], 1
+// CHECK9-NEXT: store i32 [[ADD4]], ptr [[DOTOMP_IV]], align 4
// CHECK9-NEXT: br label [[OMP_INNER_FOR_COND]]
// CHECK9: omp.inner.for.end:
// CHECK9-NEXT: br label [[OMP_LOOP_EXIT:%.*]]
// CHECK9: omp.loop.exit:
-// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB2]], i32 [[TMP4]])
-// CHECK9-NEXT: [[TMP15:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
-// CHECK9-NEXT: store ptr [[SIVAR2]], ptr [[TMP15]], align 8
-// CHECK9-NEXT: [[TMP16:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
-// CHECK9-NEXT: switch i32 [[TMP16]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
+// CHECK9-NEXT: call void @__kmpc_for_static_fini(ptr @[[GLOB1]], i32 [[TMP2]])
+// CHECK9-NEXT: [[TMP13:%.*]] = getelementptr inbounds [1 x ptr], ptr [[DOTOMP_REDUCTION_RED_LIST]], i64 0, i64 0
+// CHECK9-NEXT: store ptr [[SIVAR1]], ptr [[TMP13]], align 8
+// CHECK9-NEXT: [[TMP14:%.*]] = call i32 @__kmpc_reduce_nowait(ptr @[[GLOB2:[0-9]+]], i32 [[TMP2]], i32 1, i64 8, ptr [[DOTOMP_REDUCTION_RED_LIST]], ptr @{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp.reduction.reduction_func, ptr @.gomp_critical_user_.reduction.var)
+// CHECK9-NEXT: switch i32 [[TMP14]], label [[DOTOMP_REDUCTION_DEFAULT:%.*]] [
// CHECK9-NEXT: i32 1, label [[DOTOMP_REDUCTION_CASE1:%.*]]
// CHECK9-NEXT: i32 2, label [[DOTOMP_REDUCTION_CASE2:%.*]]
// CHECK9-NEXT: ]
// CHECK9: .omp.reduction.case1:
-// CHECK9-NEXT: [[TMP17:%.*]] = load i32, ptr [[TMP0]], align 4
-// CHECK9-NEXT: [[TMP18:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK9-NEXT: [[ADD6:%.*]] = add nsw i32 [[TMP17]], [[TMP18]]
-// CHECK9-NEXT: store i32 [[ADD6]], ptr [[TMP0]], align 4
-// CHECK9-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB3]], i32 [[TMP4]], ptr @.gomp_critical_user_.reduction.var)
+// CHECK9-NEXT: [[TMP15:%.*]] = load i32, ptr [[TMP0]], align 4
+// CHECK9-NEXT: [[TMP16:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK9-NEXT: [[ADD5:%.*]] = add nsw i32 [[TMP15]], [[TMP16]]
+// CHECK9-NEXT: store i32 [[ADD5]], ptr [[TMP0]], align 4
+// CHECK9-NEXT: call void @__kmpc_end_reduce_nowait(ptr @[[GLOB2]], i32 [[TMP2]], ptr @.gomp_critical_user_.reduction.var)
// CHECK9-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK9: .omp.reduction.case2:
-// CHECK9-NEXT: [[TMP19:%.*]] = load i32, ptr [[SIVAR2]], align 4
-// CHECK9-NEXT: [[TMP20:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP19]] monotonic, align 4
+// CHECK9-NEXT: [[TMP17:%.*]] = load i32, ptr [[SIVAR1]], align 4
+// CHECK9-NEXT: [[TMP18:%.*]] = atomicrmw add ptr [[TMP0]], i32 [[TMP17]] monotonic, align 4
// CHECK9-NEXT: br label [[DOTOMP_REDUCTION_DEFAULT]]
// CHECK9: .omp.reduction.default:
// CHECK9-NEXT: ret void
//
//
-// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp_outlined.omp.reduction.reduction_func
-// CHECK9-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR4:[0-9]+]] {
-// CHECK9-NEXT: entry:
-// CHECK9-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
-// CHECK9-NEXT: store ptr [[TMP0]], ptr [[DOTADDR]], align 8
-// CHECK9-NEXT: store ptr [[TMP1]], ptr [[DOTADDR1]], align 8
-// CHECK9-NEXT: [[TMP2:%.*]] = load ptr, ptr [[DOTADDR]], align 8
-// CHECK9-NEXT: [[TMP3:%.*]] = load ptr, ptr [[DOTADDR1]], align 8
-// CHECK9-NEXT: [[TMP4:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP3]], i64 0, i64 0
-// CHECK9-NEXT: [[TMP5:%.*]] = load ptr, ptr [[TMP4]], align 8
-// CHECK9-NEXT: [[TMP6:%.*]] = getelementptr inbounds [1 x ptr], ptr [[TMP2]], i64 0, i64 0
-// CHECK9-NEXT: [[TMP7:%.*]] = load ptr, ptr [[TMP6]], align 8
-// CHECK9-NEXT: [[TMP8:%.*]] = load i32, ptr [[TMP7]], align 4
-// CHECK9-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP5]], align 4
-// CHECK9-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP8]], [[TMP9]]
-// CHECK9-NEXT: store i32 [[ADD]], ptr [[TMP7]], align 4
-// CHECK9-NEXT: ret void
-//
-//
// CHECK9-LABEL: define {{[^@]+}}@{{__omp_offloading_[0-9a-z]+_[0-9a-z]+}}_main_l45.omp_outlined.omp.reduction.reduction_func
-// CHECK9-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR4]] {
+// CHECK9-SAME: (ptr noundef [[TMP0:%.*]], ptr noundef [[TMP1:%.*]]) #[[ATTR4:[0-9]+]] {
// CHECK9-NEXT: entry:
// CHECK9-NEXT: [[DOTADDR:%.*]] = alloca ptr, align 8
// CHECK9-NEXT: [[DOTADDR1:%.*]] = alloca ptr, align 8
diff --git a/clang/test/ParserOpenACC/parse-clauses.c b/clang/test/ParserOpenACC/parse-clauses.c
index b58b332ad324..b363a0cb1362 100644
--- a/clang/test/ParserOpenACC/parse-clauses.c
+++ b/clang/test/ParserOpenACC/parse-clauses.c
@@ -173,45 +173,37 @@ void DefaultClause() {
#pragma acc serial default), seq
for(;;){}
- // expected-error@+2{{expected identifier}}
- // expected-warning@+1{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+1{{expected identifier}}
#pragma acc serial default()
for(;;){}
- // expected-error@+3{{expected identifier}}
- // expected-warning@+2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial default() seq
for(;;){}
- // expected-error@+3{{expected identifier}}
- // expected-warning@+2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+2{{expected identifier}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial default(), seq
for(;;){}
- // expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
- // expected-warning@+1{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+1{{invalid value for 'default' clause; expected 'present' or 'none'}}
#pragma acc serial default(invalid)
for(;;){}
- // expected-error@+3{{invalid value for 'default' clause; expected 'present' or 'none'}}
- // expected-warning@+2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial default(auto) seq
for(;;){}
- // expected-error@+3{{invalid value for 'default' clause; expected 'present' or 'none'}}
- // expected-warning@+2{{OpenACC clause 'default' not yet implemented, clause ignored}}
+ // expected-error@+2{{invalid value for 'default' clause; expected 'present' or 'none'}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial default(invalid), seq
for(;;){}
- // expected-warning@+1{{OpenACC clause 'default' not yet implemented, clause ignored}}
#pragma acc serial default(none)
for(;;){}
- // expected-warning@+2{{OpenACC clause 'default' not yet implemented, clause ignored}}
// expected-warning@+1{{OpenACC clause 'seq' not yet implemented, clause ignored}}
#pragma acc serial default(present), seq
for(;;){}
diff --git a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
index 55c97c73e8b6..6a1feeb9bf53 100644
--- a/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
+++ b/clang/test/Sema/aarch64-incompat-sm-builtin-calls.c
@@ -1,6 +1,6 @@
// NOTE: Assertions have been autogenerated by utils/update_cc_test_checks.py
// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sve \
-// RUN: -target-feature +sme2 -target-feature +sve2 -target-feature +neon -fsyntax-only -verify %s
+// RUN: -target-feature +sme2 -target-feature +sve2 -target-feature +neon -Waarch64-sme-attributes -fsyntax-only -verify %s
// REQUIRES: aarch64-registered-target
@@ -33,6 +33,7 @@ svuint32_t incompat_sve_sm(svbool_t pg, svuint32_t a, int16_t b) __arm_streaming
return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
}
+// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
__arm_locally_streaming svuint32_t incompat_sve_ls(svbool_t pg, svuint32_t a, int64_t b) {
// expected-warning@+1 {{builtin call has undefined behaviour when called from a streaming function}}
return __builtin_sve_svld1_gather_u32base_index_u32(pg, a, b);
@@ -48,6 +49,7 @@ svuint32_t incompat_sve2_sm(svbool_t pg, svuint32_t a, int64_t b) __arm_streamin
return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
}
+// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
__arm_locally_streaming svuint32_t incompat_sve2_ls(svbool_t pg, svuint32_t a, int64_t b) {
// expected-warning@+1 {{builtin call has undefined behaviour when called from a streaming function}}
return __builtin_sve_svldnt1_gather_u32base_index_u32(pg, a, b);
@@ -68,6 +70,7 @@ svfloat64_t streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) __arm_
return svadd_n_f64_m(pg, a, b);
}
+// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
__arm_locally_streaming svfloat64_t locally_streaming_caller_sve(svbool_t pg, svfloat64_t a, float64_t b) {
// expected-no-warning
return svadd_n_f64_m(pg, a, b);
@@ -83,6 +86,7 @@ svint16_t streaming_caller_sve2(svint16_t op1, svint16_t op2) __arm_streaming {
return svmul_lane_s16(op1, op2, 0);
}
+// expected-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
__arm_locally_streaming svint16_t locally_streaming_caller_sve2(svint16_t op1, svint16_t op2) {
// expected-no-warning
return svmul_lane_s16(op1, op2, 0);
diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c
index bfc8768c3f36..12de16509ccb 100644
--- a/clang/test/Sema/aarch64-sme-func-attrs.c
+++ b/clang/test/Sema/aarch64-sme-func-attrs.c
@@ -1,5 +1,5 @@
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -fsyntax-only -verify %s
-// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -fsyntax-only -verify=expected-cpp -x c++ %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify %s
+// RUN: %clang_cc1 -triple aarch64-none-linux-gnu -target-feature +sme2 -target-feature +sve -Waarch64-sme-attributes -fsyntax-only -verify=expected-cpp -x c++ %s
// Valid attributes
@@ -496,3 +496,135 @@ void fmv_caller() {
just_fine();
incompatible_locally_streaming();
}
+
+void sme_streaming_with_vl_arg(__SVInt8_t a) __arm_streaming { }
+
+__SVInt8_t sme_streaming_returns_vl(void) __arm_streaming { __SVInt8_t r; return r; }
+
+void sme_streaming_compatible_with_vl_arg(__SVInt8_t a) __arm_streaming_compatible { }
+
+__SVInt8_t sme_streaming_compatible_returns_vl(void) __arm_streaming_compatible { __SVInt8_t r; return r; }
+
+void sme_no_streaming_with_vl_arg(__SVInt8_t a) { }
+
+__SVInt8_t sme_no_streaming_returns_vl(void) { __SVInt8_t r; return r; }
+
+// expected-warning@+2 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
+// expected-cpp-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
+__arm_locally_streaming void sme_locally_streaming_with_vl_arg(__SVInt8_t a) { }
+
+// expected-warning@+2 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
+// expected-cpp-warning@+1 {{passing/returning a VL-dependent argument to/from a __arm_locally_streaming function. The streaming and non-streaming vector lengths may be different}}
+__arm_locally_streaming __SVInt8_t sme_locally_streaming_returns_vl(void) { __SVInt8_t r; return r; }
+
+void sme_no_streaming_calling_streaming_with_vl_args() {
+ __SVInt8_t a;
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ sme_streaming_with_vl_arg(a);
+}
+
+void sme_no_streaming_calling_streaming_with_return_vl() {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ __SVInt8_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_calling_non_streaming_with_vl_args(void) __arm_streaming {
+ __SVInt8_t a;
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ sme_no_streaming_with_vl_arg(a);
+}
+
+void sme_streaming_calling_non_streaming_with_return_vl(void) __arm_streaming {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ __SVInt8_t r = sme_no_streaming_returns_vl();
+}
+
+void sme_no_streaming_calling_streaming_with_vl_args_param(__SVInt8_t arg, void (*sc)( __SVInt8_t arg) __arm_streaming) {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ sc(arg);
+}
+
+__SVInt8_t sme_no_streaming_calling_streaming_return_vl_param(__SVInt8_t (*s)(void) __arm_streaming) {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ return s();
+}
+
+void sme_streaming_compatible_calling_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ sme_streaming_with_vl_arg(arg);
+}
+
+void sme_streaming_compatible_calling_sme_streaming_return_vl(void) __arm_streaming_compatible {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ __SVInt8_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_compatible_calling_no_streaming_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ sme_no_streaming_with_vl_arg(arg);
+}
+
+void sme_streaming_compatible_calling_no_sme_streaming_return_vl(void) __arm_streaming_compatible {
+ // expected-warning@+2 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ // expected-cpp-warning@+1 {{passing a VL-dependent argument to/from a function that has a different streaming-mode. The streaming and non-streaming vector lengths may be different}}
+ __SVInt8_t r = sme_no_streaming_returns_vl();
+}
+
+void sme_streaming_calling_streaming(__SVInt8_t arg, void (*s)( __SVInt8_t arg) __arm_streaming) __arm_streaming {
+ s(arg);
+}
+
+__SVInt8_t sme_streaming_calling_streaming_return_vl(__SVInt8_t (*s)(void) __arm_streaming) __arm_streaming {
+ return s();
+}
+
+void sme_streaming_calling_streaming_with_vl_args(__SVInt8_t a) __arm_streaming {
+ sme_streaming_with_vl_arg(a);
+}
+
+void sme_streaming_calling_streaming_with_return_vl(void) __arm_streaming {
+ __SVInt8_t r = sme_streaming_returns_vl();
+}
+
+void sme_streaming_calling_streaming_compatible_with_vl_args(__SVInt8_t a) __arm_streaming {
+ sme_streaming_compatible_with_vl_arg(a);
+}
+
+void sme_streaming_calling_streaming_compatible_with_return_vl(void) __arm_streaming {
+ __SVInt8_t r = sme_streaming_compatible_returns_vl();
+}
+
+void sme_no_streaming_calling_streaming_compatible_with_vl_args() {
+ __SVInt8_t a;
+ sme_streaming_compatible_with_vl_arg(a);
+}
+
+void sme_no_streaming_calling_streaming_compatible_with_return_vl() {
+ __SVInt8_t r = sme_streaming_compatible_returns_vl();
+}
+
+void sme_no_streaming_calling_non_streaming_compatible_with_vl_args() {
+ __SVInt8_t a;
+ sme_no_streaming_with_vl_arg(a);
+}
+
+void sme_no_streaming_calling_non_streaming_compatible_with_return_vl() {
+ __SVInt8_t r = sme_no_streaming_returns_vl();
+}
+
+void sme_streaming_compatible_calling_streaming_compatible_with_vl_args(__SVInt8_t arg) __arm_streaming_compatible {
+ sme_streaming_compatible_with_vl_arg(arg);
+}
+
+void sme_streaming_compatible_calling_streaming_compatible_with_return_vl(void) __arm_streaming_compatible {
+ __SVInt8_t r = sme_streaming_compatible_returns_vl();
+}
diff --git a/clang/test/SemaCXX/type-traits.cpp b/clang/test/SemaCXX/type-traits.cpp
index e29763714341..421d3007d27f 100644
--- a/clang/test/SemaCXX/type-traits.cpp
+++ b/clang/test/SemaCXX/type-traits.cpp
@@ -1759,6 +1759,7 @@ void is_layout_compatible(int n)
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(!__is_layout_compatible(int[n], int[n]));
// expected-error@-1 {{variable length arrays are not supported in '__is_layout_compatible'}}
+ // expected-error@-2 {{variable length arrays are not supported in '__is_layout_compatible'}}
static_assert(__is_layout_compatible(int&, int&));
static_assert(!__is_layout_compatible(int&, char&));
static_assert(__is_layout_compatible(void(int), void(int)));
diff --git a/clang/test/SemaOpenACC/compute-construct-ast.cpp b/clang/test/SemaOpenACC/compute-construct-ast.cpp
index 55c080838a18..e632522f877b 100644
--- a/clang/test/SemaOpenACC/compute-construct-ast.cpp
+++ b/clang/test/SemaOpenACC/compute-construct-ast.cpp
@@ -12,14 +12,16 @@ void NormalFunc() {
// CHECK-LABEL: NormalFunc
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+ // CHECK-NEXT: default(none)
// CHECK-NEXT: CompoundStmt
-#pragma acc parallel
+#pragma acc parallel default(none)
{
#pragma acc parallel
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+ // CHECK-NEXT: default(present)
// CHECK-NEXT: CompoundStmt
-#pragma acc parallel
+#pragma acc parallel default(present)
{}
}
// FIXME: Add a test once we have clauses for this.
@@ -50,12 +52,12 @@ void NormalFunc() {
template<typename T>
void TemplFunc() {
-#pragma acc parallel
+#pragma acc parallel default(none)
{
typename T::type I;
}
-#pragma acc serial
+#pragma acc serial default(present)
{
typename T::type I;
}
@@ -72,10 +74,12 @@ void TemplFunc() {
// CHECK-NEXT: FunctionDecl
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+ // CHECK-NEXT: default(none)
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}} I 'typename T::type'
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}serial
+ // CHECK-NEXT: default(present)
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}} I 'typename T::type'
@@ -91,10 +95,12 @@ void TemplFunc() {
// CHECK-NEXT: CXXRecord
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}parallel
+ // CHECK-NEXT: default(none)
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}} I 'typename S::type':'int'
// CHECK-NEXT: OpenACCComputeConstruct {{.*}}serial
+ // CHECK-NEXT: default(present)
// CHECK-NEXT: CompoundStmt
// CHECK-NEXT: DeclStmt
// CHECK-NEXT: VarDecl{{.*}} I 'typename S::type':'int'
diff --git a/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp b/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
new file mode 100644
index 000000000000..bd8010344502
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-clause-ast.cpp
@@ -0,0 +1,74 @@
+// RUN: %clang_cc1 %s -fopenacc -ast-dump | FileCheck %s
+
+// Test this with PCH.
+// RUN: %clang_cc1 %s -fopenacc -emit-pch -o %t %s
+// RUN: %clang_cc1 %s -fopenacc -include-pch %t -ast-dump-all | FileCheck %s
+
+#ifndef PCH_HELPER
+#define PCH_HELPER
+void NormalFunc() {
+ // CHECK: FunctionDecl{{.*}}NormalFunc
+ // CHECK-NEXT: CompoundStmt
+#pragma acc parallel default(none)
+ while(true);
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+ // CHECK-NEXT: default(none)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+
+#pragma acc serial default(present)
+ while(true);
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}serial
+ // CHECK-NEXT: default(present)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+}
+
+template<typename T>
+void TemplFunc() {
+ // CHECK: FunctionTemplateDecl{{.*}}TemplFunc
+ // CHECK-NEXT: TemplateTypeParmDecl
+
+ // Match the prototype:
+ // CHECK-NEXT: FunctionDecl{{.*}}TemplFunc
+ // CHECK-NEXT: CompoundStmt
+
+#pragma acc kernels default(none)
+ while(true);
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
+ // CHECK-NEXT: default(none)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+
+#pragma acc parallel default(present)
+ while(true);
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+ // CHECK-NEXT: default(present)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+
+ // Match the instantiation:
+ // CHECK: FunctionDecl{{.*}}TemplFunc{{.*}}implicit_instantiation
+ // CHECK-NEXT: TemplateArgument type 'int'
+ // CHECK-NEXT: BuiltinType
+ // CHECK-NEXT: CompoundStmt
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}kernels
+ // CHECK-NEXT: default(none)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+ // CHECK-NEXT: OpenACCComputeConstruct{{.*}}parallel
+ // CHECK-NEXT: default(present)
+ // CHECK-NEXT: WhileStmt
+ // CHECK-NEXT: CXXBoolLiteralExpr
+ // CHECK-NEXT: NullStmt
+}
+
+void Instantiate() {
+ TemplFunc<int>();
+}
+#endif
diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.c b/clang/test/SemaOpenACC/compute-construct-default-clause.c
new file mode 100644
index 000000000000..b1235fcca1f6
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.c
@@ -0,0 +1,55 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+void SingleOnly() {
+ #pragma acc parallel default(none)
+ while(0);
+
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'serial' directive}}
+ // expected-note@+1{{previous clause is here}}
+ #pragma acc serial default(present) seq default(none)
+ while(0);
+
+ // expected-warning@+5{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+4{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'kernels' directive}}
+ // expected-note@+1{{previous clause is here}}
+ #pragma acc kernels seq default(present) seq default(none) seq
+ while(0);
+
+ // expected-warning@+6{{OpenACC construct 'parallel loop' not yet implemented}}
+ // expected-warning@+5{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+4{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+2{{OpenACC clause 'default' not yet implemented}}
+ // expected-warning@+1{{OpenACC clause 'default' not yet implemented}}
+ #pragma acc parallel loop seq default(present) seq default(none) seq
+ while(0);
+
+ // expected-warning@+3{{OpenACC construct 'serial loop' not yet implemented}}
+ // expected-warning@+2{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+1{{expected '('}}
+ #pragma acc serial loop seq default seq default(none) seq
+ while(0);
+
+ // expected-warning@+2{{OpenACC construct 'kernels loop' not yet implemented}}
+ // expected-warning@+1{{OpenACC clause 'default' not yet implemented}}
+ #pragma acc kernels loop default(none)
+ while(0);
+
+ // expected-warning@+2{{OpenACC construct 'data' not yet implemented}}
+ // expected-warning@+1{{OpenACC clause 'default' not yet implemented}}
+ #pragma acc data default(none)
+ while(0);
+
+ // expected-warning@+2{{OpenACC construct 'loop' not yet implemented}}
+ // expected-error@+1{{OpenACC 'default' clause is not valid on 'loop' directive}}
+ #pragma acc loop default(none)
+ while(0);
+
+ // expected-warning@+2{{OpenACC construct 'wait' not yet implemented}}
+ // expected-error@+1{{OpenACC 'default' clause is not valid on 'wait' directive}}
+ #pragma acc wait default(none)
+ while(0);
+}
diff --git a/clang/test/SemaOpenACC/compute-construct-default-clause.cpp b/clang/test/SemaOpenACC/compute-construct-default-clause.cpp
new file mode 100644
index 000000000000..2c3e711ffd08
--- /dev/null
+++ b/clang/test/SemaOpenACC/compute-construct-default-clause.cpp
@@ -0,0 +1,39 @@
+// RUN: %clang_cc1 %s -fopenacc -verify
+
+template<typename T>
+void SingleOnly() {
+ #pragma acc parallel default(none)
+ while(false);
+
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'parallel' directive}}
+ // expected-note@+1{{previous clause is here}}
+ #pragma acc parallel default(present) seq default(none)
+ while(false);
+
+ // expected-warning@+5{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+4{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'serial' directive}}
+ // expected-note@+1{{previous clause is here}}
+ #pragma acc serial seq default(present) seq default(none) seq
+ while(false);
+
+ // expected-warning@+5{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+4{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+2{{OpenACC 'default' clause cannot appear more than once on a 'kernels' directive}}
+ // expected-note@+1{{previous clause is here}}
+ #pragma acc kernels seq default(present) seq default(none) seq
+ while(false);
+
+ // expected-warning@+3{{OpenACC clause 'seq' not yet implemented}}
+ // expected-warning@+2{{OpenACC clause 'seq' not yet implemented}}
+ // expected-error@+1{{expected '('}}
+ #pragma acc parallel seq default(none) seq default seq
+ while(false);
+}
+
+void Instantiate() {
+ SingleOnly<int>();
+}
diff --git a/clang/test/SemaTemplate/alias-templates.cpp b/clang/test/SemaTemplate/alias-templates.cpp
index 8d7cc6118610..ab5cad72faf1 100644
--- a/clang/test/SemaTemplate/alias-templates.cpp
+++ b/clang/test/SemaTemplate/alias-templates.cpp
@@ -236,6 +236,29 @@ namespace PR14858 {
void test_q(int (&a)[5]) { Q<B, B, B>().f<B, B>(&a); }
}
+namespace PR84220 {
+
+template <class...> class list {};
+
+template <int> struct foo_impl {
+ template <class> using f = int;
+};
+
+template <class... xs>
+using foo = typename foo_impl<sizeof...(xs)>::template f<xs...>;
+
+// We call getFullyPackExpandedSize at the annotation stage
+// before parsing the ellipsis next to the foo<xs>. This happens before
+// a PackExpansionType is formed for foo<xs>.
+// getFullyPackExpandedSize shouldn't determine the value here. Otherwise,
+// foo_impl<sizeof...(xs)> would lose its dependency despite the template
+// arguments being unsubstituted.
+template <class... xs> using test = list<foo<xs>...>;
+
+test<int> a;
+
+}
+
namespace redecl {
template<typename> using A = int;
template<typename = void> using A = int;
diff --git a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
index 6977623a0816..dcab9bfaeabc 100644
--- a/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
+++ b/clang/test/SemaTemplate/ms-function-specialization-class-scope.cpp
@@ -1,6 +1,7 @@
-// RUN: %clang_cc1 -fms-extensions -fsyntax-only -Wno-unused-value -verify %s
-// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -Wno-unused-value -verify %s
+// RUN: %clang_cc1 -fms-extensions -fsyntax-only -verify %s
+// RUN: %clang_cc1 -fms-extensions -fdelayed-template-parsing -fsyntax-only -verify %s
+// expected-no-diagnostics
class A {
public:
template<class U> A(U p) {}
@@ -75,42 +76,3 @@ struct S {
int f<0>(int);
};
}
-
-namespace UsesThis {
- template<typename T>
- struct A {
- int x;
-
- template<typename U>
- static void f();
-
- template<>
- void f<int>() {
- this->x; // expected-error {{invalid use of 'this' outside of a non-static member function}}
- x; // expected-error {{invalid use of member 'x' in static member function}}
- A::x; // expected-error {{invalid use of member 'x' in static member function}}
- +x; // expected-error {{invalid use of member 'x' in static member function}}
- +A::x; // expected-error {{invalid use of member 'x' in static member function}}
- }
-
- template<typename U>
- void g();
-
- template<>
- void g<int>() {
- this->x;
- x;
- A::x;
- +x;
- +A::x;
- }
-
- template<typename U>
- static auto h() -> A*;
-
- template<>
- auto h<int>() -> decltype(this); // expected-error {{'this' cannot be used in a static member function declaration}}
- };
-
- template struct A<int>; // expected-note 2{{in instantiation of}}
-}
diff --git a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
index 73e695a67093..a1879fc7712d 100644
--- a/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
+++ b/clang/tools/clang-linker-wrapper/ClangLinkerWrapper.cpp
@@ -1448,9 +1448,9 @@ getDeviceInput(const ArgList &Args) {
StringSaver Saver(Alloc);
// Try to extract device code from the linker input files.
- DenseMap<OffloadFile::TargetID, SmallVector<OffloadFile>> InputFiles;
- DenseMap<OffloadFile::TargetID, DenseMap<StringRef, Symbol>> Syms;
bool WholeArchive = Args.hasArg(OPT_wholearchive_flag) ? true : false;
+ SmallVector<OffloadFile> ObjectFilesToExtract;
+ SmallVector<OffloadFile> ArchiveFilesToExtract;
for (const opt::Arg *Arg : Args.filtered(
OPT_INPUT, OPT_library, OPT_whole_archive, OPT_no_whole_archive)) {
if (Arg->getOption().matches(OPT_whole_archive) ||
@@ -1486,50 +1486,87 @@ getDeviceInput(const ArgList &Args) {
if (Error Err = extractOffloadBinaries(Buffer, Binaries))
return std::move(Err);
- // We only extract archive members that are needed.
- bool IsArchive = identify_magic(Buffer.getBuffer()) == file_magic::archive;
- bool Extracted = true;
- while (Extracted) {
- Extracted = false;
- for (OffloadFile &Binary : Binaries) {
- // If the binary was previously extracted it will be set to null.
- if (!Binary.getBinary())
+ for (auto &OffloadFile : Binaries) {
+ if (identify_magic(Buffer.getBuffer()) == file_magic::archive &&
+ !WholeArchive)
+ ArchiveFilesToExtract.emplace_back(std::move(OffloadFile));
+ else
+ ObjectFilesToExtract.emplace_back(std::move(OffloadFile));
+ }
+ }
+
+ // Link all standard input files and update the list of symbols.
+ DenseMap<OffloadFile::TargetID, SmallVector<OffloadFile>> InputFiles;
+ DenseMap<OffloadFile::TargetID, DenseMap<StringRef, Symbol>> Syms;
+ for (OffloadFile &Binary : ObjectFilesToExtract) {
+ if (!Binary.getBinary())
+ continue;
+
+ SmallVector<OffloadFile::TargetID> CompatibleTargets = {Binary};
+ for (const auto &[ID, Input] : InputFiles)
+ if (object::areTargetsCompatible(Binary, ID))
+ CompatibleTargets.emplace_back(ID);
+
+ for (const auto &[Index, ID] : llvm::enumerate(CompatibleTargets)) {
+ Expected<bool> ExtractOrErr = getSymbols(
+ Binary.getBinary()->getImage(), Binary.getBinary()->getOffloadKind(),
+ /*IsArchive=*/false, Saver, Syms[ID]);
+ if (!ExtractOrErr)
+ return ExtractOrErr.takeError();
+
+ // If another target needs this binary it must be copied instead.
+ if (Index == CompatibleTargets.size() - 1)
+ InputFiles[ID].emplace_back(std::move(Binary));
+ else
+ InputFiles[ID].emplace_back(Binary.copy());
+ }
+ }
+
+ // Archive members only extract if they define needed symbols. We do this
+ // after every regular input file so that libraries may be included out of
+ // order. This follows 'ld.lld' semantics which are more lenient.
+ bool Extracted = true;
+ while (Extracted) {
+ Extracted = false;
+ for (OffloadFile &Binary : ArchiveFilesToExtract) {
+ // If the binary was previously extracted it will be set to null.
+ if (!Binary.getBinary())
+ continue;
+
+ SmallVector<OffloadFile::TargetID> CompatibleTargets = {Binary};
+ for (const auto &[ID, Input] : InputFiles)
+ if (object::areTargetsCompatible(Binary, ID))
+ CompatibleTargets.emplace_back(ID);
+
+ for (const auto &[Index, ID] : llvm::enumerate(CompatibleTargets)) {
+ // Only extract an if we have an an object matching this target.
+ if (!InputFiles.count(ID))
continue;
- SmallVector<OffloadFile::TargetID> CompatibleTargets = {Binary};
- for (const auto &[ID, Input] : InputFiles)
- if (object::areTargetsCompatible(Binary, ID))
- CompatibleTargets.emplace_back(ID);
-
- for (const auto &[Index, ID] : llvm::enumerate(CompatibleTargets)) {
- // Only extract an if we have an an object matching this target.
- if (IsArchive && !WholeArchive && !InputFiles.count(ID))
- continue;
-
- Expected<bool> ExtractOrErr = getSymbols(
- Binary.getBinary()->getImage(),
- Binary.getBinary()->getOffloadKind(), IsArchive, Saver, Syms[ID]);
- if (!ExtractOrErr)
- return ExtractOrErr.takeError();
-
- Extracted = !WholeArchive && *ExtractOrErr;
-
- // Skip including the file if it is an archive that does not resolve
- // any symbols.
- if (IsArchive && !WholeArchive && !Extracted)
- continue;
-
- // If another target needs this binary it must be copied instead.
- if (Index == CompatibleTargets.size() - 1)
- InputFiles[ID].emplace_back(std::move(Binary));
- else
- InputFiles[ID].emplace_back(Binary.copy());
- }
+ Expected<bool> ExtractOrErr =
+ getSymbols(Binary.getBinary()->getImage(),
+ Binary.getBinary()->getOffloadKind(), /*IsArchive=*/true,
+ Saver, Syms[ID]);
+ if (!ExtractOrErr)
+ return ExtractOrErr.takeError();
- // If we extracted any files we need to check all the symbols again.
- if (Extracted)
- break;
+ Extracted = *ExtractOrErr;
+
+ // Skip including the file if it is an archive that does not resolve
+ // any symbols.
+ if (!Extracted)
+ continue;
+
+ // If another target needs this binary it must be copied instead.
+ if (Index == CompatibleTargets.size() - 1)
+ InputFiles[ID].emplace_back(std::move(Binary));
+ else
+ InputFiles[ID].emplace_back(Binary.copy());
}
+
+ // If we extracted any files we need to check all the symbols again.
+ if (Extracted)
+ break;
}
}
diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp
index 71450f433cec..f312a9e21158 100644
--- a/clang/unittests/Format/FormatTest.cpp
+++ b/clang/unittests/Format/FormatTest.cpp
@@ -1865,6 +1865,13 @@ TEST_F(FormatTest, UnderstandsMacros) {
verifyFormat("MACRO(co_return##something)");
verifyFormat("#define A x:");
+
+ verifyFormat("#define Foo(Bar) {#Bar}", "#define Foo(Bar) \\\n"
+ " { \\\n"
+ " #Bar \\\n"
+ " }");
+ verifyFormat("#define Foo(Bar) {#Bar}", "#define Foo(Bar) \\\n"
+ " { #Bar }");
}
TEST_F(FormatTest, ShortBlocksInMacrosDontMergeWithCodeAfterMacro) {
@@ -11033,7 +11040,7 @@ TEST_F(FormatTest, UnderstandsTemplateParameters) {
verifyFormat("some_templated_type<decltype([](int i) { return i; })>");
verifyFormat("#define FOO(typeName, realClass) \\\n"
- " { #typeName, foo<FooType>(new foo<realClass>(#typeName)) }",
+ " {#typeName, foo<FooType>(new foo<realClass>(#typeName))}",
getLLVMStyleWithColumns(60));
}
diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp
index 5ba5e0fbd16f..c3153cf6b16f 100644
--- a/clang/unittests/Format/TokenAnnotatorTest.cpp
+++ b/clang/unittests/Format/TokenAnnotatorTest.cpp
@@ -1769,6 +1769,10 @@ TEST_F(TokenAnnotatorTest, UnderstandsFunctionDeclarationNames) {
EXPECT_TOKEN(Tokens[3], tok::identifier, TT_Unknown);
EXPECT_TOKEN(Tokens[4], tok::l_paren, TT_FunctionTypeLParen);
+ Tokens = annotate("void instanceof();");
+ ASSERT_EQ(Tokens.size(), 6u);
+ EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
+
Tokens = annotate("int iso_time(time_t);");
ASSERT_EQ(Tokens.size(), 7u) << Tokens;
EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName);
@@ -1933,14 +1937,20 @@ TEST_F(TokenAnnotatorTest, UnderstandHashInMacro) {
" #Bar \\\n"
" }");
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
- EXPECT_BRACE_KIND(Tokens[6], BK_Block);
- EXPECT_BRACE_KIND(Tokens[9], BK_Block);
+ EXPECT_BRACE_KIND(Tokens[6], BK_BracedInit);
+ EXPECT_BRACE_KIND(Tokens[9], BK_BracedInit);
Tokens = annotate("#define Foo(Bar) \\\n"
" { #Bar }");
ASSERT_EQ(Tokens.size(), 11u) << Tokens;
- EXPECT_BRACE_KIND(Tokens[6], BK_Block);
- EXPECT_BRACE_KIND(Tokens[9], BK_Block);
+ EXPECT_BRACE_KIND(Tokens[6], BK_BracedInit);
+ EXPECT_BRACE_KIND(Tokens[9], BK_BracedInit);
+
+ Tokens = annotate("#define FOO(typeName, realClass) \\\n"
+ " {#typeName, foo<Foo>(new foo<realClass>(#typeName))}");
+ ASSERT_EQ(Tokens.size(), 29u) << Tokens;
+ EXPECT_BRACE_KIND(Tokens[8], BK_BracedInit);
+ EXPECT_BRACE_KIND(Tokens[27], BK_BracedInit);
}
TEST_F(TokenAnnotatorTest, UnderstandsAttributeMacros) {
@@ -2822,6 +2832,13 @@ TEST_F(TokenAnnotatorTest, BraceKind) {
EXPECT_BRACE_KIND(Tokens[0], BK_Block);
EXPECT_BRACE_KIND(Tokens[7], BK_BracedInit);
EXPECT_BRACE_KIND(Tokens[21], BK_BracedInit);
+
+ Tokens =
+ annotate("#define SCOP_STAT(NAME, DESC) \\\n"
+ " {\"polly\", #NAME, \"Number of rejected regions: \" DESC}");
+ ASSERT_EQ(Tokens.size(), 18u) << Tokens;
+ EXPECT_BRACE_KIND(Tokens[8], BK_BracedInit);
+ EXPECT_BRACE_KIND(Tokens[16], BK_BracedInit);
}
TEST_F(TokenAnnotatorTest, StreamOperator) {
diff --git a/flang/include/flang/Frontend/PreprocessorOptions.h b/flang/include/flang/Frontend/PreprocessorOptions.h
index b2e9ac0e963b..13a91ee9a184 100644
--- a/flang/include/flang/Frontend/PreprocessorOptions.h
+++ b/flang/include/flang/Frontend/PreprocessorOptions.h
@@ -56,6 +56,9 @@ struct PreprocessorOptions {
// -fno-reformat: Emit cooked character stream as -E output
bool noReformat{false};
+ // -dM: Show macro definitions with -dM -E
+ bool showMacros{false};
+
void addMacroDef(llvm::StringRef name) {
macros.emplace_back(std::string(name), false);
}
diff --git a/flang/include/flang/Parser/parsing.h b/flang/include/flang/Parser/parsing.h
index e80d8f724ac8..4d329c189cb8 100644
--- a/flang/include/flang/Parser/parsing.h
+++ b/flang/include/flang/Parser/parsing.h
@@ -15,6 +15,7 @@
#include "parse-tree.h"
#include "provenance.h"
#include "flang/Common/Fortran-features.h"
+#include "flang/Parser/preprocessor.h"
#include "llvm/Support/raw_ostream.h"
#include <optional>
#include <string>
@@ -59,6 +60,7 @@ public:
const SourceFile *Prescan(const std::string &path, Options);
void EmitPreprocessedSource(
llvm::raw_ostream &, bool lineDirectives = true) const;
+ void EmitPreprocessorMacros(llvm::raw_ostream &) const;
void DumpCookedChars(llvm::raw_ostream &) const;
void DumpProvenance(llvm::raw_ostream &) const;
void DumpParsingLog(llvm::raw_ostream &) const;
@@ -83,6 +85,7 @@ private:
const char *finalRestingPlace_{nullptr};
std::optional<Program> parseTree_;
ParsingLog log_;
+ Preprocessor preprocessor_{allCooked_.allSources()};
};
} // namespace Fortran::parser
#endif // FORTRAN_PARSER_PARSING_H_
diff --git a/flang/lib/Parser/preprocessor.h b/flang/include/flang/Parser/preprocessor.h
index b61f1577727b..630d5273d427 100644
--- a/flang/lib/Parser/preprocessor.h
+++ b/flang/include/flang/Parser/preprocessor.h
@@ -15,9 +15,10 @@
// performed, so that special compiler command options &/or source file name
// extensions for preprocessing will not be necessary.
-#include "token-sequence.h"
#include "flang/Parser/char-block.h"
#include "flang/Parser/provenance.h"
+#include "flang/Parser/token-sequence.h"
+#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <list>
#include <stack>
@@ -39,7 +40,7 @@ public:
Definition(const std::string &predefined, AllSources &);
bool isFunctionLike() const { return isFunctionLike_; }
- std::size_t argumentCount() const { return argumentCount_; }
+ std::size_t argumentCount() const { return argNames_.size(); }
bool isVariadic() const { return isVariadic_; }
bool isDisabled() const { return isDisabled_; }
bool isPredefined() const { return isPredefined_; }
@@ -49,15 +50,21 @@ public:
TokenSequence Apply(const std::vector<TokenSequence> &args, Prescanner &);
+ void Print(llvm::raw_ostream &out, const char *macroName = "") const;
+
private:
static TokenSequence Tokenize(const std::vector<std::string> &argNames,
const TokenSequence &token, std::size_t firstToken, std::size_t tokens);
+ // For a given token, return the index of the argument to which the token
+ // corresponds, or `argumentCount` if the token does not correspond to any
+ // argument.
+ std::size_t GetArgumentIndex(const CharBlock &token) const;
bool isFunctionLike_{false};
- std::size_t argumentCount_{0};
bool isVariadic_{false};
bool isDisabled_{false};
bool isPredefined_{false};
+ std::vector<std::string> argNames_;
TokenSequence replacement_;
};
@@ -89,6 +96,8 @@ public:
// Implements a preprocessor directive.
void Directive(const TokenSequence &, Prescanner &);
+ void PrintMacros(llvm::raw_ostream &out) const;
+
private:
enum class IsElseActive { No, Yes };
enum class CanDeadElseAppear { No, Yes };
diff --git a/flang/lib/Parser/token-sequence.h b/flang/include/flang/Parser/token-sequence.h
index 3df403d41e63..849240d8ec62 100644
--- a/flang/lib/Parser/token-sequence.h
+++ b/flang/include/flang/Parser/token-sequence.h
@@ -42,8 +42,8 @@ public:
}
TokenSequence(TokenSequence &&that)
: start_{std::move(that.start_)}, nextStart_{that.nextStart_},
- char_{std::move(that.char_)}, provenances_{
- std::move(that.provenances_)} {}
+ char_{std::move(that.char_)},
+ provenances_{std::move(that.provenances_)} {}
TokenSequence(const std::string &s, Provenance p) { Put(s, p); }
TokenSequence &operator=(const TokenSequence &that) {
diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp
index c830c7af2462..8ce6ab7baf48 100644
--- a/flang/lib/Frontend/CompilerInvocation.cpp
+++ b/flang/lib/Frontend/CompilerInvocation.cpp
@@ -772,6 +772,7 @@ static void parsePreprocessorArgs(Fortran::frontend::PreprocessorOptions &opts,
opts.noReformat = args.hasArg(clang::driver::options::OPT_fno_reformat);
opts.noLineDirectives = args.hasArg(clang::driver::options::OPT_P);
+ opts.showMacros = args.hasArg(clang::driver::options::OPT_dM);
}
/// Parses all semantic related arguments and populates the variables
diff --git a/flang/lib/Frontend/FrontendActions.cpp b/flang/lib/Frontend/FrontendActions.cpp
index 849b3c8e4dc0..8f251997ed40 100644
--- a/flang/lib/Frontend/FrontendActions.cpp
+++ b/flang/lib/Frontend/FrontendActions.cpp
@@ -399,7 +399,9 @@ void PrintPreprocessedAction::executeAction() {
// Format or dump the prescanner's output
CompilerInstance &ci = this->getInstance();
- if (ci.getInvocation().getPreprocessorOpts().noReformat) {
+ if (ci.getInvocation().getPreprocessorOpts().showMacros) {
+ ci.getParsing().EmitPreprocessorMacros(outForPP);
+ } else if (ci.getInvocation().getPreprocessorOpts().noReformat) {
ci.getParsing().DumpCookedChars(outForPP);
} else {
ci.getParsing().EmitPreprocessedSource(
diff --git a/flang/lib/Parser/parsing.cpp b/flang/lib/Parser/parsing.cpp
index a55d33bf6b91..43a898ff120c 100644
--- a/flang/lib/Parser/parsing.cpp
+++ b/flang/lib/Parser/parsing.cpp
@@ -7,10 +7,10 @@
//===----------------------------------------------------------------------===//
#include "flang/Parser/parsing.h"
-#include "preprocessor.h"
#include "prescan.h"
#include "type-parsers.h"
#include "flang/Parser/message.h"
+#include "flang/Parser/preprocessor.h"
#include "flang/Parser/provenance.h"
#include "flang/Parser/source.h"
#include "llvm/Support/raw_ostream.h"
@@ -60,20 +60,19 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
}
}
- Preprocessor preprocessor{allSources};
if (!options.predefinitions.empty()) {
- preprocessor.DefineStandardMacros();
+ preprocessor_.DefineStandardMacros();
for (const auto &predef : options.predefinitions) {
if (predef.second) {
- preprocessor.Define(predef.first, *predef.second);
+ preprocessor_.Define(predef.first, *predef.second);
} else {
- preprocessor.Undefine(predef.first);
+ preprocessor_.Undefine(predef.first);
}
}
}
currentCooked_ = &allCooked_.NewCookedSource();
Prescanner prescanner{
- messages_, *currentCooked_, preprocessor, options.features};
+ messages_, *currentCooked_, preprocessor_, options.features};
prescanner.set_fixedForm(options.isFixedForm)
.set_fixedFormColumnLimit(options.fixedFormColumns)
.AddCompilerDirectiveSentinel("dir$");
@@ -87,7 +86,7 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
if (options.features.IsEnabled(LanguageFeature::CUDA)) {
prescanner.AddCompilerDirectiveSentinel("$cuf");
prescanner.AddCompilerDirectiveSentinel("@cuf");
- preprocessor.Define("_CUDA", "1");
+ preprocessor_.Define("_CUDA", "1");
}
ProvenanceRange range{allSources.AddIncludedFile(
*sourceFile, ProvenanceRange{}, options.isModuleFile)};
@@ -107,6 +106,10 @@ const SourceFile *Parsing::Prescan(const std::string &path, Options options) {
return sourceFile;
}
+void Parsing::EmitPreprocessorMacros(llvm::raw_ostream &out) const {
+ preprocessor_.PrintMacros(out);
+}
+
void Parsing::EmitPreprocessedSource(
llvm::raw_ostream &out, bool lineDirectives) const {
const std::string *sourcePath{nullptr};
diff --git a/flang/lib/Parser/preprocessor.cpp b/flang/lib/Parser/preprocessor.cpp
index 515b8f62daf9..2fba28b0c0c7 100644
--- a/flang/lib/Parser/preprocessor.cpp
+++ b/flang/lib/Parser/preprocessor.cpp
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "preprocessor.h"
+#include "flang/Parser/preprocessor.h"
+
#include "prescan.h"
#include "flang/Common/idioms.h"
#include "flang/Parser/characters.h"
@@ -21,6 +22,7 @@
#include <optional>
#include <set>
#include <utility>
+#include <vector>
namespace Fortran::parser {
@@ -31,8 +33,7 @@ Definition::Definition(
Definition::Definition(const std::vector<std::string> &argNames,
const TokenSequence &repl, std::size_t firstToken, std::size_t tokens,
bool isVariadic)
- : isFunctionLike_{true},
- argumentCount_(argNames.size()), isVariadic_{isVariadic},
+ : isFunctionLike_{true}, isVariadic_{isVariadic}, argNames_{argNames},
replacement_{Tokenize(argNames, repl, firstToken, tokens)} {}
Definition::Definition(const std::string &predefined, AllSources &sources)
@@ -46,6 +47,37 @@ bool Definition::set_isDisabled(bool disable) {
return was;
}
+void Definition::Print(llvm::raw_ostream &out, const char *macroName) const {
+ if (!isFunctionLike_) {
+ // If it's not a function-like macro, then just print the replacement.
+ out << ' ' << replacement_.ToString();
+ return;
+ }
+
+ size_t argCount{argumentCount()};
+
+ out << '(';
+ for (size_t i{0}; i != argCount; ++i) {
+ if (i != 0) {
+ out << ", ";
+ }
+ out << argNames_[i];
+ }
+ if (isVariadic_) {
+ out << ", ...";
+ }
+ out << ") ";
+
+ for (size_t i{0}, e{replacement_.SizeInTokens()}; i != e; ++i) {
+ std::string tok{replacement_.TokenAt(i).ToString()};
+ if (size_t idx{GetArgumentIndex(tok)}; idx < argCount) {
+ out << argNames_[idx];
+ } else {
+ out << tok;
+ }
+ }
+}
+
static bool IsLegalIdentifierStart(const CharBlock &cpl) {
return cpl.size() > 0 && IsLegalIdentifierStart(cpl[0]);
}
@@ -73,6 +105,13 @@ TokenSequence Definition::Tokenize(const std::vector<std::string> &argNames,
return result;
}
+std::size_t Definition::GetArgumentIndex(const CharBlock &token) const {
+ if (token.size() >= 2 && token[0] == '~') {
+ return static_cast<size_t>(token[1] - 'A');
+ }
+ return argumentCount();
+}
+
static TokenSequence Stringify(
const TokenSequence &tokens, AllSources &allSources) {
TokenSequence result;
@@ -159,7 +198,7 @@ TokenSequence Definition::Apply(
continue;
}
if (bytes == 2 && token[0] == '~') { // argument substitution
- std::size_t index = token[1] - 'A';
+ std::size_t index{GetArgumentIndex(token)};
if (index >= args.size()) {
continue;
}
@@ -202,8 +241,8 @@ TokenSequence Definition::Apply(
Provenance commaProvenance{
prescanner.preprocessor().allSources().CompilerInsertionProvenance(
',')};
- for (std::size_t k{argumentCount_}; k < args.size(); ++k) {
- if (k > argumentCount_) {
+ for (std::size_t k{argumentCount()}; k < args.size(); ++k) {
+ if (k > argumentCount()) {
result.Put(","s, commaProvenance);
}
result.Put(args[k]);
@@ -212,7 +251,7 @@ TokenSequence Definition::Apply(
j + 2 < tokens && replacement_.TokenAt(j + 1).OnlyNonBlank() == '(' &&
parenthesesNesting == 0) {
parenthesesNesting = 1;
- skipping = args.size() == argumentCount_;
+ skipping = args.size() == argumentCount();
++j;
} else {
if (parenthesesNesting > 0) {
@@ -713,6 +752,21 @@ void Preprocessor::Directive(const TokenSequence &dir, Prescanner &prescanner) {
}
}
+void Preprocessor::PrintMacros(llvm::raw_ostream &out) const {
+ // std::set is ordered. Use that to print the macros in an
+ // alphabetical order.
+ std::set<std::string> macroNames;
+ for (const auto &[name, _] : definitions_) {
+ macroNames.insert(name.ToString());
+ }
+
+ for (const std::string &name : macroNames) {
+ out << "#define " << name;
+ definitions_.at(name).Print(out, name.c_str());
+ out << '\n';
+ }
+}
+
CharBlock Preprocessor::SaveTokenAsName(const CharBlock &t) {
names_.push_back(t.ToString());
return {names_.back().data(), names_.back().size()};
diff --git a/flang/lib/Parser/prescan.cpp b/flang/lib/Parser/prescan.cpp
index e9b23172ed2e..96db3955299f 100644
--- a/flang/lib/Parser/prescan.cpp
+++ b/flang/lib/Parser/prescan.cpp
@@ -7,12 +7,12 @@
//===----------------------------------------------------------------------===//
#include "prescan.h"
-#include "preprocessor.h"
-#include "token-sequence.h"
#include "flang/Common/idioms.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/message.h"
+#include "flang/Parser/preprocessor.h"
#include "flang/Parser/source.h"
+#include "flang/Parser/token-sequence.h"
#include "llvm/Support/raw_ostream.h"
#include <cstddef>
#include <cstring>
diff --git a/flang/lib/Parser/prescan.h b/flang/lib/Parser/prescan.h
index 7442b5d22633..581980001bcc 100644
--- a/flang/lib/Parser/prescan.h
+++ b/flang/lib/Parser/prescan.h
@@ -16,11 +16,11 @@
// fixed form character literals on truncated card images, file
// inclusion, and driving the Fortran source preprocessor.
-#include "token-sequence.h"
#include "flang/Common/Fortran-features.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/message.h"
#include "flang/Parser/provenance.h"
+#include "flang/Parser/token-sequence.h"
#include <bitset>
#include <optional>
#include <string>
diff --git a/flang/lib/Parser/token-sequence.cpp b/flang/lib/Parser/token-sequence.cpp
index 799d13a42366..d0254ecd5aae 100644
--- a/flang/lib/Parser/token-sequence.cpp
+++ b/flang/lib/Parser/token-sequence.cpp
@@ -6,7 +6,8 @@
//
//===----------------------------------------------------------------------===//
-#include "token-sequence.h"
+#include "flang/Parser/token-sequence.h"
+
#include "prescan.h"
#include "flang/Parser/characters.h"
#include "flang/Parser/message.h"
diff --git a/flang/test/Driver/driver-help-hidden.f90 b/flang/test/Driver/driver-help-hidden.f90
index 48f48f5384fd..35b188ad3a9e 100644
--- a/flang/test/Driver/driver-help-hidden.f90
+++ b/flang/test/Driver/driver-help-hidden.f90
@@ -21,6 +21,7 @@
! CHECK-NEXT: -ccc-print-phases Dump list of actions to perform
! CHECK-NEXT: -cpp Enable predefined and command line preprocessor macros
! CHECK-NEXT: -c Only run preprocess, compile, and assemble steps
+! CHECK-NEXT: -dM Print macro definitions in -E mode instead of normal output
! CHECK-NEXT: -dumpmachine Display the compiler's target processor
! CHECK-NEXT: -dumpversion Display the version of the compiler
! CHECK-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
diff --git a/flang/test/Driver/driver-help.f90 b/flang/test/Driver/driver-help.f90
index 38f74395a678..d4dab55f40e8 100644
--- a/flang/test/Driver/driver-help.f90
+++ b/flang/test/Driver/driver-help.f90
@@ -17,6 +17,7 @@
! HELP-NEXT: -### Print (but do not run) the commands to run for this compilation
! HELP-NEXT: -cpp Enable predefined and command line preprocessor macros
! HELP-NEXT: -c Only run preprocess, compile, and assemble steps
+! HELP-NEXT: -dM Print macro definitions in -E mode instead of normal output
! HELP-NEXT: -dumpmachine Display the compiler's target processor
! HELP-NEXT: -dumpversion Display the version of the compiler
! HELP-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
@@ -155,6 +156,7 @@
! HELP-FC1-NEXT:OPTIONS:
! HELP-FC1-NEXT: -cpp Enable predefined and command line preprocessor macros
! HELP-FC1-NEXT: --dependent-lib=<value> Add dependent library
+! HELP-FC1-NEXT: -dM Print macro definitions in -E mode instead of normal output
! HELP-FC1-NEXT: -D <macro>=<value> Define <macro> to <value> (or 1 if <value> omitted)
! HELP-FC1-NEXT: -emit-fir Build the parse tree, then lower it to FIR
! HELP-FC1-NEXT: -emit-hlfir Build the parse tree, then lower it to HLFIR
diff --git a/flang/test/Preprocessing/show-macros1.F90 b/flang/test/Preprocessing/show-macros1.F90
new file mode 100644
index 000000000000..8e3d59a7849f
--- /dev/null
+++ b/flang/test/Preprocessing/show-macros1.F90
@@ -0,0 +1,14 @@
+! RUN: %flang -dM -E -o - %s | FileCheck %s
+
+! Check the default macros. Omit certain ones such as __LINE__
+! or __FILE__, or target-specific ones, like __x86_64__.
+
+! Macros are printed in the alphabetical order.
+
+! CHECK: #define __DATE__
+! CHECK: #define __TIME__
+! CHECK: #define __flang__
+! CHECK: #define __flang_major__
+! CHECK: #define __flang_minor__
+! CHECK: #define __flang_patchlevel__
+
diff --git a/flang/test/Preprocessing/show-macros2.F90 b/flang/test/Preprocessing/show-macros2.F90
new file mode 100644
index 000000000000..baf52ba8161f
--- /dev/null
+++ b/flang/test/Preprocessing/show-macros2.F90
@@ -0,0 +1,6 @@
+! RUN: %flang -DFOO -DBAR=FOO -dM -E -o - %s | FileCheck %s
+
+! Check command line definitions
+
+! CHECK: #define BAR FOO
+! CHECK: #define FOO 1
diff --git a/flang/test/Preprocessing/show-macros3.F90 b/flang/test/Preprocessing/show-macros3.F90
new file mode 100644
index 000000000000..951a1ec5ba16
--- /dev/null
+++ b/flang/test/Preprocessing/show-macros3.F90
@@ -0,0 +1,9 @@
+! RUN: %flang -dM -E -o - %s | FileCheck %s
+
+! Variadic macro
+#define FOO1(X, Y, ...) bar(bar(X, Y), __VA_ARGS__)
+! CHECK: #define FOO1(X, Y, ...) bar(bar(X, Y), __VA_ARGS__)
+
+! Macro with an unused parameter
+#define FOO2(X, Y, Z) (X + Z)
+! CHECK: #define FOO2(X, Y, Z) (X + Z)
diff --git a/libc/docs/gpu/building.rst b/libc/docs/gpu/building.rst
index 6d94134a407d..d3e64c6d4243 100644
--- a/libc/docs/gpu/building.rst
+++ b/libc/docs/gpu/building.rst
@@ -33,7 +33,8 @@ The simplest way to build the GPU libc is to use the existing LLVM runtimes
support. This will automatically handle bootstrapping an up-to-date ``clang``
compiler and using it to build the C library. The following CMake invocation
will instruct it to build the ``libc`` runtime targeting both AMD and NVIDIA
-GPUs.
+GPUs. The ``LIBC_GPU_BUILD`` option can also be enabled to add the relevant
+arguments automatically.
.. code-block:: sh
@@ -234,6 +235,10 @@ standard runtime build.
This flag controls whether or not the libc build will generate its own
headers. This must always be on when targeting the GPU.
+**LIBC_GPU_BUILD**:BOOL
+ Shorthand for enabling GPU support. Equivalent to enabling support for both
+ AMDGPU and NVPTX builds for ``libc``.
+
**LIBC_GPU_TEST_ARCHITECTURE**:STRING
Sets the architecture used to build the GPU tests for, such as ``gfx90a`` or
``sm_80`` for AMD and NVIDIA GPUs respectively. The default behavior is to
diff --git a/libc/hdr/CMakeLists.txt b/libc/hdr/CMakeLists.txt
index 4ca7db5e98d6..5a1acd9d17ab 100644
--- a/libc/hdr/CMakeLists.txt
+++ b/libc/hdr/CMakeLists.txt
@@ -38,5 +38,5 @@ add_proxy_header_library(
fenv_macros.h
FULL_BUILD_DEPENDS
libc.include.llvm-libc-macros.fenv_macros
- libc.incude.fenv
+ libc.include.fenv
)
diff --git a/libcxx/docs/Status/Cxx2cIssues.csv b/libcxx/docs/Status/Cxx2cIssues.csv
index b402fb835bc1..008f7418ab9c 100644
--- a/libcxx/docs/Status/Cxx2cIssues.csv
+++ b/libcxx/docs/Status/Cxx2cIssues.csv
@@ -63,4 +63,5 @@
"`4054 <https://wg21.link/LWG4054>`__","Repeating a ``repeat_view`` should repeat the view","Tokyo March 2024","","","|ranges|"
"","","","","",""
"`3343 <https://wg21.link/LWG3343>`__","Ordering of calls to ``unlock()`` and ``notify_all()`` in Effects element of ``notify_all_at_thread_exit()`` should be reversed","Not Yet Adopted","|Complete|","16.0",""
+"XXXX","","The sys_info range should be affected by save","Not Yet Adopted","|Complete|","19.0"
"","","","","",""
diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt
index 3cbca9ff4bd1..d4e8c196a9a8 100644
--- a/libcxx/include/CMakeLists.txt
+++ b/libcxx/include/CMakeLists.txt
@@ -291,6 +291,7 @@ set(files
__chrono/parser_std_format_spec.h
__chrono/statically_widen.h
__chrono/steady_clock.h
+ __chrono/sys_info.h
__chrono/system_clock.h
__chrono/time_point.h
__chrono/time_zone.h
@@ -862,6 +863,7 @@ set(files
__utility/pair.h
__utility/piecewise_construct.h
__utility/priority_tag.h
+ __utility/private_constructor_tag.h
__utility/rel_ops.h
__utility/small_buffer.h
__utility/swap.h
diff --git a/libcxx/include/__algorithm/simd_utils.h b/libcxx/include/__algorithm/simd_utils.h
index 989a1957987e..8d540ae2cce8 100644
--- a/libcxx/include/__algorithm/simd_utils.h
+++ b/libcxx/include/__algorithm/simd_utils.h
@@ -27,7 +27,7 @@ _LIBCPP_PUSH_MACROS
#include <__undef_macros>
// TODO: Find out how altivec changes things and allow vectorizations there too.
-#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_CLANG_VER) && _LIBCPP_CLANG_VER >= 1700 && !defined(__ALTIVEC__)
+#if _LIBCPP_STD_VER >= 14 && defined(_LIBCPP_CLANG_VER) && !defined(__ALTIVEC__)
# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 1
#else
# define _LIBCPP_HAS_ALGORITHM_VECTOR_UTILS 0
diff --git a/libcxx/include/__chrono/leap_second.h b/libcxx/include/__chrono/leap_second.h
index 4e67cc2d6527..557abc15ff18 100644
--- a/libcxx/include/__chrono/leap_second.h
+++ b/libcxx/include/__chrono/leap_second.h
@@ -22,6 +22,7 @@
# include <__compare/ordering.h>
# include <__compare/three_way_comparable.h>
# include <__config>
+# include <__utility/private_constructor_tag.h>
# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -35,9 +36,8 @@ namespace chrono {
class leap_second {
public:
- struct __constructor_tag;
[[nodiscard]]
- _LIBCPP_HIDE_FROM_ABI explicit constexpr leap_second(__constructor_tag&&, sys_seconds __date, seconds __value)
+ _LIBCPP_HIDE_FROM_ABI explicit constexpr leap_second(__private_constructor_tag, sys_seconds __date, seconds __value)
: __date_(__date), __value_(__value) {}
_LIBCPP_HIDE_FROM_ABI leap_second(const leap_second&) = default;
diff --git a/libcxx/include/__chrono/sys_info.h b/libcxx/include/__chrono/sys_info.h
new file mode 100644
index 000000000000..794d22f2ccc1
--- /dev/null
+++ b/libcxx/include/__chrono/sys_info.h
@@ -0,0 +1,51 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
+
+#ifndef _LIBCPP___CHRONO_SYS_INFO_H
+#define _LIBCPP___CHRONO_SYS_INFO_H
+
+#include <version>
+// Enable the contents of the header only when libc++ was built with experimental features enabled.
+#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+# include <__chrono/duration.h>
+# include <__chrono/system_clock.h>
+# include <__chrono/time_point.h>
+# include <__config>
+# include <string>
+
+# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+# endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+# if _LIBCPP_STD_VER >= 20
+
+namespace chrono {
+
+struct sys_info {
+ sys_seconds begin;
+ sys_seconds end;
+ seconds offset;
+ minutes save;
+ string abbrev;
+};
+
+} // namespace chrono
+
+# endif //_LIBCPP_STD_VER >= 20
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+
+#endif // _LIBCPP___CHRONO_SYS_INFO_H
diff --git a/libcxx/include/__chrono/time_zone.h b/libcxx/include/__chrono/time_zone.h
index 7d97327a6c8e..8e30034b799a 100644
--- a/libcxx/include/__chrono/time_zone.h
+++ b/libcxx/include/__chrono/time_zone.h
@@ -16,6 +16,9 @@
// Enable the contents of the header only when libc++ was built with experimental features enabled.
#if !defined(_LIBCPP_HAS_NO_INCOMPLETE_TZDB)
+# include <__chrono/duration.h>
+# include <__chrono/sys_info.h>
+# include <__chrono/system_clock.h>
# include <__compare/strong_order.h>
# include <__config>
# include <__memory/unique_ptr.h>
@@ -55,10 +58,18 @@ public:
_LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI string_view name() const noexcept { return __name(); }
+ template <class _Duration>
+ _LIBCPP_NODISCARD_EXT _LIBCPP_HIDE_FROM_ABI sys_info get_info(const sys_time<_Duration>& __time) const {
+ return __get_info(chrono::time_point_cast<seconds>(__time));
+ }
+
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __impl& __implementation() const noexcept { return *__impl_; }
private:
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view __name() const noexcept;
+
+ [[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info __get_info(sys_seconds __time) const;
+
unique_ptr<__impl> __impl_;
};
diff --git a/libcxx/include/__chrono/time_zone_link.h b/libcxx/include/__chrono/time_zone_link.h
index 17e915d2677a..c76ddeff9f96 100644
--- a/libcxx/include/__chrono/time_zone_link.h
+++ b/libcxx/include/__chrono/time_zone_link.h
@@ -18,6 +18,7 @@
# include <__compare/strong_order.h>
# include <__config>
+# include <__utility/private_constructor_tag.h>
# include <string>
# include <string_view>
@@ -37,9 +38,8 @@ namespace chrono {
class time_zone_link {
public:
- struct __constructor_tag;
_LIBCPP_NODISCARD_EXT
- _LIBCPP_HIDE_FROM_ABI explicit time_zone_link(__constructor_tag&&, string_view __name, string_view __target)
+ _LIBCPP_HIDE_FROM_ABI explicit time_zone_link(__private_constructor_tag, string_view __name, string_view __target)
: __name_{__name}, __target_{__target} {}
_LIBCPP_HIDE_FROM_ABI time_zone_link(time_zone_link&&) = default;
diff --git a/libcxx/include/__config b/libcxx/include/__config
index 8550b1da4a27..d98b54926bbe 100644
--- a/libcxx/include/__config
+++ b/libcxx/include/__config
@@ -44,8 +44,8 @@
// Warn if a compiler version is used that is not supported anymore
// LLVM RELEASE Update the minimum compiler versions
# if defined(_LIBCPP_CLANG_VER)
-# if _LIBCPP_CLANG_VER < 1600
-# warning "Libc++ only supports Clang 16 and later"
+# if _LIBCPP_CLANG_VER < 1700
+# warning "Libc++ only supports Clang 17 and later"
# endif
# elif defined(_LIBCPP_APPLE_CLANG_VER)
# if _LIBCPP_APPLE_CLANG_VER < 1500
diff --git a/libcxx/include/__locale b/libcxx/include/__locale
index fab87f0d6a27..36ac099d650e 100644
--- a/libcxx/include/__locale
+++ b/libcxx/include/__locale
@@ -16,6 +16,7 @@
#include <__mutex/once_flag.h>
#include <__type_traits/make_unsigned.h>
#include <__utility/no_destroy.h>
+#include <__utility/private_constructor_tag.h>
#include <cctype>
#include <clocale>
#include <cstdint>
@@ -97,8 +98,7 @@ private:
template <class>
friend struct __no_destroy;
- struct __private_tag {};
- _LIBCPP_HIDE_FROM_ABI explicit locale(__private_tag, __imp* __loc) : __locale_(__loc) {}
+ _LIBCPP_HIDE_FROM_ABI explicit locale(__private_constructor_tag, __imp* __loc) : __locale_(__loc) {}
void __install_ctor(const locale&, facet*, long);
static locale& __global();
@@ -1248,10 +1248,10 @@ extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<char, char
#ifndef _LIBCPP_HAS_NO_WIDE_CHARACTERS
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<wchar_t, char, mbstate_t>;
#endif
-extern template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
- codecvt_byname<char16_t, char, mbstate_t>; // deprecated in C++20
-extern template class _LIBCPP_DEPRECATED_IN_CXX20 _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS
- codecvt_byname<char32_t, char, mbstate_t>; // deprecated in C++20
+extern template class _LIBCPP_DEPRECATED_IN_CXX20
+_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<char16_t, char, mbstate_t>; // deprecated in C++20
+extern template class _LIBCPP_DEPRECATED_IN_CXX20
+_LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<char32_t, char, mbstate_t>; // deprecated in C++20
#ifndef _LIBCPP_HAS_NO_CHAR8_T
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<char16_t, char8_t, mbstate_t>; // C++20
extern template class _LIBCPP_EXTERN_TEMPLATE_TYPE_VIS codecvt_byname<char32_t, char8_t, mbstate_t>; // C++20
diff --git a/libcxx/include/__stop_token/stop_callback.h b/libcxx/include/__stop_token/stop_callback.h
index 9e5b0338d466..7b526820f98a 100644
--- a/libcxx/include/__stop_token/stop_callback.h
+++ b/libcxx/include/__stop_token/stop_callback.h
@@ -21,6 +21,7 @@
#include <__type_traits/is_nothrow_constructible.h>
#include <__utility/forward.h>
#include <__utility/move.h>
+#include <__utility/private_constructor_tag.h>
#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
# pragma GCC system_header
@@ -49,13 +50,13 @@ public:
requires constructible_from<_Callback, _Cb>
_LIBCPP_HIDE_FROM_ABI explicit stop_callback(const stop_token& __st,
_Cb&& __cb) noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
- : stop_callback(__private_tag{}, __st.__state_, std::forward<_Cb>(__cb)) {}
+ : stop_callback(__private_constructor_tag{}, __st.__state_, std::forward<_Cb>(__cb)) {}
template <class _Cb>
requires constructible_from<_Callback, _Cb>
_LIBCPP_HIDE_FROM_ABI explicit stop_callback(stop_token&& __st,
_Cb&& __cb) noexcept(is_nothrow_constructible_v<_Callback, _Cb>)
- : stop_callback(__private_tag{}, std::move(__st.__state_), std::forward<_Cb>(__cb)) {}
+ : stop_callback(__private_constructor_tag{}, std::move(__st.__state_), std::forward<_Cb>(__cb)) {}
_LIBCPP_HIDE_FROM_ABI ~stop_callback() {
if (__state_) {
@@ -74,10 +75,8 @@ private:
friend __stop_callback_base;
- struct __private_tag {};
-
template <class _StatePtr, class _Cb>
- _LIBCPP_HIDE_FROM_ABI explicit stop_callback(__private_tag, _StatePtr&& __state, _Cb&& __cb) noexcept(
+ _LIBCPP_HIDE_FROM_ABI explicit stop_callback(__private_constructor_tag, _StatePtr&& __state, _Cb&& __cb) noexcept(
is_nothrow_constructible_v<_Callback, _Cb>)
: __stop_callback_base([](__stop_callback_base* __cb_base) noexcept {
// stop callback is supposed to only be called once
diff --git a/libcxx/include/__utility/private_constructor_tag.h b/libcxx/include/__utility/private_constructor_tag.h
new file mode 100644
index 000000000000..462cab48c9ed
--- /dev/null
+++ b/libcxx/include/__utility/private_constructor_tag.h
@@ -0,0 +1,28 @@
+// -*- C++ -*-
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef _LIBCPP__UTILITY_PRIVATE_CONSTRUCTOR_TAG_H
+#define _LIBCPP__UTILITY_PRIVATE_CONSTRUCTOR_TAG_H
+
+#include <__config>
+
+#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
+# pragma GCC system_header
+#endif
+
+_LIBCPP_BEGIN_NAMESPACE_STD
+
+// This tag allows defining non-standard exposition-only constructors while
+// preventing users from being able to use them, since this reserved-name tag
+// needs to be used.
+struct __private_constructor_tag {};
+
+_LIBCPP_END_NAMESPACE_STD
+
+#endif // _LIBCPP__UTILITY_PRIVATE_CONSTRUCTOR_TAG_H
diff --git a/libcxx/include/chrono b/libcxx/include/chrono
index 8fdc30a3624d..5eddd050196d 100644
--- a/libcxx/include/chrono
+++ b/libcxx/include/chrono
@@ -724,6 +724,15 @@ const time_zone* current_zone()
const tzdb& reload_tzdb(); // C++20
string remote_version(); // C++20
+// [time.zone.info], information classes
+struct sys_info { // C++20
+ sys_seconds begin;
+ sys_seconds end;
+ seconds offset;
+ minutes save;
+ string abbrev;
+};
+
// 25.10.5, class time_zone // C++20
enum class choose {earliest, latest};
class time_zone {
@@ -733,6 +742,9 @@ class time_zone {
// unspecified additional constructors
string_view name() const noexcept;
+
+ template<class Duration>
+ sys_info get_info(const sys_time<Duration>& st) const;
};
bool operator==(const time_zone& x, const time_zone& y) noexcept; // C++20
strong_ordering operator<=>(const time_zone& x, const time_zone& y) noexcept; // C++20
@@ -881,6 +893,7 @@ constexpr chrono::year operator ""y(unsigned lo
#include <__chrono/month_weekday.h>
#include <__chrono/monthday.h>
#include <__chrono/steady_clock.h>
+#include <__chrono/sys_info.h>
#include <__chrono/system_clock.h>
#include <__chrono/time_point.h>
#include <__chrono/weekday.h>
diff --git a/libcxx/include/libcxx.imp b/libcxx/include/libcxx.imp
index a79e8fedbdac..6c77ba8343c6 100644
--- a/libcxx/include/libcxx.imp
+++ b/libcxx/include/libcxx.imp
@@ -288,6 +288,7 @@
{ include: [ "<__chrono/parser_std_format_spec.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/statically_widen.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/steady_clock.h>", "private", "<chrono>", "public" ] },
+ { include: [ "<__chrono/sys_info.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/system_clock.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/time_point.h>", "private", "<chrono>", "public" ] },
{ include: [ "<__chrono/time_zone.h>", "private", "<chrono>", "public" ] },
diff --git a/libcxx/include/module.modulemap b/libcxx/include/module.modulemap
index e1637907b3ec..9c0f0ddd20c9 100644
--- a/libcxx/include/module.modulemap
+++ b/libcxx/include/module.modulemap
@@ -1167,6 +1167,9 @@ module std_private_chrono_time_zone [system] {
module std_private_chrono_time_zone_link [system] {
header "__chrono/time_zone_link.h"
}
+module std_private_chrono_sys_info [system] {
+ header "__chrono/sys_info.h"
+}
module std_private_chrono_system_clock [system] {
header "__chrono/system_clock.h"
export std_private_chrono_time_point
@@ -2087,18 +2090,19 @@ module std_private_utility_pair [system] {
export std_private_type_traits_is_nothrow_move_assignable
export std_private_utility_pair_fwd
}
-module std_private_utility_pair_fwd [system] { header "__fwd/pair.h" }
-module std_private_utility_piecewise_construct [system] { header "__utility/piecewise_construct.h" }
-module std_private_utility_priority_tag [system] { header "__utility/priority_tag.h" }
-module std_private_utility_rel_ops [system] { header "__utility/rel_ops.h" }
-module std_private_utility_small_buffer [system] { header "__utility/small_buffer.h" }
-module std_private_utility_swap [system] {
+module std_private_utility_pair_fwd [system] { header "__fwd/pair.h" }
+module std_private_utility_piecewise_construct [system] { header "__utility/piecewise_construct.h" }
+module std_private_utility_priority_tag [system] { header "__utility/priority_tag.h" }
+module std_private_utility_private_constructor_tag [system] { header "__utility/private_constructor_tag.h" }
+module std_private_utility_rel_ops [system] { header "__utility/rel_ops.h" }
+module std_private_utility_small_buffer [system] { header "__utility/small_buffer.h" }
+module std_private_utility_swap [system] {
header "__utility/swap.h"
export std_private_type_traits_is_swappable
}
-module std_private_utility_to_underlying [system] { header "__utility/to_underlying.h" }
-module std_private_utility_unreachable [system] { header "__utility/unreachable.h" }
+module std_private_utility_to_underlying [system] { header "__utility/to_underlying.h" }
+module std_private_utility_unreachable [system] { header "__utility/unreachable.h" }
-module std_private_variant_monostate [system] { header "__variant/monostate.h" }
+module std_private_variant_monostate [system] { header "__variant/monostate.h" }
-module std_private_vector_fwd [system] { header "__fwd/vector.h" }
+module std_private_vector_fwd [system] { header "__fwd/vector.h" }
diff --git a/libcxx/modules/std/chrono.inc b/libcxx/modules/std/chrono.inc
index e14228043d3b..575e6347aecc 100644
--- a/libcxx/modules/std/chrono.inc
+++ b/libcxx/modules/std/chrono.inc
@@ -212,10 +212,12 @@ export namespace std {
// [time.zone.exception], exception classes
using std::chrono::ambiguous_local_time;
using std::chrono::nonexistent_local_time;
+# endif // if 0
// [time.zone.info], information classes
using std::chrono::sys_info;
+# if 0
// [time.zone.timezone], class time_zone
using std::chrono::choose;
# endif // if 0
diff --git a/libcxx/src/CMakeLists.txt b/libcxx/src/CMakeLists.txt
index 16ccb80ba332..208500ec14fc 100644
--- a/libcxx/src/CMakeLists.txt
+++ b/libcxx/src/CMakeLists.txt
@@ -334,8 +334,6 @@ endif()
if (LIBCXX_ENABLE_LOCALIZATION AND LIBCXX_ENABLE_FILESYSTEM AND LIBCXX_ENABLE_TIME_ZONE_DATABASE)
list(APPEND LIBCXX_EXPERIMENTAL_SOURCES
- include/tzdb/leap_second_private.h
- include/tzdb/time_zone_link_private.h
include/tzdb/time_zone_private.h
include/tzdb/types_private.h
include/tzdb/tzdb_list_private.h
diff --git a/libcxx/src/include/tzdb/leap_second_private.h b/libcxx/src/include/tzdb/leap_second_private.h
deleted file mode 100644
index 7a811ab19759..000000000000
--- a/libcxx/src/include/tzdb/leap_second_private.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
-
-#ifndef _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
-#define _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
-
-#include <chrono>
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-namespace chrono {
-
-struct leap_second::__constructor_tag {};
-
-} // namespace chrono
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_SRC_INCLUDE_TZDB_LEAP_SECOND_PRIVATE_H
diff --git a/libcxx/src/include/tzdb/time_zone_link_private.h b/libcxx/src/include/tzdb/time_zone_link_private.h
deleted file mode 100644
index 139237625274..000000000000
--- a/libcxx/src/include/tzdb/time_zone_link_private.h
+++ /dev/null
@@ -1,27 +0,0 @@
-// -*- C++ -*-
-//===----------------------------------------------------------------------===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
-
-#ifndef _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
-#define _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
-
-#include <chrono>
-
-_LIBCPP_BEGIN_NAMESPACE_STD
-
-namespace chrono {
-
-struct time_zone_link::__constructor_tag {};
-
-} // namespace chrono
-
-_LIBCPP_END_NAMESPACE_STD
-
-#endif // _LIBCPP_SRC_INCLUDE_TZDB_TIME_ZONE_LINK_PRIVATE_H
diff --git a/libcxx/src/include/tzdb/time_zone_private.h b/libcxx/src/include/tzdb/time_zone_private.h
index 039a3b0ffeb7..2c47e9fdb13d 100644
--- a/libcxx/src/include/tzdb/time_zone_private.h
+++ b/libcxx/src/include/tzdb/time_zone_private.h
@@ -24,7 +24,8 @@ namespace chrono {
class time_zone::__impl {
public:
- explicit _LIBCPP_HIDE_FROM_ABI __impl(string&& __name) : __name_(std::move(__name)) {}
+ explicit _LIBCPP_HIDE_FROM_ABI __impl(string&& __name, const __tz::__rules_storage_type& __rules_db)
+ : __name_(std::move(__name)), __rules_db_(__rules_db) {}
[[nodiscard]] _LIBCPP_HIDE_FROM_ABI string_view __name() const noexcept { return __name_; }
@@ -33,12 +34,20 @@ public:
return __continuations_;
}
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI const __tz::__rules_storage_type& __rules_db() const { return __rules_db_; }
+
private:
string __name_;
// Note the first line has a name + __continuation, the other lines
// are just __continuations. So there is always at least one item in
// the vector.
vector<__tz::__continuation> __continuations_;
+
+ // Continuations often depend on a set of rules. The rules are stored in
+ // parallel data structurs in tzdb_list. From the time_zone it's not possible
+ // to find its associated tzdb entry and thus not possible to find its
+ // associated rules. Therefore a link to the rules in stored in this class.
+ const __tz::__rules_storage_type& __rules_db_;
};
} // namespace chrono
diff --git a/libcxx/src/include/tzdb/types_private.h b/libcxx/src/include/tzdb/types_private.h
index 4604b9fc8811..c86982948b61 100644
--- a/libcxx/src/include/tzdb/types_private.h
+++ b/libcxx/src/include/tzdb/types_private.h
@@ -33,7 +33,17 @@ namespace chrono::__tz {
// Sun>=8 first Sunday on or after the eighth
// Sun<=25 last Sunday on or before the 25th
struct __constrained_weekday {
- /* year_month_day operator()(year __year, month __month);*/ // needed but not implemented
+ [[nodiscard]] _LIBCPP_HIDE_FROM_ABI year_month_day operator()(year __year, month __month) const {
+ auto __result = static_cast<sys_days>(year_month_day{__year, __month, __day});
+ weekday __wd{static_cast<sys_days>(__result)};
+
+ if (__comparison == __le)
+ __result -= __wd - __weekday;
+ else
+ __result += __weekday - __wd;
+
+ return __result;
+ }
weekday __weekday;
enum __comparison_t { __le, __ge } __comparison;
@@ -85,7 +95,8 @@ struct __continuation {
// used.
// If this field contains - then standard time always
// applies. This is indicated by the monostate.
- using __rules_t = variant<monostate, __tz::__save, string, size_t>;
+ // TODO TZDB Investigate implantation the size_t based caching.
+ using __rules_t = variant<monostate, __tz::__save, string /*, size_t*/>;
__rules_t __rules;
diff --git a/libcxx/src/locale.cpp b/libcxx/src/locale.cpp
index 7fdd5be181ed..1ca88e30f63a 100644
--- a/libcxx/src/locale.cpp
+++ b/libcxx/src/locale.cpp
@@ -497,7 +497,7 @@ constinit __no_destroy<locale::__imp>
locale::__imp::classic_locale_imp_(__uninitialized_tag{}); // initialized below in classic()
const locale& locale::classic() {
- static const __no_destroy<locale> classic_locale(__private_tag{}, [] {
+ static const __no_destroy<locale> classic_locale(__private_constructor_tag{}, [] {
// executed exactly once on first initialization of `classic_locale`
locale::__imp::classic_locale_imp_.__emplace(1u);
return &locale::__imp::classic_locale_imp_.__get();
diff --git a/libcxx/src/time_zone.cpp b/libcxx/src/time_zone.cpp
index b6bf06a116f6..aef6ac674a11 100644
--- a/libcxx/src/time_zone.cpp
+++ b/libcxx/src/time_zone.cpp
@@ -8,14 +8,712 @@
// For information see https://libcxx.llvm.org/DesignDocs/TimeZone.html
+// TODO TZDB look at optimizations
+//
+// The current algorithm is correct but not efficient. For example, in a named
+// rule based continuation finding the next rule does quite a bit of work,
+// returns the next rule and "forgets" its state. This could be better.
+//
+// It would be possible to cache lookups. If a time for a zone is calculated its
+// sys_info could be kept and the next lookup could test whether the time is in
+// a "known" sys_info. The wording in the Standard hints at this slowness by
+// "suggesting" this could be implemented on the user's side.
+
+// TODO TZDB look at removing quirks
+//
+// The code has some special rules to adjust the timing at the continuation
+// switches. This works correctly, but some of the places feel odd. It would be
+// good to investigate this further and see whether all quirks are needed or
+// that there are better fixes.
+//
+// These quirks often use a 12h interval; this is the scan interval of zdump,
+// which implies there are no sys_info objects with a duration of less than 12h.
+
+#include <algorithm>
+#include <cctype>
#include <chrono>
+#include <expected>
+#include <map>
+#include <ranges>
#include "include/tzdb/time_zone_private.h"
+#include "include/tzdb/tzdb_list_private.h"
+
+// TODO TZDB remove debug printing
+#ifdef PRINT
+# include <print>
+#endif
_LIBCPP_BEGIN_NAMESPACE_STD
+#ifdef PRINT
+template <>
+struct formatter<chrono::sys_info, char> {
+ template <class ParseContext>
+ constexpr typename ParseContext::iterator parse(ParseContext& ctx) {
+ return ctx.begin();
+ }
+
+ template <class FormatContext>
+ typename FormatContext::iterator format(const chrono::sys_info& info, FormatContext& ctx) const {
+ return std::format_to(
+ ctx.out(), "[{}, {}) {:%Q%q} {:%Q%q} {}", info.begin, info.end, info.offset, info.save, info.abbrev);
+ }
+};
+#endif
+
namespace chrono {
+//===----------------------------------------------------------------------===//
+// Details
+//===----------------------------------------------------------------------===//
+
+struct __sys_info {
+ sys_info __info;
+ bool __can_merge; // Can the returned sys_info object be merged with
+};
+
+// Return type for helper function to get a sys_info.
+// - The expected result returns the "best" sys_info object. This object can be
+// before the requested time. Sometimes sys_info objects from different
+// continuations share their offset, save, and abbrev and these objects are
+// merged to one sys_info object. The __can_merge flag determines whether the
+// current result can be merged with the next result.
+// - The unexpected result means no sys_info object was found and the time is
+// the time to be used for the next search iteration.
+using __sys_info_result = expected<__sys_info, sys_seconds>;
+
+template <ranges::forward_range _Range,
+ class _Type,
+ class _Proj = identity,
+ indirect_strict_weak_order<const _Type*, projected<ranges::iterator_t<_Range>, _Proj>> _Comp = ranges::less>
+[[nodiscard]] static ranges::borrowed_iterator_t<_Range>
+__binary_find(_Range&& __r, const _Type& __value, _Comp __comp = {}, _Proj __proj = {}) {
+ auto __end = ranges::end(__r);
+ auto __ret = ranges::lower_bound(ranges::begin(__r), __end, __value, __comp, __proj);
+ if (__ret == __end)
+ return __end;
+
+ // When the value does not match the predicate it's equal and a valid result
+ // was found.
+ return !std::invoke(__comp, __value, std::invoke(__proj, *__ret)) ? __ret : __end;
+}
+
+// Format based on https://data.iana.org/time-zones/tz-how-to.html
+//
+// 1 a time zone abbreviation that is a string of three or more characters that
+// are either ASCII alphanumerics, "+", or "-"
+// 2 the string "%z", in which case the "%z" will be replaced by a numeric time
+// zone abbreviation
+// 3 a pair of time zone abbreviations separated by a slash ('/'), in which
+// case the first string is the abbreviation for the standard time name and
+// the second string is the abbreviation for the daylight saving time name
+// 4 a string containing "%s", in which case the "%s" will be replaced by the
+// text in the appropriate Rule's LETTER column, and the resulting string
+// should be a time zone abbreviation
+//
+// Rule 1 is not strictly validated since America/Barbados uses a two letter
+// abbreviation AT.
+[[nodiscard]] static string
+__format(const __tz::__continuation& __continuation, const string& __letters, seconds __save) {
+ bool __shift = false;
+ string __result;
+ for (char __c : __continuation.__format) {
+ if (__shift) {
+ switch (__c) {
+ case 's':
+ std::ranges::copy(__letters, std::back_inserter(__result));
+ break;
+
+ case 'z': {
+ if (__continuation.__format.size() != 2)
+ std::__throw_runtime_error(
+ std::format("corrupt tzdb FORMAT field: %z should be the entire contents, instead contains '{}'",
+ __continuation.__format)
+ .c_str());
+ chrono::hh_mm_ss __offset{__continuation.__stdoff + __save};
+ if (__offset.is_negative()) {
+ __result += '-';
+ __offset = chrono::hh_mm_ss{-(__continuation.__stdoff + __save)};
+ } else
+ __result += '+';
+
+ if (__offset.minutes() != 0min)
+ std::format_to(std::back_inserter(__result), "{:%H%M}", __offset);
+ else
+ std::format_to(std::back_inserter(__result), "{:%H}", __offset);
+ } break;
+
+ default:
+ std::__throw_runtime_error(
+ std::format("corrupt tzdb FORMAT field: invalid sequence '%{}' found, expected %s or %z", __c).c_str());
+ }
+ __shift = false;
+
+ } else if (__c == '/') {
+ if (__save != 0s)
+ __result.clear();
+ else
+ break;
+
+ } else if (__c == '%') {
+ __shift = true;
+ } else if (__c == '+' || __c == '-' || std::isalnum(__c)) {
+ __result.push_back(__c);
+ } else {
+ std::__throw_runtime_error(
+ std::format(
+ "corrupt tzdb FORMAT field: invalid character '{}' found, expected +, -, or an alphanumeric value", __c)
+ .c_str());
+ }
+ }
+
+ if (__shift)
+ std::__throw_runtime_error("corrupt tzdb FORMAT field: input ended with the start of the escape sequence '%'");
+
+ if (__result.empty())
+ std::__throw_runtime_error("corrupt tzdb FORMAT field: result is empty");
+
+ return __result;
+}
+
+[[nodiscard]] static sys_seconds __to_sys_seconds(year_month_day __ymd, seconds __seconds) {
+ seconds __result = static_cast<sys_days>(__ymd).time_since_epoch() + __seconds;
+ return sys_seconds{__result};
+}
+
+[[nodiscard]] static seconds __at_to_sys_seconds(const __tz::__continuation& __continuation) {
+ switch (__continuation.__at.__clock) {
+ case __tz::__clock::__local:
+ return __continuation.__at.__time - __continuation.__stdoff -
+ std::visit(
+ [](const auto& __value) {
+ using _Tp = decay_t<decltype(__value)>;
+ if constexpr (same_as<_Tp, monostate>)
+ return chrono::seconds{0};
+ else if constexpr (same_as<_Tp, __tz::__save>)
+ return chrono::duration_cast<seconds>(__value.__time);
+ else if constexpr (same_as<_Tp, std::string>)
+ // For a named rule based continuation the SAVE depends on the RULE
+ // active at the end. This should be determined separately.
+ return chrono::seconds{0};
+ else
+ static_assert(sizeof(_Tp) == 0); // TODO TZDB static_assert(false); after droping clang-16 support
+
+ std::__libcpp_unreachable();
+ },
+ __continuation.__rules);
+
+ case __tz::__clock::__universal:
+ return __continuation.__at.__time;
+
+ case __tz::__clock::__standard:
+ return __continuation.__at.__time - __continuation.__stdoff;
+ }
+ std::__libcpp_unreachable();
+}
+
+[[nodiscard]] static year_month_day __to_year_month_day(year __year, month __month, __tz::__on __on) {
+ return std::visit(
+ [&](const auto& __value) {
+ using _Tp = decay_t<decltype(__value)>;
+ if constexpr (same_as<_Tp, chrono::day>)
+ return year_month_day{__year, __month, __value};
+ else if constexpr (same_as<_Tp, weekday_last>)
+ return year_month_day{static_cast<sys_days>(year_month_weekday_last{__year, __month, __value})};
+ else if constexpr (same_as<_Tp, __tz::__constrained_weekday>)
+ return __value(__year, __month);
+ else
+ static_assert(sizeof(_Tp) == 0); // TODO TZDB static_assert(false); after droping clang-16 support
+
+ std::__libcpp_unreachable();
+ },
+ __on);
+}
+
+[[nodiscard]] static sys_seconds __until_to_sys_seconds(const __tz::__continuation& __continuation) {
+ // Does UNTIL contain the magic value for the last continuation?
+ if (__continuation.__year == chrono::year::min())
+ return sys_seconds::max();
+
+ year_month_day __ymd = chrono::__to_year_month_day(__continuation.__year, __continuation.__in, __continuation.__on);
+ return chrono::__to_sys_seconds(__ymd, chrono::__at_to_sys_seconds(__continuation));
+}
+
+// Holds the UNTIL time for a continuation with a named rule.
+//
+// Unlike continuations with an fixed SAVE named rules have a variable SAVE.
+// This means when the UNTIL uses the local wall time the actual UNTIL value can
+// only be determined when the SAVE is known. This class holds that abstraction.
+class __named_rule_until {
+public:
+ explicit __named_rule_until(const __tz::__continuation& __continuation)
+ : __until_{chrono::__until_to_sys_seconds(__continuation)},
+ __needs_adjustment_{
+ // The last continuation of a ZONE has no UNTIL which basically is
+ // until the end of _local_ time. This value is expressed by
+ // sys_seconds::max(). Subtracting the SAVE leaves large value.
+ // However SAVE can be negative, which would add a value to maximum
+ // leading to undefined behaviour. In practice this often results in
+ // an overflow to a very small value.
+ __until_ != sys_seconds::max() && __continuation.__at.__clock == __tz::__clock::__local} {}
+
+ // Gives the unadjusted until value, this is useful when the SAVE is not known
+ // at all.
+ sys_seconds __until() const noexcept { return __until_; }
+
+ bool __needs_adjustment() const noexcept { return __needs_adjustment_; }
+
+ // Returns the UNTIL adjusted for SAVE.
+ sys_seconds operator()(seconds __save) const noexcept { return __until_ - __needs_adjustment_ * __save; }
+
+private:
+ sys_seconds __until_;
+ bool __needs_adjustment_;
+};
+
+[[nodiscard]] static seconds __at_to_seconds(seconds __stdoff, const __tz::__rule& __rule) {
+ switch (__rule.__at.__clock) {
+ case __tz::__clock::__local:
+ // Local time and standard time behave the same. This is not
+ // correct. Local time needs to adjust for the current saved time.
+ // To know the saved time the rules need to be known and sorted.
+ // This needs a time so to avoid the chicken and egg adjust the
+ // saving of the local time later.
+ return __rule.__at.__time - __stdoff;
+
+ case __tz::__clock::__universal:
+ return __rule.__at.__time;
+
+ case __tz::__clock::__standard:
+ return __rule.__at.__time - __stdoff;
+ }
+ std::__libcpp_unreachable();
+}
+
+[[nodiscard]] static sys_seconds __from_to_sys_seconds(seconds __stdoff, const __tz::__rule& __rule, year __year) {
+ year_month_day __ymd = chrono::__to_year_month_day(__year, __rule.__in, __rule.__on);
+
+ seconds __at = chrono::__at_to_seconds(__stdoff, __rule);
+ return chrono::__to_sys_seconds(__ymd, __at);
+}
+
+[[nodiscard]] static sys_seconds __from_to_sys_seconds(seconds __stdoff, const __tz::__rule& __rule) {
+ return chrono::__from_to_sys_seconds(__stdoff, __rule, __rule.__from);
+}
+
+[[nodiscard]] static const vector<__tz::__rule>&
+__get_rules(const __tz::__rules_storage_type& __rules_db, const string& __rule_name) {
+ auto __result = chrono::__binary_find(__rules_db, __rule_name, {}, [](const auto& __p) { return __p.first; });
+ if (__result == std::end(__rules_db))
+ std::__throw_runtime_error(("corrupt tzdb: rule '" + __rule_name + " 'does not exist").c_str());
+
+ return __result->second;
+}
+
+// Returns the letters field for a time before the first rule.
+//
+// Per https://data.iana.org/time-zones/tz-how-to.html
+// One wrinkle, not fully explained in zic.8.txt, is what happens when switching
+// to a named rule. To what values should the SAVE and LETTER data be
+// initialized?
+//
+// 1 If at least one transition has happened, use the SAVE and LETTER data from
+// the most recent.
+// 2 If switching to a named rule before any transition has happened, assume
+// standard time (SAVE zero), and use the LETTER data from the earliest
+// transition with a SAVE of zero.
+//
+// This function implements case 2.
+[[nodiscard]] static string __letters_before_first_rule(const vector<__tz::__rule>& __rules) {
+ auto __letters =
+ __rules //
+ | views::filter([](const __tz::__rule& __rule) { return __rule.__save.__time == 0s; }) //
+ | views::transform([](const __tz::__rule& __rule) { return __rule.__letters; }) //
+ | views::take(1);
+
+ if (__letters.empty())
+ std::__throw_runtime_error("corrupt tzdb: rule has zero entries");
+
+ return __letters.front();
+}
+
+// Determines the information based on the continuation and the rules.
+//
+// There are several special cases to take into account
+//
+// === Entries before the first rule becomes active ===
+// Asia/Hong_Kong
+// 9 - JST 1945 N 18 2 // (1)
+// 8 HK HK%sT // (2)
+// R HK 1946 o - Ap 21 0 1 S // (3)
+// There (1) is active until Novemer 18th 1945 at 02:00, after this time
+// (2) becomes active. The first rule entry for HK (3) becomes active
+// from April 21st 1945 at 01:00. In the period between (2) is active.
+// This entry has an offset.
+// This entry has no save, letters, or dst flag. So in the period
+// after (1) and until (3) no rule entry is associated with the time.
+
+[[nodiscard]] static sys_info __get_sys_info_before_first_rule(
+ sys_seconds __begin,
+ sys_seconds __end,
+ const __tz::__continuation& __continuation,
+ const vector<__tz::__rule>& __rules) {
+ return sys_info{
+ __begin,
+ __end,
+ __continuation.__stdoff,
+ chrono::minutes(0),
+ chrono::__format(__continuation, __letters_before_first_rule(__rules), 0s)};
+}
+
+// Returns the sys_info object for a time before the first rule.
+// When this first rule has a SAVE of 0s the sys_info for the time before the
+// first rule and for the first rule are identical and will be merged.
+[[nodiscard]] static sys_info __get_sys_info_before_first_rule(
+ sys_seconds __begin,
+ sys_seconds __rule_end, // The end used when SAVE != 0s
+ sys_seconds __next_end, // The end used when SAVE == 0s the times are merged
+ const __tz::__continuation& __continuation,
+ const vector<__tz::__rule>& __rules,
+ vector<__tz::__rule>::const_iterator __rule) {
+ if (__rule->__save.__time != 0s)
+ return __get_sys_info_before_first_rule(__begin, __rule_end, __continuation, __rules);
+
+ return sys_info{
+ __begin, __next_end, __continuation.__stdoff, 0min, chrono::__format(__continuation, __rule->__letters, 0s)};
+}
+
+[[nodiscard]] static seconds __at_to_seconds(seconds __stdoff, seconds __save, const __tz::__rule& __rule) {
+ switch (__rule.__at.__clock) {
+ case __tz::__clock::__local:
+ return __rule.__at.__time - __stdoff - __save;
+
+ case __tz::__clock::__universal:
+ return __rule.__at.__time;
+
+ case __tz::__clock::__standard:
+ return __rule.__at.__time - __stdoff;
+ }
+ std::__libcpp_unreachable();
+}
+
+[[nodiscard]] static sys_seconds
+__rule_to_sys_seconds(seconds __stdoff, seconds __save, const __tz::__rule& __rule, year __year) {
+ year_month_day __ymd = chrono::__to_year_month_day(__year, __rule.__in, __rule.__on);
+
+ seconds __at = chrono::__at_to_seconds(__stdoff, __save, __rule);
+ return chrono::__to_sys_seconds(__ymd, __at);
+}
+
+// Returns the first rule after __time.
+// Note that a rule can be "active" in multiple years, this may result in an
+// infinite loop where the same rule is returned every time, use __current to
+// guard against that.
+//
+// When no next rule exists the returned time will be sys_seconds::max(). This
+// can happen in practice. For example,
+//
+// R So 1945 o - May 24 2 2 M
+// R So 1945 o - S 24 3 1 S
+// R So 1945 o - N 18 2s 0 -
+//
+// Has 3 rules that are all only active in 1945.
+[[nodiscard]] static pair<sys_seconds, vector<__tz::__rule>::const_iterator>
+__next_rule(sys_seconds __time,
+ seconds __stdoff,
+ seconds __save,
+ const vector<__tz::__rule>& __rules,
+ vector<__tz::__rule>::const_iterator __current) {
+ year __year = year_month_day{chrono::floor<days>(__time)}.year();
+
+ // Note it would probably be better to store the pairs in a vector and then
+ // use min() to get the smallest element
+ map<sys_seconds, vector<__tz::__rule>::const_iterator> __candidates;
+ // Note this evaluates all rules which is a waste of effort; when the entries
+ // are beyond the current year's "next year" (where "next year" is not always
+ // year + 1) the algorithm should end.
+ for (auto __it = __rules.begin(); __it != __rules.end(); ++__it) {
+ for (year __y = __it->__from; __y <= __it->__to; ++__y) {
+ // Adding the current entry for the current year may lead to infinite
+ // loops due to the SAVE adjustment. Skip these entries.
+ if (__y == __year && __it == __current)
+ continue;
+
+ sys_seconds __t = chrono::__rule_to_sys_seconds(__stdoff, __save, *__it, __y);
+ if (__t <= __time)
+ continue;
+
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(!__candidates.contains(__t), "duplicated rule");
+ __candidates[__t] = __it;
+ break;
+ }
+ }
+
+ if (!__candidates.empty()) [[likely]] {
+ auto __it = __candidates.begin();
+
+ // When no rule is selected the time before the first rule and the first rule
+ // should not be merged.
+ if (__time == sys_seconds::min())
+ return *__it;
+
+ // There can be two constitutive rules that are the same. For example,
+ // Hong Kong
+ //
+ // R HK 1973 o - D 30 3:30 1 S (R1)
+ // R HK 1965 1976 - Ap Su>=16 3:30 1 S (R2)
+ //
+ // 1973-12-29 19:30:00 R1 becomes active.
+ // 1974-04-20 18:30:00 R2 becomes active.
+ // Both rules have a SAVE of 1 hour and LETTERS are S for both of them.
+ while (__it != __candidates.end()) {
+ if (__current->__save.__time != __it->second->__save.__time || __current->__letters != __it->second->__letters)
+ return *__it;
+
+ ++__it;
+ }
+ }
+
+ return {sys_seconds::max(), __rules.end()};
+}
+
+// Returns the first rule of a set of rules.
+// This is not always the first of the listed rules. For example
+// R Sa 2008 2009 - Mar Su>=8 0 0 -
+// R Sa 2007 2008 - O Su>=8 0 1 -
+// The transition in October 2007 happens before the transition in March 2008.
+[[nodiscard]] static vector<__tz::__rule>::const_iterator
+__first_rule(seconds __stdoff, const vector<__tz::__rule>& __rules) {
+ return chrono::__next_rule(sys_seconds::min(), __stdoff, 0s, __rules, __rules.end()).second;
+}
+
+[[nodiscard]] static __sys_info_result __get_sys_info_rule(
+ sys_seconds __time,
+ sys_seconds __continuation_begin,
+ const __tz::__continuation& __continuation,
+ const vector<__tz::__rule>& __rules) {
+ auto __rule = chrono::__first_rule(__continuation.__stdoff, __rules);
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(__rule != __rules.end(), "the set of rules has no first rule");
+
+ // Avoid selecting a time before the start of the continuation
+ __time = std::max(__time, __continuation_begin);
+
+ sys_seconds __rule_begin = chrono::__from_to_sys_seconds(__continuation.__stdoff, *__rule);
+
+ // The time sought is very likely inside the current rule.
+ // When the continuation's UNTIL uses the local clock there are edge cases
+ // where this is not true.
+ //
+ // Start to walk the rules to find the proper one.
+ //
+ // For now we just walk all the rules TODO TZDB investigate whether a smarter
+ // algorithm would work.
+ auto __next = chrono::__next_rule(__rule_begin, __continuation.__stdoff, __rule->__save.__time, __rules, __rule);
+
+ // Ignore small steps, this happens with America/Punta_Arenas for the
+ // transition
+ // -4:42:46 - SMT 1927 S
+ // -5 x -05/-04 1932 S
+ // ...
+ //
+ // R x 1927 1931 - S 1 0 1 -
+ // R x 1928 1932 - Ap 1 0 0 -
+ //
+ // America/Punta_Arenas Thu Sep 1 04:42:45 1927 UT = Thu Sep 1 00:42:45 1927 -04 isdst=1 gmtoff=-14400
+ // America/Punta_Arenas Sun Apr 1 03:59:59 1928 UT = Sat Mar 31 23:59:59 1928 -04 isdst=1 gmtoff=-14400
+ // America/Punta_Arenas Sun Apr 1 04:00:00 1928 UT = Sat Mar 31 23:00:00 1928 -05 isdst=0 gmtoff=-18000
+ //
+ // Without this there will be a transition
+ // [1927-09-01 04:42:45, 1927-09-01 05:00:00) -05:00:00 0min -05
+
+ if (sys_seconds __begin = __rule->__save.__time != 0s ? __rule_begin : __next.first; __time < __begin) {
+ if (__continuation_begin == sys_seconds::min() || __begin - __continuation_begin > 12h)
+ return __sys_info{__get_sys_info_before_first_rule(
+ __continuation_begin, __rule_begin, __next.first, __continuation, __rules, __rule),
+ false};
+
+ // Europe/Berlin
+ // 1 c CE%sT 1945 May 24 2 (C1)
+ // 1 So CE%sT 1946 (C2)
+ //
+ // R c 1944 1945 - Ap M>=1 2s 1 S (R1)
+ //
+ // R So 1945 o - May 24 2 2 M (R2)
+ //
+ // When C2 becomes active the time would be before the first rule R2,
+ // giving a 1 hour sys_info.
+ seconds __save = __rule->__save.__time;
+ __named_rule_until __continuation_end{__continuation};
+ sys_seconds __sys_info_end = std::min(__continuation_end(__save), __next.first);
+
+ return __sys_info{
+ sys_info{__continuation_begin,
+ __sys_info_end,
+ __continuation.__stdoff + __save,
+ chrono::duration_cast<minutes>(__save),
+ chrono::__format(__continuation, __rule->__letters, __save)},
+ __sys_info_end == __continuation_end(__save)};
+ }
+
+ // See above for America/Asuncion
+ if (__rule->__save.__time == 0s && __time < __next.first) {
+ return __sys_info{
+ sys_info{__continuation_begin,
+ __next.first,
+ __continuation.__stdoff,
+ 0min,
+ chrono::__format(__continuation, __rule->__letters, 0s)},
+ false};
+ }
+
+ __named_rule_until __continuation_end{__continuation};
+ if (__time >= __continuation_end.__until() && !__continuation_end.__needs_adjustment())
+ // note std::unexpected<sys_seconds>(__end); is ambiguous with std::unexpected() in <exception>,
+ return __sys_info_result{std::unexpect, __continuation_end.__until()};
+
+ while (__next.second != __rules.end()) {
+#ifdef PRINT
+ std::print(
+ stderr,
+ "Rule for {}: [{}, {}) off={} save={} duration={}\n",
+ __time,
+ __rule_begin,
+ __next.first,
+ __continuation.__stdoff,
+ __rule->__save.__time,
+ __next.first - __rule_begin);
+#endif
+
+ sys_seconds __end = __continuation_end(__rule->__save.__time);
+
+ sys_seconds __sys_info_begin = std::max(__continuation_begin, __rule_begin);
+ sys_seconds __sys_info_end = std::min(__end, __next.first);
+ seconds __diff = chrono::abs(__sys_info_end - __sys_info_begin);
+
+ if (__diff < 12h) {
+ // Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31
+ // -4:16:48 - CMT 1920 May
+ // -4 - -04 1930 D
+ // -4 A -04/-03 1969 O 5
+ // -3 A -03/-02 1999 O 3
+ // -4 A -04/-03 2000 Mar 3
+ // ...
+ //
+ // ...
+ // R A 1989 1992 - O Su>=15 0 1 -
+ // R A 1999 o - O Su>=1 0 1 -
+ // R A 2000 o - Mar 3 0 0 -
+ // R A 2007 o - D 30 0 1 -
+ // ...
+
+ // The 1999 switch uses the same rule, but with a different stdoff.
+ // R A 1999 o - O Su>=1 0 1 -
+ // stdoff -3 -> 1999-10-03 03:00:00
+ // stdoff -4 -> 1999-10-03 04:00:00
+ // This generates an invalid entry and this is evaluated as a transition.
+ // Looking at the zdump like output in libc++ this generates jumps in
+ // the UTC time.
+
+ __rule = __next.second;
+ __next = __next_rule(__next.first, __continuation.__stdoff, __rule->__save.__time, __rules, __rule);
+ __end = __continuation_end(__rule->__save.__time);
+ __sys_info_end = std::min(__end, __next.first);
+ }
+
+ if ((__time >= __rule_begin && __time < __next.first) || __next.first >= __end) {
+ __sys_info_begin = std::max(__continuation_begin, __rule_begin);
+ __sys_info_end = std::min(__end, __next.first);
+
+ return __sys_info{
+ sys_info{__sys_info_begin,
+ __sys_info_end,
+ __continuation.__stdoff + __rule->__save.__time,
+ chrono::duration_cast<minutes>(__rule->__save.__time),
+ chrono::__format(__continuation, __rule->__letters, __rule->__save.__time)},
+ __sys_info_end == __end};
+ }
+
+ __rule_begin = __next.first;
+ __rule = __next.second;
+ __next = __next_rule(__rule_begin, __continuation.__stdoff, __rule->__save.__time, __rules, __rule);
+ }
+
+ return __sys_info{
+ sys_info{std::max(__continuation_begin, __rule_begin),
+ __continuation_end(__rule->__save.__time),
+ __continuation.__stdoff + __rule->__save.__time,
+ chrono::duration_cast<minutes>(__rule->__save.__time),
+ chrono::__format(__continuation, __rule->__letters, __rule->__save.__time)},
+ true};
+}
+
+[[nodiscard]] static __sys_info_result __get_sys_info_basic(
+ sys_seconds __time, sys_seconds __continuation_begin, const __tz::__continuation& __continuation, seconds __save) {
+ sys_seconds __continuation_end = chrono::__until_to_sys_seconds(__continuation);
+ return __sys_info{
+ sys_info{__continuation_begin,
+ __continuation_end,
+ __continuation.__stdoff + __save,
+ chrono::duration_cast<minutes>(__save),
+ __continuation.__format},
+ true};
+}
+
+[[nodiscard]] static __sys_info_result
+__get_sys_info(sys_seconds __time,
+ sys_seconds __continuation_begin,
+ const __tz::__continuation& __continuation,
+ const __tz::__rules_storage_type& __rules_db) {
+ return std::visit(
+ [&](const auto& __value) {
+ using _Tp = decay_t<decltype(__value)>;
+ if constexpr (same_as<_Tp, std::string>)
+ return chrono::__get_sys_info_rule(
+ __time, __continuation_begin, __continuation, __get_rules(__rules_db, __value));
+ else if constexpr (same_as<_Tp, monostate>)
+ return chrono::__get_sys_info_basic(__time, __continuation_begin, __continuation, chrono::seconds(0));
+ else if constexpr (same_as<_Tp, __tz::__save>)
+ return chrono::__get_sys_info_basic(__time, __continuation_begin, __continuation, __value.__time);
+ else
+ static_assert(sizeof(_Tp) == 0); // TODO TZDB static_assert(false); after droping clang-16 support
+
+ std::__libcpp_unreachable();
+ },
+ __continuation.__rules);
+}
+
+// The transition from one continuation to the next continuation may result in
+// two constitutive continuations with the same "offset" information.
+// [time.zone.info.sys]/3
+// The begin and end data members indicate that, for the associated time_zone
+// and time_point, the offset and abbrev are in effect in the range
+// [begin, end). This information can be used to efficiently iterate the
+// transitions of a time_zone.
+//
+// Note that this does considers a change in the SAVE field not to be a
+// different sys_info, zdump does consider this different.
+// LWG XXXX The sys_info range should be affected by save
+// matches the behaviour of the Standard and zdump.
+//
+// Iff the "offsets" are the same '__current.__end' is replaced with
+// '__next.__end', which effectively merges the two objects in one object. The
+// function returns true if a merge occurred.
+[[nodiscard]] bool __merge_continuation(sys_info& __current, const sys_info& __next) {
+ if (__current.end != __next.begin)
+ return false;
+
+ if (__current.offset != __next.offset || __current.abbrev != __next.abbrev || __current.save != __next.save)
+ return false;
+
+ __current.end = __next.end;
+ return true;
+}
+
+//===----------------------------------------------------------------------===//
+// Public API
+//===----------------------------------------------------------------------===//
+
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI time_zone time_zone::__create(unique_ptr<time_zone::__impl>&& __p) {
_LIBCPP_ASSERT_NON_NULL(__p != nullptr, "initialized time_zone without a valid pimpl object");
time_zone result;
@@ -27,6 +725,173 @@ _LIBCPP_EXPORTED_FROM_ABI time_zone::~time_zone() = default;
[[nodiscard]] _LIBCPP_EXPORTED_FROM_ABI string_view time_zone::__name() const noexcept { return __impl_->__name(); }
+[[nodiscard]] _LIBCPP_AVAILABILITY_TZDB _LIBCPP_EXPORTED_FROM_ABI sys_info
+time_zone::__get_info(sys_seconds __time) const {
+ optional<sys_info> __result;
+ bool __valid_result = false; // true iff __result.has_value() is true and
+ // __result.begin <= __time < __result.end is true.
+ bool __can_merge = false;
+ sys_seconds __continuation_begin = sys_seconds::min();
+ // Iterates over the Zone entry and its continuations. Internally the Zone
+ // entry is split in a Zone information and the first continuation. The last
+ // continuation has no UNTIL field. This means the loop should always find a
+ // continuation.
+ //
+ // For more information on background of zone information please consult the
+ // following information
+ // [zic manual](https://www.man7.org/linux/man-pages/man8/zic.8.html)
+ // [tz source info](https://data.iana.org/time-zones/tz-how-to.html)
+ // On POSIX systems the zdump tool can be useful:
+ // zdump -v Asia/Hong_Kong
+ // Gives all transitions in the Hong Kong time zone.
+ //
+ // During iteration the result for the current continuation is returned. If
+ // no continuation is applicable it will return the end time as "error". When
+ // two continuations are contiguous and contain the "same" information these
+ // ranges are merged as one range.
+ // The merging requires keeping any result that occurs before __time,
+ // likewise when a valid result is found the algorithm needs to test the next
+ // continuation to see whether it can be merged. For example, Africa/Ceuta
+ // Continuations
+ // 0 s WE%sT 1929 (C1)
+ // 0 - WET 1967 (C2)
+ // 0 Sp WE%sT 1984 Mar 16 (C3)
+ //
+ // Rules
+ // R s 1926 1929 - O Sa>=1 24s 0 - (R1)
+ //
+ // R Sp 1967 o - Jun 3 12 1 S (R2)
+ //
+ // The rule R1 is the last rule used in C1. The rule R2 is the first rule in
+ // C3. Since R2 is the first rule this means when a continuation uses this
+ // rule its value prior to R2 will be SAVE 0 LETTERS of the first entry with a
+ // SAVE of 0, in this case WET.
+ // This gives the following changes in the information.
+ // 1928-10-07 00:00:00 C1 R1 becomes active: offset 0 save 0 abbrev WET
+ // 1929-01-01 00:00:00 C2 becomes active: offset 0 save 0 abbrev WET
+ // 1967-01-01 00:00:00 C3 becomes active: offset 0 save 0 abbrev WET
+ // 1967-06-03 12:00:00 C3 R2 becomes active: offset 0 save 1 abbrev WEST
+ //
+ // The first 3 entries are contiguous and contain the same information, this
+ // means the period [1928-10-07 00:00:00, 1967-06-03 12:00:00) should be
+ // returned in one sys_info object.
+
+ const auto& __continuations = __impl_->__continuations();
+ const __tz::__rules_storage_type& __rules_db = __impl_->__rules_db();
+ for (auto __it = __continuations.begin(); __it != __continuations.end(); ++__it) {
+ const auto& __continuation = *__it;
+ __sys_info_result __sys_info = chrono::__get_sys_info(__time, __continuation_begin, __continuation, __rules_db);
+
+ if (__sys_info) {
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
+ __sys_info->__info.begin < __sys_info->__info.end, "invalid sys_info range");
+
+ // Filters out dummy entries
+ // Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31
+ // ...
+ // -4 A -04/-03 2000 Mar 3 (C1)
+ // -3 A -03/-02 (C2)
+ //
+ // ...
+ // R A 2000 o - Mar 3 0 0 -
+ // R A 2007 o - D 30 0 1 -
+ // ...
+ //
+ // This results in an entry
+ // [2000-03-03 03:00:00, 2000-03-03 04:00:00) -10800s 60min -03
+ // for [C1 & R1, C1, R2) which due to the end of the continuation is an
+ // one hour "sys_info". Instead the entry should be ignored and replaced
+ // by [C2 & R1, C2 & R2) which is the proper range
+ // "[2000-03-03 03:00:00, 2007-12-30 03:00:00) -02:00:00 60min -02
+
+ if (std::holds_alternative<string>(__continuation.__rules) && __sys_info->__can_merge &&
+ __sys_info->__info.begin + 12h > __sys_info->__info.end) {
+ __continuation_begin = __sys_info->__info.begin;
+ continue;
+ }
+
+ if (!__result) {
+ // First entry found, always keep it.
+ __result = __sys_info->__info;
+
+ __valid_result = __time >= __result->begin && __time < __result->end;
+ __can_merge = __sys_info->__can_merge;
+ } else if (__can_merge && chrono::__merge_continuation(*__result, __sys_info->__info)) {
+ // The results are merged, update the result state. This may
+ // "overwrite" a valid sys_info object with another valid sys_info
+ // object.
+ __valid_result = __time >= __result->begin && __time < __result->end;
+ __can_merge = __sys_info->__can_merge;
+ } else {
+ // Here things get interesting:
+ // For example, America/Argentina/San_Luis
+ //
+ // -3 A -03/-02 2008 Ja 21 (C1)
+ // -4 Sa -04/-03 2009 O 11 (C2)
+ //
+ // R A 2007 o - D 30 0 1 - (R1)
+ //
+ // R Sa 2007 2008 - O Su>=8 0 1 - (R2)
+ //
+ // Based on C1 & R1 the end time of C1 is 2008-01-21 03:00:00
+ // Based on C2 & R2 the end time of C1 is 2008-01-21 02:00:00
+ // In this case the earlier time is the real time of the transition.
+ // However the algorithm used gives 2008-01-21 03:00:00.
+ //
+ // So we need to calculate the previous UNTIL in the current context and
+ // see whether it's earlier.
+
+ // The results could not be merged.
+ // - When we have a valid result that result is the final result.
+ // - Otherwise the result we had is before __time and the result we got
+ // is at a later time (possibly valid). This result is always better
+ // than the previous result.
+ if (__valid_result) {
+ return *__result;
+ } else {
+ _LIBCPP_ASSERT_ARGUMENT_WITHIN_DOMAIN(
+ __it != __continuations.begin(), "the first rule should always seed the result");
+ const auto& __last = *(__it - 1);
+ if (std::holds_alternative<string>(__last.__rules)) {
+ // Europe/Berlin
+ // 1 c CE%sT 1945 May 24 2 (C1)
+ // 1 So CE%sT 1946 (C2)
+ //
+ // R c 1944 1945 - Ap M>=1 2s 1 S (R1)
+ //
+ // R So 1945 o - May 24 2 2 M (R2)
+ //
+ // When C2 becomes active the time would be before the first rule R2,
+ // giving a 1 hour sys_info. This is not valid and the results need
+ // merging.
+
+ if (__result->end != __sys_info->__info.begin) {
+ // When the UTC gap between the rules is due to the change of
+ // offsets adjust the new time to remove the gap.
+ sys_seconds __end = __result->end - __result->offset;
+ sys_seconds __begin = __sys_info->__info.begin - __sys_info->__info.offset;
+ if (__end == __begin) {
+ __sys_info->__info.begin = __result->end;
+ }
+ }
+ }
+
+ __result = __sys_info->__info;
+ __valid_result = __time >= __result->begin && __time < __result->end;
+ __can_merge = __sys_info->__can_merge;
+ }
+ }
+ __continuation_begin = __result->end;
+ } else {
+ __continuation_begin = __sys_info.error();
+ }
+ }
+ if (__valid_result)
+ return *__result;
+
+ std::__throw_runtime_error("tzdb: corrupt db");
+}
+
} // namespace chrono
_LIBCPP_END_NAMESPACE_STD
diff --git a/libcxx/src/tzdb.cpp b/libcxx/src/tzdb.cpp
index 9d06eb920e5c..d521d810523e 100644
--- a/libcxx/src/tzdb.cpp
+++ b/libcxx/src/tzdb.cpp
@@ -15,8 +15,6 @@
#include <stdexcept>
#include <string>
-#include "include/tzdb/leap_second_private.h"
-#include "include/tzdb/time_zone_link_private.h"
#include "include/tzdb/time_zone_private.h"
#include "include/tzdb/types_private.h"
#include "include/tzdb/tzdb_list_private.h"
@@ -561,7 +559,7 @@ static void __parse_rule(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istr
static void __parse_zone(tzdb& __tzdb, __tz::__rules_storage_type& __rules, istream& __input) {
chrono::__skip_mandatory_whitespace(__input);
- auto __p = std::make_unique<time_zone::__impl>(chrono::__parse_string(__input));
+ auto __p = std::make_unique<time_zone::__impl>(chrono::__parse_string(__input), __rules);
vector<__tz::__continuation>& __continuations = __p->__continuations();
chrono::__skip_mandatory_whitespace(__input);
@@ -582,7 +580,7 @@ static void __parse_link(tzdb& __tzdb, istream& __input) {
string __name = chrono::__parse_string(__input);
chrono::__skip_line(__input);
- __tzdb.links.emplace_back(time_zone_link::__constructor_tag{}, std::move(__name), std::move(__target));
+ __tzdb.links.emplace_back(std::__private_constructor_tag{}, std::move(__name), std::move(__target));
}
static void __parse_tzdata(tzdb& __db, __tz::__rules_storage_type& __rules, istream& __input) {
@@ -649,7 +647,7 @@ static void __parse_leap_seconds(vector<leap_second>& __leap_seconds, istream&&
seconds __value{chrono::__parse_integral(__input, false)};
chrono::__skip_line(__input);
- __leap_seconds.emplace_back(leap_second::__constructor_tag{}, __date, __value);
+ __leap_seconds.emplace_back(std::__private_constructor_tag{}, __date, __value);
}
}
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
index 9acb57fa05f7..cbdb2ab1758e 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.compile.pass.cpp
@@ -50,6 +50,7 @@ void test() {
{
tz.name();
+ tz.get_info(std::chrono::sys_seconds{});
operator==(tz, tz);
operator<=>(tz, tz);
}
diff --git a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
index 8795a4eb3c6c..e88c176af4a8 100644
--- a/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
+++ b/libcxx/test/libcxx/diagnostics/chrono.nodiscard_extensions.verify.cpp
@@ -47,7 +47,9 @@ void test() {
crno::remote_version(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
{
+ std::chrono::sys_seconds s{};
tz.name(); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
+ tz.get_info(s); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
operator==(tz, tz); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
operator<=>(tz, tz); // expected-warning {{ignoring return value of function declared with 'nodiscard' attribute}}
}
diff --git a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
index 479c1b93fcab..640365889efa 100644
--- a/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
+++ b/libcxx/test/libcxx/gdb/gdb_pretty_printer_test.sh.cpp
@@ -12,7 +12,7 @@
// UNSUPPORTED: c++03
// TODO: Investigate these failures which break the CI.
-// UNSUPPORTED: clang-16, clang-17, clang-18, clang-19
+// UNSUPPORTED: clang-17, clang-18, clang-19
// TODO: Investigate this failure on GCC 13 (in Ubuntu Jammy)
// UNSUPPORTED: gcc-13
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp
new file mode 100644
index 000000000000..194f58215b92
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp
@@ -0,0 +1,199 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class time_zone;
+
+// template <class _Duration>
+// sys_info get_info(const sys_time<_Duration>& time) const;
+
+// tests the parts not validated in the public test
+// - Validates a zone with an UNTIL in its last continuation is corrupt
+// - The formatting of the FORMAT field's constrains
+// - Formatting of "%z", this is valid but not present in the actual database
+
+#include <algorithm>
+#include <cassert>
+#include <fstream>
+#include <chrono>
+#include <format>
+
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+#include "filesystem_test_helper.h"
+#include "test_tzdb.h"
+
+/***** ***** HELPERS ***** *****/
+
+scoped_test_env env;
+[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
+const std::filesystem::path file = env.create_file("zoneinfo/tzdata.zi");
+
+std::string_view std::chrono::__libcpp_tzdb_directory() {
+ static std::string result = dir.string();
+ return result;
+}
+
+static void write(std::string_view input) {
+ static int version = 0;
+
+ std::ofstream f{file};
+ f << "# version " << version++ << '\n';
+ f.write(input.data(), input.size());
+}
+
+static const std::chrono::tzdb& parse(std::string_view input) {
+ write(input);
+ return std::chrono::reload_tzdb();
+}
+
+[[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(int year) {
+ std::chrono::year_month_day result{std::chrono::year{year}, std::chrono::January, std::chrono::day{1}};
+
+ return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result));
+}
+
+static void test_exception([[maybe_unused]] std::string_view input, [[maybe_unused]] std::string_view what) {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ const std::chrono::tzdb& tzdb = parse(input);
+ const std::chrono::time_zone* tz = tzdb.locate_zone("Format");
+ TEST_VALIDATE_EXCEPTION(
+ std::runtime_error,
+ [&]([[maybe_unused]] const std::runtime_error& e) {
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+ },
+ TEST_IGNORE_NODISCARD tz->get_info(to_sys_seconds(2000)));
+#endif // TEST_HAS_NO_EXCEPTIONS
+}
+
+static void zone_without_until_entry() {
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ const std::chrono::tzdb& tzdb = parse(
+ R"(
+Z America/Paramaribo -3:40:40 - LMT 1911
+-3:40:52 - PMT 1935
+-3:40:36 - PMT 1945 O
+-3:30 - -0330 1984 O
+# -3 - -03 Commented out so the last entry has an UNTIL field.
+)");
+ const std::chrono::time_zone* tz = tzdb.locate_zone("America/Paramaribo");
+
+ TEST_IGNORE_NODISCARD tz->get_info(to_sys_seconds(1984));
+ TEST_VALIDATE_EXCEPTION(
+ std::runtime_error,
+ [&]([[maybe_unused]] const std::runtime_error& e) {
+ std::string what = "tzdb: corrupt db";
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+ },
+ TEST_IGNORE_NODISCARD tz->get_info(to_sys_seconds(1985)));
+#endif // TEST_HAS_NO_EXCEPTIONS
+}
+
+static void invalid_format() {
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 foo
+Z Format 0 F %zandfoo)",
+ "corrupt tzdb FORMAT field: %z should be the entire contents, instead contains '%zandfoo'");
+
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 foo
+Z Format 0 F %q)",
+ "corrupt tzdb FORMAT field: invalid sequence '%q' found, expected %s or %z");
+
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 foo
+Z Format 0 F !)",
+ "corrupt tzdb FORMAT field: invalid character '!' found, expected +, -, or an alphanumeric value");
+
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 foo
+Z Format 0 F @)",
+ "corrupt tzdb FORMAT field: invalid character '@' found, expected +, -, or an alphanumeric value");
+
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 foo
+Z Format 0 F $)",
+ "corrupt tzdb FORMAT field: invalid character '$' found, expected +, -, or an alphanumeric value");
+
+ test_exception(
+ R"(
+R F 1970 max - Jan 5 0 0 foo
+Z Format 0 F %)",
+ "corrupt tzdb FORMAT field: input ended with the start of the escape sequence '%'");
+
+ test_exception(
+ R"(
+R F 2000 max - Jan 5 0 0 -
+Z Format 0 F %s)",
+ "corrupt tzdb FORMAT field: result is empty");
+}
+
+static void test_abbrev(std::string_view input, std::string_view expected) {
+ const std::chrono::tzdb& tzdb = parse(input);
+ const std::chrono::time_zone* tz = tzdb.locate_zone("Format");
+ std::string result = tz->get_info(to_sys_seconds(2000)).abbrev;
+ TEST_LIBCPP_REQUIRE(result == expected, TEST_WRITE_CONCATENATED("\nExpected ", expected, "\nActual ", result, '\n'));
+}
+
+// This format is valid, however is not used in the tzdata.zi.
+static void percentage_z_format() {
+ test_abbrev(
+ R"(
+R F 1999 max - Jan 5 0 0 foo
+Z Format 0 F %z)",
+ "+00");
+
+ test_abbrev(
+ R"(
+R F 1999 max - Jan 5 0 1 foo
+Z Format 0 F %z)",
+ "+01");
+
+ test_abbrev(
+ R"(
+R F 1999 max - Jan 5 0 -1 foo
+Z Format 0 F %z)",
+ "-01");
+
+ test_abbrev(
+ R"(
+R F 1999 max - Jan 5 0 0 foo
+Z Format 0:45 F %z)",
+ "+0045");
+
+ test_abbrev(
+ R"(
+R F 1999 max - Jan 5 0 -1 foo
+Z Format 0:45 F %z)",
+ "-0015");
+}
+
+int main(int, const char**) {
+ zone_without_until_entry();
+ invalid_format();
+ percentage_z_format();
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.rule_selection.pass.cpp b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.rule_selection.pass.cpp
new file mode 100644
index 000000000000..accd5bcdc89e
--- /dev/null
+++ b/libcxx/test/libcxx/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.rule_selection.pass.cpp
@@ -0,0 +1,185 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class time_zone;
+
+// template <class _Duration>
+// sys_info get_info(const sys_time<_Duration>& time) const;
+
+// The time zone database contains of the following entries
+// - Zones,
+// - Rules,
+// - Links, and
+// - Leapseconds.
+//
+// The public tzdb struct stores all entries except the Rules. How
+// implementations keep track of the Rules is not specified. When the sys_info
+// for a time_zone is requested it needs to use the correct Rules. This lookup
+// cannot rely on 'get_tzdb()` since that returns the most recently loaded
+// database.
+//
+// A reload could change the rules of a time zone or the time zone could no
+// longer be present in the current database. These two conditions are tested.
+//
+// It is possible the tzdb entry has been removed by the user from the tzdb_list
+// after a reload. This is UB and not tested.
+
+#include <cassert>
+#include <fstream>
+#include <chrono>
+
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+#include "filesystem_test_helper.h"
+#include "test_tzdb.h"
+
+/***** ***** HELPERS ***** *****/
+
+scoped_test_env env;
+[[maybe_unused]] const std::filesystem::path dir = env.create_dir("zoneinfo");
+const std::filesystem::path file = env.create_file("zoneinfo/tzdata.zi");
+
+std::string_view std::chrono::__libcpp_tzdb_directory() {
+ static std::string result = dir.string();
+ return result;
+}
+
+static void write(std::string_view input) {
+ static int version = 0;
+
+ std::ofstream f{file};
+ f << "# version " << version++ << '\n';
+ f.write(input.data(), input.size());
+}
+
+static const std::chrono::tzdb& parse(std::string_view input) {
+ write(input);
+ return std::chrono::reload_tzdb();
+}
+
+[[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(
+ std::chrono::year year,
+ std::chrono::month month,
+ std::chrono::day day,
+ std::chrono::hours h = std::chrono::hours(0),
+ std::chrono::minutes m = std::chrono::minutes{0},
+ std::chrono::seconds s = std::chrono::seconds{0}) {
+ std::chrono::year_month_day result{year, month, day};
+
+ return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result)) + h + m + s;
+}
+
+static void assert_equal(const std::chrono::sys_info& lhs, const std::chrono::sys_info& rhs) {
+ TEST_REQUIRE(lhs.begin == rhs.begin,
+ TEST_WRITE_CONCATENATED("\nBegin:\nExpected output ", lhs.begin, "\nActual output ", rhs.begin, '\n'));
+ TEST_REQUIRE(lhs.end == rhs.end,
+ TEST_WRITE_CONCATENATED("\nEnd:\nExpected output ", lhs.end, "\nActual output ", rhs.end, '\n'));
+ TEST_REQUIRE(
+ lhs.offset == rhs.offset,
+ TEST_WRITE_CONCATENATED("\nOffset:\nExpected output ", lhs.offset, "\nActual output ", rhs.offset, '\n'));
+ TEST_REQUIRE(lhs.save == rhs.save,
+ TEST_WRITE_CONCATENATED("\nSave:\nExpected output ", lhs.save, "\nActual output ", rhs.save, '\n'));
+ TEST_REQUIRE(
+ lhs.abbrev == rhs.abbrev,
+ TEST_WRITE_CONCATENATED("\nAbbrev:\nExpected output ", lhs.abbrev, "\nActual output ", rhs.abbrev, '\n'));
+}
+
+/***** ***** TESTS ***** *****/
+
+int main(int, const char**) {
+ using namespace std::literals::chrono_literals;
+
+ // DST starts on the first of March.
+ const std::chrono::tzdb& tzdb_1 = parse(
+ R"(
+Z Test 0 - LMT 1900
+0 Rule %s
+
+R Rule 1900 max - Mar 1 2u 1 Summer
+R Rule 1900 max - Oct 1 2u 0 Winter
+)");
+
+ const std::chrono::time_zone* tz_1 = tzdb_1.locate_zone("Test");
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1901y, std::chrono::March, 1d, 2h),
+ to_sys_seconds(1901y, std::chrono::October, 1d, 2h),
+ 1h,
+ 60min,
+ "Summer"),
+ tz_1->get_info(to_sys_seconds(1901y, std::chrono::March, 1d, 2h)));
+
+ // The DST start changes from the first of March to the first of April.
+ const std::chrono::tzdb& tzdb_2 = parse(
+ R"(
+Z Test 0 - LMT 1900
+0 Rule %s
+
+R Rule 1900 max - Apr 1 2u 1 Summer
+R Rule 1900 max - Oct 1 2u 0 Winter
+)");
+
+ const std::chrono::time_zone* tz_2 = tzdb_2.locate_zone("Test");
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1900y, std::chrono::October, 1d, 2h),
+ to_sys_seconds(1901y, std::chrono::April, 1d, 2h),
+ 0s,
+ 0min,
+ "Winter"),
+ tz_2->get_info(to_sys_seconds(1901y, std::chrono::March, 1d, 2h)));
+
+ // Validate when using tz_1 the DST still starts on the first of March.
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1901y, std::chrono::March, 1d, 2h),
+ to_sys_seconds(1901y, std::chrono::October, 1d, 2h),
+ 1h,
+ 60min,
+ "Summer"),
+ tz_1->get_info(to_sys_seconds(1901y, std::chrono::March, 1d, 2h)));
+
+ // The zone Test is no longer present
+ [[maybe_unused]] const std::chrono::tzdb& tzdb_3 = parse("Z Etc/UTC 0 - UTC");
+#ifndef TEST_HAS_NO_EXCEPTIONS
+ TEST_VALIDATE_EXCEPTION(
+ std::runtime_error,
+ [&]([[maybe_unused]] const std::runtime_error& e) {
+ std::string what = "tzdb: requested time zone not found";
+ TEST_LIBCPP_REQUIRE(
+ e.what() == what,
+ TEST_WRITE_CONCATENATED("\nExpected exception ", what, "\nActual exception ", e.what(), '\n'));
+ },
+ TEST_IGNORE_NODISCARD tzdb_3.locate_zone("Test"));
+#endif // TEST_HAS_NO_EXCEPTIONS
+
+ // Search the zone Test in the original version 1 of the TZDB.
+ // This database should be unaffected by the removal in version 3.
+ tz_1 = tzdb_1.locate_zone("Test");
+
+ // Validate the rules still uses version 1's DST switch in March.
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1901y, std::chrono::March, 1d, 2h),
+ to_sys_seconds(1901y, std::chrono::October, 1d, 2h),
+ 1h,
+ 60min,
+ "Summer"),
+ tz_1->get_info(to_sys_seconds(1901y, std::chrono::March, 1d, 2h)));
+
+ return 0;
+}
diff --git a/libcxx/test/libcxx/transitive_includes/cxx23.csv b/libcxx/test/libcxx/transitive_includes/cxx23.csv
index 69429b5bce82..9ae422a31f07 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx23.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx23.csv
@@ -80,7 +80,6 @@ chrono cstring
chrono ctime
chrono cwchar
chrono forward_list
-chrono initializer_list
chrono limits
chrono new
chrono optional
diff --git a/libcxx/test/libcxx/transitive_includes/cxx26.csv b/libcxx/test/libcxx/transitive_includes/cxx26.csv
index 69429b5bce82..9ae422a31f07 100644
--- a/libcxx/test/libcxx/transitive_includes/cxx26.csv
+++ b/libcxx/test/libcxx/transitive_includes/cxx26.csv
@@ -80,7 +80,6 @@ chrono cstring
chrono ctime
chrono cwchar
chrono forward_list
-chrono initializer_list
chrono limits
chrono new
chrono optional
diff --git a/libcxx/test/libcxx/utilities/utility/private_constructor_tag.compile.pass.cpp b/libcxx/test/libcxx/utilities/utility/private_constructor_tag.compile.pass.cpp
new file mode 100644
index 000000000000..097e05f29ceb
--- /dev/null
+++ b/libcxx/test/libcxx/utilities/utility/private_constructor_tag.compile.pass.cpp
@@ -0,0 +1,19 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// struct __private_constructor_tag{};
+
+// The private constructor tag is intended to be a trivial type that can easily
+// be used to mark a constructor exposition-only.
+//
+// Tests whether the type is trivial.
+
+#include <__utility/private_constructor_tag.h>
+#include <type_traits>
+
+static_assert(std::is_trivial<std::__private_constructor_tag>::value, "");
diff --git a/libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp b/libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp
index f84cedbc122a..58307bd88d0f 100644
--- a/libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp
+++ b/libcxx/test/std/ranges/range.utility/range.utility.conv/to_deduction.pass.cpp
@@ -9,7 +9,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20
// There is a bug in older versions of Clang that causes trouble with constraints in classes like
// `ContainerWithDirectCtr`.
-// XFAIL: clang-16, apple-clang-15
+// XFAIL: apple-clang-15
// template<template<class...> class C, input_range R, class... Args>
// constexpr auto to(R&& r, Args&&... args); // Since C++23
diff --git a/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/sys_info.members.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/sys_info.members.pass.cpp
new file mode 100644
index 000000000000..2510792c2280
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.info/time.zone.info.sys/sys_info.members.pass.cpp
@@ -0,0 +1,48 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+
+// <chrono>
+
+// struct sys_info {
+// sys_seconds begin;
+// sys_seconds end;
+// seconds offset;
+// minutes save;
+// string abbrev;
+// };
+
+// Validates whether:
+// - The members are present as non-const members.
+// - The struct is an aggregate.
+
+#include <chrono>
+#include <string>
+#include <type_traits>
+
+int main(int, const char**) {
+ static_assert(std::is_aggregate_v<std::chrono::sys_info>);
+
+ std::chrono::sys_info sys_info{
+ .begin = std::chrono::sys_seconds::min(),
+ .end = std::chrono::sys_seconds::max(),
+ .offset = std::chrono::seconds(0),
+ .save = std::chrono::minutes(0),
+ .abbrev = "UTC"};
+
+ [[maybe_unused]] std::chrono::sys_seconds& begin = sys_info.begin;
+ [[maybe_unused]] std::chrono::sys_seconds& end = sys_info.end;
+ [[maybe_unused]] std::chrono::seconds& offset = sys_info.offset;
+ [[maybe_unused]] std::chrono::minutes& save = sys_info.save;
+ [[maybe_unused]] std::string& abbrev = sys_info.abbrev;
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
index 4d91e73f38e4..6918ed6be5c1 100644
--- a/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/assign.copy.pass.cpp
@@ -27,8 +27,6 @@
#include <type_traits>
#include <cassert>
-// Add the include path required by test_chrono_leap_second.h when using libc++.
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
#include "test_chrono_leap_second.h"
constexpr bool test() {
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
index e2419b7d1f09..3dad08968d12 100644
--- a/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/cons.copy.pass.cpp
@@ -25,8 +25,6 @@
#include <concepts>
#include <cassert>
-// Add the include path required by test_chrono_leap_second.h when using libc++.
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
#include "test_chrono_leap_second.h"
constexpr bool test() {
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
index 23f95eccfdec..6f9fe1c47d35 100644
--- a/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/members/date.pass.cpp
@@ -23,8 +23,6 @@
#include "test_macros.h"
-// Add the include path required by test_chrono_leap_second.h when using libc++.
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
#include "test_chrono_leap_second.h"
constexpr void test(const std::chrono::leap_second leap_second, std::chrono::sys_seconds expected) {
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
index 844c74d002ac..652e51ef0bf1 100644
--- a/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/members/value.pass.cpp
@@ -23,8 +23,6 @@
#include "test_macros.h"
-// Add the include path required by test_chrono_leap_second.h when using libc++.
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
#include "test_chrono_leap_second.h"
constexpr void test(const std::chrono::leap_second leap_second, std::chrono::seconds expected) {
diff --git a/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
index ac8b780af854..bf6855ea63df 100644
--- a/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
+++ b/libcxx/test/std/time/time.zone/time.zone.leap/nonmembers/comparison.pass.cpp
@@ -50,8 +50,6 @@
#include "test_macros.h"
#include "test_comparisons.h"
-// Add the include path required by test_chrono_leap_second.h when using libc++.
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
#include "test_chrono_leap_second.h"
constexpr void test_comparison(const std::chrono::leap_second lhs, const std::chrono::leap_second rhs) {
diff --git a/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp
new file mode 100644
index 000000000000..2ad408968589
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/get_info.sys_time.pass.cpp
@@ -0,0 +1,1374 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// <chrono>
+
+// class time_zone;
+
+// template <class _Duration>
+// sys_info get_info(const sys_time<_Duration>& time) const;
+
+// This test uses the system provided database. This makes the test portable,
+// but may cause failures when the database information changes. Historic data
+// may change if new facts are uncovered, future data may change when regions
+// change their time zone or daylight saving time. Most tests will not look in
+// the future to attempt to avoid issues. All tests list the data on which they
+// are based, this makes debugging easier upon failure; including to see whether
+// the provided data has not been changed
+//
+//
+// The data in the tests can be validated by using the zdump tool. For
+// example
+// zdump -v Asia/Hong_Kong
+// show all transistions in the Hong Kong time zone. Or
+// zdump -c1970,1980 -v Asia/Hong_Kong
+// shows all transitions in Hong Kong between 1970 and 1980.
+
+#include <algorithm>
+#include <cassert>
+#include <chrono>
+#include <format>
+
+#include "test_macros.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+/***** ***** HELPERS ***** *****/
+
+[[nodiscard]] static std::chrono::sys_seconds to_sys_seconds(
+ std::chrono::year year,
+ std::chrono::month month,
+ std::chrono::day day,
+ std::chrono::hours h = std::chrono::hours(0),
+ std::chrono::minutes m = std::chrono::minutes{0},
+ std::chrono::seconds s = std::chrono::seconds{0}) {
+ std::chrono::year_month_day result{year, month, day};
+
+ return std::chrono::time_point_cast<std::chrono::seconds>(static_cast<std::chrono::sys_days>(result)) + h + m + s;
+}
+
+static void assert_equal(const std::chrono::sys_info& lhs, const std::chrono::sys_info& rhs) {
+ TEST_REQUIRE(lhs.begin == rhs.begin,
+ TEST_WRITE_CONCATENATED("\nBegin:\nExpected output ", lhs.begin, "\nActual output ", rhs.begin, '\n'));
+ TEST_REQUIRE(lhs.end == rhs.end,
+ TEST_WRITE_CONCATENATED("\nEnd:\nExpected output ", lhs.end, "\nActual output ", rhs.end, '\n'));
+ TEST_REQUIRE(
+ lhs.offset == rhs.offset,
+ TEST_WRITE_CONCATENATED("\nOffset:\nExpected output ", lhs.offset, "\nActual output ", rhs.offset, '\n'));
+ TEST_REQUIRE(lhs.save == rhs.save,
+ TEST_WRITE_CONCATENATED("\nSave:\nExpected output ", lhs.save, "\nActual output ", rhs.save, '\n'));
+ TEST_REQUIRE(
+ lhs.abbrev == rhs.abbrev,
+ TEST_WRITE_CONCATENATED("\nAbbrev:\nExpected output ", lhs.abbrev, "\nActual output ", rhs.abbrev, '\n'));
+}
+
+static void assert_equal(std::string_view expected, const std::chrono::sys_info& value) {
+ // Note the output of operator<< is implementation defined, use this
+ // format to keep the test portable.
+ std::string result = std::format(
+ "[{}, {}) {:%T} {:%Q%q} {}",
+ value.begin,
+ value.end,
+ std::chrono::hh_mm_ss{value.offset},
+ value.save,
+ value.abbrev);
+
+ TEST_REQUIRE(expected == result,
+ TEST_WRITE_CONCATENATED("\nExpected output ", expected, "\nActual output ", result, '\n'));
+}
+
+static void
+assert_range(std::string_view expected, const std::chrono::sys_info& begin, const std::chrono::sys_info& end) {
+ assert_equal(expected, begin);
+ assert_equal(expected, end);
+}
+
+static void assert_cycle(
+ std::string_view expected_1,
+ const std::chrono::sys_info& begin_1,
+ const std::chrono::sys_info& end_1,
+ std::string_view expected_2,
+ const std::chrono::sys_info& begin_2,
+ const std::chrono::sys_info& end_2
+
+) {
+ assert_range(expected_1, begin_1, end_1);
+ assert_range(expected_2, begin_2, end_2);
+}
+
+/***** ***** TESTS ***** *****/
+
+static void test_gmt() {
+ // Simple zone always valid, no rule entries, lookup using a link.
+ // L Etc/GMT GMT
+ // Z Etc/GMT 0 - GMT
+
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ std::chrono::sys_seconds::max(),
+ std::chrono::seconds(0),
+ std::chrono::minutes(0),
+ "GMT"),
+ tz->get_info(std::chrono::sys_seconds::min()));
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ std::chrono::sys_seconds::max(),
+ std::chrono::seconds(0),
+ std::chrono::minutes(0),
+ "GMT"),
+ tz->get_info(std::chrono::sys_seconds(std::chrono::seconds{0})));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ std::chrono::sys_seconds::max(),
+ std::chrono::seconds(0),
+ std::chrono::minutes(0),
+ "GMT"),
+ tz->get_info(std::chrono::sys_seconds::max() - std::chrono::seconds{1})); // max is not valid
+}
+
+static void test_durations() {
+ // Doesn't test a location, instead tests whether different duration
+ // specializations work.
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("GMT");
+
+ // Using the GMT zone means every call gives the same result.
+ std::chrono::sys_info expected(
+ std::chrono::sys_seconds::min(),
+ std::chrono::sys_seconds::max(),
+ std::chrono::seconds(0),
+ std::chrono::minutes(0),
+ "GMT");
+
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::nanoseconds>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::microseconds>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::milliseconds>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::seconds>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::minutes>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::minutes>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::hours>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::days>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::weeks>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::months>{}));
+ assert_equal(expected, tz->get_info(std::chrono::sys_time<std::chrono::years>{}));
+}
+
+static void test_indian_kerguelen() {
+ // One change, no rules, no dst changes.
+
+ // Z Indian/Kerguelen 0 - -00 1950
+ // 5 - +05
+
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Indian/Kerguelen");
+
+ std::chrono::sys_seconds transition =
+ to_sys_seconds(std::chrono::year(1950), std::chrono::January, std::chrono::day(1));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(), //
+ transition, //
+ std::chrono::seconds(0), //
+ std::chrono::minutes(0), //
+ "-00"), //
+ tz->get_info(std::chrono::sys_seconds::min()));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(), //
+ transition, //
+ std::chrono::seconds(0), //
+ std::chrono::minutes(0), //
+ "-00"), //
+ tz->get_info(transition - std::chrono::seconds{1}));
+
+ assert_equal(
+ std::chrono::sys_info(
+ transition, //
+ std::chrono::sys_seconds::max(), //
+ std::chrono::hours(5), //
+ std::chrono::minutes(0), //
+ "+05"), //
+ tz->get_info(transition));
+}
+
+static void test_antarctica_syowa() {
+ // One change, no rules, no dst changes
+ // This change uses an ON field with a day number
+ //
+ // There don't seem to be rule-less zones that use last day or a
+ // contrained day
+
+ // Z Antarctica/Syowa 0 - -00 1957 Ja 29
+ // 3 - +03
+
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Antarctica/Syowa");
+
+ std::chrono::sys_seconds transition =
+ to_sys_seconds(std::chrono::year(1957), std::chrono::January, std::chrono::day(29));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(), //
+ transition, //
+ std::chrono::seconds(0), //
+ std::chrono::minutes(0), //
+ "-00"), //
+ tz->get_info(std::chrono::sys_seconds::min()));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(), //
+ transition, //
+ std::chrono::seconds(0), //
+ std::chrono::minutes(0), //
+ "-00"), //
+ tz->get_info(transition - std::chrono::seconds(1)));
+
+ assert_equal(
+ std::chrono::sys_info(
+ transition, //
+ std::chrono::sys_seconds::max(), //
+ std::chrono::hours(3), //
+ std::chrono::minutes(0), //
+ "+03"), //
+ tz->get_info(transition));
+}
+
+static void test_asia_hong_kong() {
+ // A more typical entry, first some hard-coded entires and then at the
+ // end a rules based entry. This rule is valid for its entire period
+ //
+ // Z Asia/Hong_Kong 7:36:42 - LMT 1904 O 30 0:36:42
+ // 8 - HKT 1941 Jun 15 3
+ // 8 1 HKST 1941 O 1 4
+ // 8 0:30 HKWT 1941 D 25
+ // 9 - JST 1945 N 18 2
+ // 8 HK HK%sT
+ //
+ // R HK 1946 o - Ap 21 0 1 S
+ // R HK 1946 o - D 1 3:30s 0 -
+ // R HK 1947 o - Ap 13 3:30s 1 S
+ // R HK 1947 o - N 30 3:30s 0 -
+ // R HK 1948 o - May 2 3:30s 1 S
+ // R HK 1948 1952 - O Su>=28 3:30s 0 -
+ // R HK 1949 1953 - Ap Su>=1 3:30 1 S
+ // R HK 1953 1964 - O Su>=31 3:30 0 -
+ // R HK 1954 1964 - Mar Su>=18 3:30 1 S
+ // R HK 1965 1976 - Ap Su>=16 3:30 1 S
+ // R HK 1965 1976 - O Su>=16 3:30 0 -
+ // R HK 1973 o - D 30 3:30 1 S
+ // R HK 1979 o - May 13 3:30 1 S
+ // R HK 1979 o - O 21 3:30 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Hong_Kong");
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1904y, std::chrono::October, 29d, 17h), // 7:36:42 - LMT 1904 O 30 0:36:42
+ 7h + 36min + 42s,
+ 0min,
+ "LMT"),
+ tz->get_info(std::chrono::sys_seconds::min()));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1904y, std::chrono::October, 29d, 17h), // 7:36:42 - LMT 1904 O 30 0:36:42
+ 7h + 36min + 42s,
+ 0min,
+ "LMT"),
+ tz->get_info(to_sys_seconds(1904y, std::chrono::October, 29d, 16h, 59min, 59s)));
+
+ assert_range("[1904-10-29 17:00:00, 1941-06-14 19:00:00) 08:00:00 0min HKT", // 8 - HKT 1941 Jun 15 3
+ tz->get_info(to_sys_seconds(1904y, std::chrono::October, 29d, 17h)),
+ tz->get_info(to_sys_seconds(1941y, std::chrono::June, 14d, 18h, 59min, 59s)));
+
+ assert_range("[1941-06-14 19:00:00, 1941-09-30 19:00:00) 09:00:00 60min HKST", // 8 1 HKST 1941 O 1 4
+ tz->get_info(to_sys_seconds(1941y, std::chrono::June, 14d, 19h)),
+ tz->get_info(to_sys_seconds(1941y, std::chrono::September, 30d, 18h, 59min, 59s)));
+
+ assert_range("[1941-09-30 19:00:00, 1941-12-24 15:30:00) 08:30:00 30min HKWT", // 8 0:30 HKWT 1941 D 25
+ tz->get_info(to_sys_seconds(1941y, std::chrono::September, 30d, 19h)),
+ tz->get_info(to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 29min, 59s)));
+
+ assert_range("[1941-12-24 15:30:00, 1945-11-17 17:00:00) 09:00:00 0min JST", // 9 - JST 1945 N 18 2
+ tz->get_info(to_sys_seconds(1941y, std::chrono::December, 24d, 15h, 30min)),
+ tz->get_info(to_sys_seconds(1945y, std::chrono::November, 17d, 16h, 59min, 59s)));
+
+ assert_range("[1945-11-17 17:00:00, 1946-04-20 16:00:00) 08:00:00 0min HKT", // 8 HK%sT
+ tz->get_info(to_sys_seconds(1945y, std::chrono::November, 17d, 17h)),
+ tz->get_info(to_sys_seconds(1946y, std::chrono::April, 20d, 15h, 59min, 59s)));
+
+ assert_cycle( // 8 HK%sT
+ "[1946-04-20 16:00:00, 1946-11-30 19:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1946y, std::chrono::April, 20d, 16h)), // 1946 o Ap 21 0 1 S
+ tz->get_info(to_sys_seconds(1946y, std::chrono::November, 30d, 19h, 29min, 59s)), // 1946 o D 1 3:30s 0 -
+ "[1946-11-30 19:30:00, 1947-04-12 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1946y, std::chrono::November, 30d, 19h, 30min)), // 1946 o D 1 3:30s 0 -
+ tz->get_info(to_sys_seconds(1947y, std::chrono::April, 12d, 19h, 29min, 59s))); // 1947 o Ap 13 3:30s 1 S
+
+ assert_cycle( // 8 HK%sT
+ "[1947-04-12 19:30:00, 1947-11-29 19:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::April, 12d, 19h, 30min)), // 1947 o Ap 13 3:30s 1 S
+ tz->get_info(to_sys_seconds(1947y, std::chrono::November, 29d, 19h, 29min, 59s)), // 1947 o N 30 3:30s 0 -
+ "[1947-11-29 19:30:00, 1948-05-01 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::November, 29d, 19h, 30min)), // 1947 o N 30 3:30s 0 -
+ tz->get_info(to_sys_seconds(1948y, std::chrono::May, 1d, 19h, 29min, 59s))); // 1948 o May 2 3:30s 1 S
+
+ assert_cycle( // 8 HK%sT
+ "[1948-05-01 19:30:00, 1948-10-30 19:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1948y, std::chrono::May, 1d, 19h, 30min)), // 1948 o May 2 3:30s 1 S
+ tz->get_info(to_sys_seconds(1948y, std::chrono::October, 30d, 19h, 29min, 59s)), // 1948 1952 O Su>=28 3:30s 0 -
+ "[1948-10-30 19:30:00, 1949-04-02 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1948y, std::chrono::October, 30d, 19h, 30min)), // 1948 1952 O Su>=28 3:30s 0 -
+ tz->get_info(to_sys_seconds(1949y, std::chrono::April, 2d, 19h, 29min, 59s))); // 1949 1953 Ap Su>=1 3:30 1 S
+
+ assert_cycle( // 8 HK%sT
+ "[1949-04-02 19:30:00, 1949-10-29 19:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1949y, std::chrono::April, 2d, 19h, 30min)), // 1949 1953 Ap Su>=1 3:30 1 S
+ tz->get_info(to_sys_seconds(1949y, std::chrono::October, 29d, 19h, 29min, 59s)), // 1948 1952 O Su>=28 3:30s 0
+ "[1949-10-29 19:30:00, 1950-04-01 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1949y, std::chrono::October, 29d, 19h, 30min)), // 1948 1952 O Su>=28 3:30s 0
+ tz->get_info(to_sys_seconds(1950y, std::chrono::April, 1d, 19h, 29min, 59s))); // 1949 1953 Ap Su>=1 3:30 1 S
+
+ assert_range(
+ "[1953-10-31 18:30:00, 1954-03-20 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 30min)), // 1953 1964 - O Su>=31 3:30 0 -
+ tz->get_info(to_sys_seconds(1954y, std::chrono::March, 20d, 19h, 29min, 59s))); // 1954 1964 - Mar Su>=18 3:30 1 S
+
+ assert_cycle( // 8 HK%sT
+ "[1953-04-04 19:30:00, 1953-10-31 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1953y, std::chrono::April, 4d, 19h, 30min)), // 1949 1953 Ap Su>=1 3:30 1 S
+ tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 29min, 59s)), // 1953 1964 - O Su>=31 3:30 0 -
+ "[1953-10-31 18:30:00, 1954-03-20 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1953y, std::chrono::October, 31d, 18h, 30min)), // 1953 1964 - O Su>=31 3:30 0 -
+ tz->get_info(to_sys_seconds(1954y, std::chrono::March, 20d, 19h, 29min, 59s))); // 1954 1964 - Mar Su>=18 3:30 1 S
+
+ assert_cycle( // 8 HK%sT
+ "[1972-04-15 19:30:00, 1972-10-21 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1972y, std::chrono::April, 19d, 19h, 30min)), // 1965 1976 - Ap Su>=16 3:30 1 S
+ tz->get_info(to_sys_seconds(1972y, std::chrono::October, 21d, 18h, 29min, 59s)), // 1965 1976 - O Su>=16 3:30 0 -
+ "[1972-10-21 18:30:00, 1973-04-21 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1972y, std::chrono::October, 21d, 18h, 30min)), // 1965 1976 - O Su>=16 3:30 0 -
+ tz->get_info(to_sys_seconds(1973y, std::chrono::April, 21d, 19h, 29min, 59s))); // 1965 1976 - Ap Su>=16 3:30 1 S
+
+ assert_range( // 8 HK%sT
+ "[1973-04-21 19:30:00, 1973-10-20 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1973y, std::chrono::April, 21d, 19h, 30min)), // 1965 1976 - Ap Su>=16 3:30 1 S
+ tz->get_info(to_sys_seconds(1973y, std::chrono::October, 20d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30 0 -
+
+ assert_range( // 8 HK%sT, test "1973 o - D 30 3:30 1 S"
+ "[1973-10-20 18:30:00, 1973-12-29 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1973y, std::chrono::October, 20d, 18h, 30min)), // 1965 1976 - O Su>=16 3:30
+ tz->get_info(to_sys_seconds(1973y, std::chrono::December, 29d, 19h, 29min, 59s))); // 1973 o - D 30 3:30 1 S
+
+ assert_range( // 8 HK%sT
+ "[1973-12-29 19:30:00, 1974-10-19 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1973y, std::chrono::December, 29d, 19h, 30min)), // 1973 o - D 30 3:30 1 S
+ tz->get_info(to_sys_seconds(1974y, std::chrono::October, 19d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30
+
+ assert_range( // 8 HK%sT, between 1973 and 1979 no rule is active so falls back to default
+ "[1976-04-17 19:30:00, 1976-10-16 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1976y, std::chrono::April, 17d, 19h, 30min)), // 1965 1976 - Ap Su>=16 3:30 1 S
+ tz->get_info(to_sys_seconds(1976y, std::chrono::October, 16d, 18h, 29min, 59s))); // 1965 1976 - O Su>=16 3:30 0 -
+
+ assert_range( // 8 HK%sT, between 1973 and 1979 no rule is active so falls back to default
+ "[1976-10-16 18:30:00, 1979-05-12 19:30:00) 08:00:00 0min HKT",
+ tz->get_info(to_sys_seconds(1976y, std::chrono::October, 16d, 18h, 30min)), // 1965 1976 - O Su>=16 3:30 0 -
+ tz->get_info(to_sys_seconds(1979y, std::chrono::May, 12d, 19h, 29min, 59s))); // 1979 o - May 13 3:30 1 S
+
+ assert_range( // 8 HK%sT
+ "[1979-05-12 19:30:00, 1979-10-20 18:30:00) 09:00:00 60min HKST",
+ tz->get_info(to_sys_seconds(1979y, std::chrono::May, 12d, 19h, 30min)), // 1979 o - May 13 3:30 1 S
+ tz->get_info(to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 29min, 59s))); // 1979 o - O 21 3:30 0 -
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min),
+ std::chrono::sys_seconds::max(),
+ 8h,
+ std::chrono::minutes(0),
+ "HKT"),
+ tz->get_info(to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min)));
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1979y, std::chrono::October, 20d, 18h, 30min),
+ std::chrono::sys_seconds::max(),
+ 8h,
+ std::chrono::minutes(0),
+ "HKT"),
+ tz->get_info(std::chrono::sys_seconds::max() - std::chrono::seconds{1})); // max is not valid
+}
+
+static void test_europe_berlin() {
+ // A more typical entry, first some hard-coded entires and then at the
+ // end a rules based entry. This rule is valid for its entire period
+ //
+
+ // Z Europe/Berlin 0:53:28 - LMT 1893 Ap
+ // 1 c CE%sT 1945 May 24 2
+ // 1 So CE%sT 1946
+ // 1 DE CE%sT 1980
+ // 1 E CE%sT
+ //
+ // R c 1916 o - Ap 30 23 1 S
+ // R c 1916 o - O 1 1 0 -
+ // R c 1917 1918 - Ap M>=15 2s 1 S
+ // R c 1917 1918 - S M>=15 2s 0 -
+ // R c 1940 o - Ap 1 2s 1 S
+ // R c 1942 o - N 2 2s 0 -
+ // R c 1943 o - Mar 29 2s 1 S
+ // R c 1943 o - O 4 2s 0 -
+ // R c 1944 1945 - Ap M>=1 2s 1 S
+ // R c 1944 o - O 2 2s 0 -
+ // R c 1945 o - S 16 2s 0 -
+ // R c 1977 1980 - Ap Su>=1 2s 1 S
+ // R c 1977 o - S lastSu 2s 0 -
+ // R c 1978 o - O 1 2s 0 -
+ // R c 1979 1995 - S lastSu 2s 0 -
+ // R c 1981 ma - Mar lastSu 2s 1 S
+ // R c 1996 ma - O lastSu 2s 0 -
+ //
+ // R So 1945 o - May 24 2 2 M
+ // R So 1945 o - S 24 3 1 S
+ // R So 1945 o - N 18 2s 0 -
+ //
+ // R DE 1946 o - Ap 14 2s 1 S
+ // R DE 1946 o - O 7 2s 0 -
+ // R DE 1947 1949 - O Su>=1 2s 0 -
+ // R DE 1947 o - Ap 6 3s 1 S
+ // R DE 1947 o - May 11 2s 2 M
+ // R DE 1947 o - Jun 29 3 1 S
+ // R DE 1948 o - Ap 18 2s 1 S
+ // R DE 1949 o - Ap 10 2s 1 S
+ //
+ // R E 1977 1980 - Ap Su>=1 1u 1 S
+ // R E 1977 o - S lastSu 1u 0 -
+ // R E 1978 o - O 1 1u 0 -
+ // R E 1979 1995 - S lastSu 1u 0 -
+ // R E 1981 ma - Mar lastSu 1u 1 S
+ // R E 1996 ma - O lastSu 1u 0 -
+ //
+ // Note the European Union decided to stop the seasonal change in
+ // 2021. In 2023 seasonal changes are still in effect.
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Europe/Berlin");
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s), // 0:53:28 - LMT 1893 Ap
+ 53min + 28s,
+ 0min,
+ "LMT"),
+ tz->get_info(std::chrono::sys_seconds::min()));
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s), // 0:53:28 - LMT 1893 Ap
+ 53min + 28s,
+ 0min,
+ "LMT"),
+ tz->get_info(to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 31s)));
+
+ assert_range(
+ // 1 CE%sT before 1916 o - Ap 30 23 1 S
+ "[1893-03-31 23:06:32, 1916-04-30 22:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1893y, std::chrono::March, 31d, 23h, 6min, 32s)),
+ tz->get_info(to_sys_seconds(1916y, std::chrono::April, 30d, 21h, 59min, 59s)));
+
+ assert_cycle(
+ // 1 CE%sT
+ "[1916-04-30 22:00:00, 1916-09-30 23:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1916y, std::chrono::April, 30d, 22h)), // 1916 o - Ap 30 23 1 S
+ tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 22h, 59min, 59s)), // o - O 1 1 0 -
+ "[1916-09-30 23:00:00, 1917-04-16 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 23h)), // o - O 1 1 0 -
+ tz->get_info(to_sys_seconds(1917y, std::chrono::April, 16d, 0h, 59min, 59s))); // 1917 1918 - Ap M>=15 2s 1 S
+
+ assert_cycle(
+ // 1 CE%sT
+ "[1917-04-16 01:00:00, 1917-09-17 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1917y, std::chrono::April, 16d, 1h)), // 1917 1918 Ap M>=15 2s 1 S
+ tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 0h, 59min, 59s)), // 1917 1918 S M>=15 2s 0 -
+ "[1917-09-17 01:00:00, 1918-04-15 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 1h)), // 1917 1918 S M>=15 2s 0 -
+ tz->get_info(to_sys_seconds(1918y, std::chrono::April, 15d, 0h, 59min, 59s))); // 1917 1918 Ap M>=15 2s 1 S
+
+ assert_cycle(
+ // 1 CE%sT (The cycle is more than 1 year)
+ "[1918-04-15 01:00:00, 1918-09-16 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1918y, std::chrono::April, 15d, 1h)), // 1917 1918 Ap M>=15 2s 1 S
+ tz->get_info(to_sys_seconds(1918y, std::chrono::September, 16d, 0h, 59min, 59s)), // 1917 1918 S M>=15 2s 0 -
+ "[1918-09-16 01:00:00, 1940-04-01 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1918y, std::chrono::September, 16d, 1h)), // 1917 1918 S M>=15 2s 0 -
+ tz->get_info(to_sys_seconds(1940y, std::chrono::April, 1d, 0h, 59min, 59s))); // 1940 o Ap 1 2s 1 S
+
+ assert_cycle(
+ // 1 CE%sT (The cycle is more than 1 year)
+ "[1940-04-01 01:00:00, 1942-11-02 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1940y, std::chrono::April, 1d, 1h)), // 1940 o Ap 1 2s 1 S
+ tz->get_info(to_sys_seconds(1942y, std::chrono::November, 2d, 0h, 59min, 59s)), // 1942 o N 2 2s 0 -
+ "[1942-11-02 01:00:00, 1943-03-29 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1942y, std::chrono::November, 2d, 1h)), // 1942 o N 2 2s 0 -
+ tz->get_info(to_sys_seconds(1943y, std::chrono::March, 29d, 0h, 59min, 59s))); // 1943 o Mar 29 2s 1 S
+
+ assert_range(
+ // Here the zone changes from c (C-Eur) to So (SovietZone).
+ // The rule c ends on 1945-09-16, instead it ends at the zone change date/time
+ // There is a tricky part in the time
+ // "1 c CE%sT" has an offset of 1 at the moment the rule
+ // ends there is a save of 60 minutes. This means the
+ // local offset to UTC is 2 hours. The rule ends at
+ // 1945-05-24 02:00:00 local time, which is
+ // 1945-05-24 00:00:00 UTC.
+ "[1945-04-02 01:00:00, 1945-05-24 00:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1945y, std::chrono::April, 2d, 1h)), // 1 CE%sT & 1945 Ap M>=1 2s 1 S
+ tz->get_info(to_sys_seconds(1945y, std::chrono::May, 23d, 23h, 59min, 59s))); // 1 c CE%sT & 1945 May 24 2
+
+ assert_range( // --
+ "[1945-05-24 00:00:00, 1945-09-24 00:00:00) 03:00:00 120min CEMT",
+ tz->get_info(to_sys_seconds(1945y, std::chrono::May, 24d)), // 1 c CE%sT & 1945 May 24 2
+ tz->get_info(to_sys_seconds(1945y, std::chrono::September, 23d, 23h, 59min, 59s))); // 1945 o S 24 3 1 S
+
+ assert_range(
+ // 1 c CE%sT 1945 May 24 2
+ "[1945-09-24 00:00:00, 1945-11-18 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1945y, std::chrono::September, 24d)), // 1945 o S 24 3 1 S
+ tz->get_info(to_sys_seconds(1945y, std::chrono::November, 18d, 0h, 59min, 59s))); // 1945 o N 18 2s 0 -
+ assert_range( // --
+ // Merges 2 continuations
+ "[1945-11-18 01:00:00, 1946-04-14 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1945y, std::chrono::November, 18d, 1h)), // 1 c CE%sT & 1945 o N 18 2s 0 -
+ tz->get_info(to_sys_seconds(1946y, std::chrono::April, 14d, 0h, 59min, 59s))); // 1 So CE%sT & 1946 o Ap 14 2s 1 S
+
+ assert_range(
+ // 1 DE CE%sT 1980
+ "[1946-04-14 01:00:00, 1946-10-07 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1946y, std::chrono::April, 14d, 1h)), // 1946 o Ap 14 2s 1 S
+ tz->get_info(to_sys_seconds(1946y, std::chrono::October, 7d, 0h, 59min, 59s))); // 1946 o O 7 2s 0 -
+
+ // Note 1947 is an interesting year with 4 rules
+ // R DE 1947 1949 - O Su>=1 2s 0 -
+ // R DE 1947 o - Ap 6 3s 1 S
+ // R DE 1947 o - May 11 2s 2 M
+ // R DE 1947 o - Jun 29 3 1 S
+ assert_range(
+ // 1 DE CE%sT 1980
+ "[1946-10-07 01:00:00, 1947-04-06 02:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1946y, std::chrono::October, 7d, 1h)), // 1946 o O 7 2s 0 -
+ tz->get_info(to_sys_seconds(1947y, std::chrono::April, 6d, 1h, 59min, 59s))); // 1947 o Ap 6 3s 1 S
+
+ assert_range(
+ // 1 DE CE%sT 1980
+ "[1947-04-06 02:00:00, 1947-05-11 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::April, 6d, 2h)), // 1947 o Ap 6 3s 1 S
+ tz->get_info(to_sys_seconds(1947y, std::chrono::May, 11d, 0h, 59min, 59s))); // 1947 o May 11 2s 2 M
+
+ assert_range(
+ // 1 DE CE%sT 1980
+ "[1947-05-11 01:00:00, 1947-06-29 00:00:00) 03:00:00 120min CEMT",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::May, 11d, 1h)), // 1947 o May 11 2s 2 M
+ tz->get_info(to_sys_seconds(1947y, std::chrono::June, 28d, 23h, 59min, 59s))); // 1947 o Jun 29 3 1 S
+
+ assert_cycle(
+ // 1 DE CE%sT 1980
+ "[1947-06-29 00:00:00, 1947-10-05 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::June, 29d)), // 1947 o Jun 29 3 1 S
+ tz->get_info(to_sys_seconds(1947y, std::chrono::October, 5d, 0h, 59min, 59s)), // 1947 1949 O Su>=1 2s 0 -
+ "[1947-10-05 01:00:00, 1948-04-18 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1947y, std::chrono::October, 5d, 1h)), // 1947 1949 O Su>=1 2s 0 -
+ tz->get_info(to_sys_seconds(1948y, std::chrono::April, 18d, 0h, 59min, 59s))); // 1948 o Ap 18 2s 1 S
+
+ assert_cycle(
+ // 1 DE CE%sT 1980
+ "[1948-04-18 01:00:00, 1948-10-03 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(1948y, std::chrono::April, 18d, 1h)), // 1948 o Ap 18 2s 1 S
+ tz->get_info(to_sys_seconds(1948y, std::chrono::October, 3d, 0h, 59min, 59s)), // 1947 1949 O Su>=1 2s 0 -
+ "[1948-10-03 01:00:00, 1949-04-10 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1948y, std::chrono::October, 3d, 1h)), // 1947 1949 O Su>=1 2s 0 -
+ tz->get_info(to_sys_seconds(1949y, std::chrono::April, 10d, 0h, 59min, 59s))); // 1949 o Ap 10 2s 1 S
+
+ assert_cycle( // Note the end time is in a different continuation.
+ "[1949-04-10 01:00:00, 1949-10-02 01:00:00) 02:00:00 60min CEST", // 1 DE CE%sT 1980
+ tz->get_info(to_sys_seconds(1949y, std::chrono::April, 10d, 1h)), // 1949 o Ap 10 2s 1 S
+ tz->get_info(to_sys_seconds(1949y, std::chrono::October, 2d, 0h, 59min, 59s)), // 1947 1949 O Su>=1 2s 0 -
+ "[1949-10-02 01:00:00, 1980-04-06 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(1949y, std::chrono::October, 2d, 1h)), // 1947 1949 O Su>=1 2s 0 -
+ tz->get_info( // 1 E CE%sT
+ to_sys_seconds(1980y, std::chrono::April, 6d, 0h, 59min, 59s))); // 1977 1980 Ap Su>=1 1u 1 S
+
+ assert_cycle(
+ // 1 E CE%sT
+ "[2020-03-29 01:00:00, 2020-10-25 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 1h)), // 1981 ma Mar lastSu 1u 1 S
+ tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -
+ "[2020-10-25 01:00:00, 2021-03-28 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 1h)), // 1996 ma O lastSu 1u 0 -
+ tz->get_info(to_sys_seconds(2021y, std::chrono::March, 28d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S
+
+ assert_cycle(
+ // 1 E CE%sT
+ "[2021-03-28 01:00:00, 2021-10-31 01:00:00) 02:00:00 60min CEST",
+ tz->get_info(to_sys_seconds(2021y, std::chrono::March, 28d, 1h)), // 1981 ma Mar lastSu 1u 1 S
+ tz->get_info(to_sys_seconds(2021y, std::chrono::October, 31d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -
+ "[2021-10-31 01:00:00, 2022-03-27 01:00:00) 01:00:00 0min CET",
+ tz->get_info(to_sys_seconds(2021y, std::chrono::October, 31d, 1h)), // 1996 ma O lastSu 1u 0 -
+ tz->get_info(to_sys_seconds(2022y, std::chrono::March, 27d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S
+}
+
+static void test_america_st_johns() {
+ // A more typical entry,
+ // Uses letters both when DST is ative and not and has multiple
+ // letters. Uses negetive offsets.
+ // Switches several times between their own and Canadian rules
+ // Switches the stdoff from -3:30:52 to -3:30 while observing the same rule
+
+ // Z America/St_Johns -3:30:52 - LMT 1884
+ // -3:30:52 j N%sT 1918
+ // -3:30:52 C N%sT 1919
+ // -3:30:52 j N%sT 1935 Mar 30
+ // -3:30 j N%sT 1942 May 11
+ // -3:30 C N%sT 1946
+ // -3:30 j N%sT 2011 N
+ // -3:30 C N%sT
+ //
+ // R j 1917 o - Ap 8 2 1 D
+ // R j 1917 o - S 17 2 0 S
+ // R j 1919 o - May 5 23 1 D
+ // R j 1919 o - Au 12 23 0 S
+ // R j 1920 1935 - May Su>=1 23 1 D
+ // R j 1920 1935 - O lastSu 23 0 S
+ // R j 1936 1941 - May M>=9 0 1 D
+ // R j 1936 1941 - O M>=2 0 0 S
+ // R j 1946 1950 - May Su>=8 2 1 D
+ // R j 1946 1950 - O Su>=2 2 0 S
+ // R j 1951 1986 - Ap lastSu 2 1 D
+ // R j 1951 1959 - S lastSu 2 0 S
+ // R j 1960 1986 - O lastSu 2 0 S
+ // R j 1987 o - Ap Su>=1 0:1 1 D
+ // R j 1987 2006 - O lastSu 0:1 0 S
+ // R j 1988 o - Ap Su>=1 0:1 2 DD
+ // R j 1989 2006 - Ap Su>=1 0:1 1 D
+ // R j 2007 2011 - Mar Su>=8 0:1 1 D
+ // R j 2007 2010 - N Su>=1 0:1 0 S
+ //
+ // R C 1918 o - Ap 14 2 1 D
+ // R C 1918 o - O 27 2 0 S
+ // R C 1942 o - F 9 2 1 W
+ // R C 1945 o - Au 14 23u 1 P
+ // R C 1945 o - S 30 2 0 S
+ // R C 1974 1986 - Ap lastSu 2 1 D
+ // R C 1974 2006 - O lastSu 2 0 S
+ // R C 1987 2006 - Ap Su>=1 2 1 D
+ // R C 2007 ma - Mar Su>=8 2 1 D
+ // R C 2007 ma - N Su>=1 2 0 S
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/St_Johns");
+
+ assert_equal( // --
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s), // -3:30:52 - LMT 1884
+ -(3h + 30min + 52s),
+ 0min,
+ "LMT"),
+ tz->get_info(std::chrono::sys_seconds::min()));
+
+ assert_equal( // --
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s), // -3:30:52 - LMT 1884
+ -(3h + 30min + 52s),
+ 0min,
+ "LMT"),
+ tz->get_info(to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 51s)));
+
+ assert_range( // -3:30:52 j N%sT 1918
+ "[1884-01-01 03:30:52, 1917-04-08 05:30:52) -03:30:52 0min NST",
+ tz->get_info(to_sys_seconds(1884y, std::chrono::January, 1d, 3h, 30min, 52s)), // no rule active
+ tz->get_info(to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 51s))); // 1917 o Ap 8 2 1 D
+
+ assert_range( // -3:30:52 j N%sT 1918
+ "[1917-04-08 05:30:52, 1917-09-17 04:30:52) -02:30:52 60min NDT",
+ tz->get_info(to_sys_seconds(1917y, std::chrono::April, 8d, 5h, 30min, 52s)), // 1917 o Ap 8 2 1 D
+ tz->get_info(to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 51s))); // 1917 o S 17 2 0 S
+
+ assert_range("[1917-09-17 04:30:52, 1918-04-14 05:30:52) -03:30:52 0min NST",
+ tz->get_info( // -3:30:52 j N%sT 1918
+ to_sys_seconds(1917y, std::chrono::September, 17d, 4h, 30min, 52s)), // 1917 o S 17 2 0 S
+ tz->get_info( // -3:30:52 C N%sT 1919
+ to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 51s))); // 1918 o Ap 14 2 1 D
+
+ assert_range( // -3:30:52 C N%sT 1919
+ "[1918-04-14 05:30:52, 1918-10-27 04:30:52) -02:30:52 60min NDT",
+ tz->get_info(to_sys_seconds(1918y, std::chrono::April, 14d, 5h, 30min, 52s)), // 1918 o Ap 14 2 1 D
+ tz->get_info(to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 51s))); // 1918 o O 27 2 0 S
+
+ assert_range("[1918-10-27 04:30:52, 1919-05-06 02:30:52) -03:30:52 0min NST",
+ tz->get_info( // -3:30:52 C N%sT 1919
+ to_sys_seconds(1918y, std::chrono::October, 27d, 4h, 30min, 52s)), // 1918 o O 27 2 0 S
+ tz->get_info( // -3:30:52 j N%sT 1935 Mar 30
+ to_sys_seconds(1919y, std::chrono::May, 6d, 2h, 30min, 51s))); // 1919 o May 5 23 1 D
+
+ assert_range( // -3:30:52 j N%sT 1935 Mar 30
+ "[1934-10-29 01:30:52, 1935-03-30 03:30:52) -03:30:52 0min NST",
+ tz->get_info(to_sys_seconds(1934y, std::chrono::October, 29d, 1h, 30min, 52s)), // 1920 1935 O lastSu 23 0 S
+ tz->get_info(to_sys_seconds(1935y, std::chrono::March, 30d, 3h, 30min, 51s))); // 1920 1935 May Su>=1 23 1 D
+
+ assert_range( // -3:30 j N%sT 1942 May 11
+ // Changed the stdoff while the same rule remains active.
+ "[1935-03-30 03:30:52, 1935-05-06 02:30:00) -03:30:00 0min NST",
+ tz->get_info(to_sys_seconds(1935y, std::chrono::March, 30d, 3h, 30min, 52s)), // 1920 1935 O lastSu 23 0 S
+ tz->get_info(to_sys_seconds(1935y, std::chrono::May, 6d, 2h, 29min, 59s))); // 1920 1935 May Su>=1 23 1 D
+
+ assert_range( // -3:30 j N%sT 1942 May 11
+ "[1935-05-06 02:30:00, 1935-10-28 01:30:00) -02:30:00 60min NDT",
+ tz->get_info(to_sys_seconds(1935y, std::chrono::May, 6d, 2h, 30min, 0s)), // 1920 1935 May Su>=1 23 1 D
+ tz->get_info(to_sys_seconds(1935y, std::chrono::October, 28d, 1h, 29min, 59s))); // 1920 1935 O lastSu 23 0 S
+
+ assert_range( // -3:30 j N%sT 1942 May 11
+ "[1941-10-06 02:30:00, 1942-05-11 03:30:00) -03:30:00 0min NST",
+ tz->get_info(to_sys_seconds(1941y, std::chrono::October, 6d, 2h, 30min, 0s)), // 1936 1941 O M>=2 0 0 S
+ tz->get_info(to_sys_seconds(1942y, std::chrono::May, 11d, 3h, 29min, 59s))); // 1946 1950 May Su>=8 2 1 D
+
+ assert_range( // -3:30 C N%sT 1946
+ "[1942-05-11 03:30:00, 1945-08-14 23:00:00) -02:30:00 60min NWT",
+ tz->get_info(to_sys_seconds(1942y, std::chrono::May, 11d, 3h, 30min, 0s)), // 1942 o F 9 2 1 W
+ tz->get_info(to_sys_seconds(1945y, std::chrono::August, 14d, 22h, 59min, 59s))); // 1945 o Au 14 23u 1 P
+
+ assert_range( // -3:30 C N%sT 1946
+ "[1945-08-14 23:00:00, 1945-09-30 04:30:00) -02:30:00 60min NPT",
+ tz->get_info(to_sys_seconds(1945y, std::chrono::August, 14d, 23h, 0min, 0s)), // 1945 o Au 14 23u 1 P
+ tz->get_info(to_sys_seconds(1945y, std::chrono::September, 30d, 4h, 29min, 59s))); // 1945 o S 30 2 0 S
+
+ assert_range(
+ "[1945-09-30 04:30:00, 1946-05-12 05:30:00) -03:30:00 0min NST",
+ tz->get_info(
+ to_sys_seconds(1945y, std::chrono::September, 30d, 4h, 30min, 0s)), // -3:30 C N%sT 1946 & 945 o S 30 2 0 S
+ tz->get_info(to_sys_seconds(
+ 1946y, std::chrono::May, 12d, 5h, 29min, 59s))); // -3:30 j N%sT 2011 N & 1946 1950 May Su>=8 2 1 D
+
+ assert_range( // -3:30 j N%sT 2011 N
+ "[1988-04-03 03:31:00, 1988-10-30 01:31:00) -01:30:00 120min NDDT",
+ tz->get_info(to_sys_seconds(1988y, std::chrono::April, 3d, 3h, 31min, 0s)), // 1988 o Ap Su>=1 0:1 2 DD
+ tz->get_info(to_sys_seconds(1988y, std::chrono::October, 30d, 1h, 30min, 59s))); // 1987 2006 O lastSu 0:1 0 S
+
+ assert_range("[2011-03-13 03:31:00, 2011-11-06 04:30:00) -02:30:00 60min NDT",
+ tz->get_info( // -3:30 j N%sT 2011 N
+ to_sys_seconds(2011y, std::chrono::March, 13d, 3h, 31min, 0s)), // 2007 2011 Mar Su>=8 0:1 1 D
+ tz->get_info( // -3:30 C N%sT
+ to_sys_seconds(2011y, std::chrono::November, 6d, 04h, 29min, 59s))); // 2007 ma N Su>=1 2 0 S
+}
+
+static void test_get_at_standard_time_universal() {
+ // Z Asia/Barnaul 5:35 - LMT 1919 D 10
+ // ...
+ // 7 R +07/+08 1995 May 28
+ // 6 R +06/+07 2011 Mar 27 2s
+ // ...
+ //
+ // ...
+ // R R 1985 2010 - Mar lastSu 2s 1 S
+ // R R 1996 2010 - O lastSu 2s 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Barnaul");
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(2010y, std::chrono::October, 30d, 20h),
+ to_sys_seconds(2011y, std::chrono::March, 26d, 20h),
+ 6h,
+ 0min,
+ "+06"),
+ tz->get_info(to_sys_seconds(2010y, std::chrono::October, 31d, 10h)));
+}
+
+static void test_get_at_standard_time_standard() {
+ // Z Africa/Bissau -1:2:20 - LMT 1912 Ja 1 1u
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Bissau");
+
+ assert_equal(
+ std::chrono::sys_info(
+ std::chrono::sys_seconds::min(),
+ to_sys_seconds(1912y, std::chrono::January, 1d, 1h),
+ -(1h + 2min + 20s),
+ 0min,
+ "LMT"),
+ tz->get_info(std::chrono::sys_seconds::min()));
+}
+
+static void test_get_at_save_universal() {
+ // Z America/Tijuana -7:48:4 - LMT 1922 Ja 1 0:11:56
+ // -7 - MST 1924
+ // -8 - PST 1927 Jun 10 23
+ // -7 - MST 1930 N 15
+ // -8 - PST 1931 Ap
+ // -8 1 PDT 1931 S 30
+ // -8 - PST 1942 Ap 24
+ // -8 1 PWT 1945 Au 14 23u
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Tijuana");
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1942y, std::chrono::April, 24d, 8h),
+ to_sys_seconds(1945y, std::chrono::August, 14d, 23h),
+ -7h,
+ 60min,
+ "PWT"),
+ tz->get_info(to_sys_seconds(1942y, std::chrono::April, 24d, 8h)));
+}
+
+static void test_get_at_rule_standard() {
+ // Z Antarctica/Macquarie 0 - -00 1899 N
+ // 10 - AEST 1916 O 1 2
+ // 10 1 AEDT 1917 F
+ // 10 AU AE%sT 1919 Ap 1 0s
+ // ...
+ //
+ // R AU 1917 o - Ja 1 2s 1 D
+ // R AU 1917 o - Mar lastSu 2s 0 S
+ // R AU 1942 o - Ja 1 2s 1 D
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Antarctica/Macquarie");
+
+ // Another rule where the S propagates?
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1916y, std::chrono::September, 30d, 16h),
+ to_sys_seconds(1917y, std::chrono::March, 24d, 16h),
+ 11h,
+ 60min,
+ "AEDT"),
+ tz->get_info(to_sys_seconds(1916y, std::chrono::September, 30d, 16h)));
+}
+
+static void test_get_at_rule_universal() {
+ // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28
+ // -3 - -03 1980 Ap 6 2
+ // -3 E -03/-02 2023 O 29 1u
+ // -2 E -02/-01
+ //
+ // R E 1977 1980 - Ap Su>=1 1u 1 S
+ // R E 1977 o - S lastSu 1u 0 -
+ // R E 1978 o - O 1 1u 0 -
+ // R E 1979 1995 - S lastSu 1u 0 -
+ // R E 1981 ma - Mar lastSu 1u 1 S
+ // R E 1996 ma - O lastSu 1u 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Nuuk");
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1980y, std::chrono::April, 6d, 5h),
+ to_sys_seconds(1980y, std::chrono::September, 28d, 1h),
+ -2h,
+ 60min,
+ "-02"),
+ tz->get_info(to_sys_seconds(1980y, std::chrono::April, 6d, 5h)));
+}
+
+static void test_format_with_alternatives_west() {
+ // Z America/Nuuk -3:26:56 - LMT 1916 Jul 28
+ // -3 - -03 1980 Ap 6 2
+ // -3 E -03/-02 2023 O 29 1u
+ // -2 E -02/-01
+ //
+ // ...
+ // R E 1981 ma - Mar lastSu 1u 1 S
+ // R E 1996 ma - O lastSu 1u 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Nuuk");
+
+ assert_cycle( // -3 E -03/-02
+ "[2019-10-27 01:00:00, 2020-03-29 01:00:00) -03:00:00 0min -03",
+ tz->get_info(to_sys_seconds(2019y, std::chrono::October, 27d, 1h)), // 1981 ma Mar lastSu 1u 1 S
+ tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 0h, 59min, 59s)), // 1996 ma O lastSu 1u 0 -
+ "[2020-03-29 01:00:00, 2020-10-25 01:00:00) -02:00:00 60min -02",
+ tz->get_info(to_sys_seconds(2020y, std::chrono::March, 29d, 1h)), // 1996 ma O lastSu 1u 0 -
+ tz->get_info(to_sys_seconds(2020y, std::chrono::October, 25d, 0h, 59min, 59s))); // 1981 ma Mar lastSu 1u 1 S
+}
+
+static void test_format_with_alternatives_east() {
+ // Z Asia/Barnaul 5:35 - LMT 1919 D 10
+ // ...
+ // 6 R +06/+07 2011 Mar 27 2s
+ // ...
+ //
+ // ...
+ // R R 1985 2010 - Mar lastSu 2s 1 S
+ // R R 1996 2010 - O lastSu 2s 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Asia/Barnaul");
+
+ assert_cycle( // 6 R +06/+07 2011 Mar 27 2s
+ "[2000-03-25 20:00:00, 2000-10-28 20:00:00) 07:00:00 60min +07",
+ tz->get_info(to_sys_seconds(2000y, std::chrono::March, 25d, 20h)), // 1985 2010 Mar lastSu 2s 1 S
+ tz->get_info(to_sys_seconds(2000y, std::chrono::October, 28d, 19h, 59min, 59s)), // 1996 2010 O lastSu 2s 0 -
+ "[2000-10-28 20:00:00, 2001-03-24 20:00:00) 06:00:00 0min +06",
+ tz->get_info(to_sys_seconds(2000y, std::chrono::October, 28d, 20h)), // 1996 2010 O lastSu 2s 0 -
+ tz->get_info(to_sys_seconds(2001y, std::chrono::March, 24d, 19h, 59min, 59s))); // 1985 2010 Mar lastSu 2s 1 S
+}
+
+static void test_africa_algiers() {
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Algiers");
+
+ assert_equal(
+ std::chrono::sys_info(
+ to_sys_seconds(1977y, std::chrono::October, 20d, 23h),
+ to_sys_seconds(1978y, std::chrono::March, 24d),
+ 1h,
+ std::chrono::minutes(0),
+ "CET"),
+ tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 23h)));
+
+ assert_range("[1977-05-06 00:00:00, 1977-10-20 23:00:00) 01:00:00 60min WEST", // 0 d WE%sT 1977 O 21
+ tz->get_info(to_sys_seconds(1977y, std::chrono::May, 6d)),
+ tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 22h, 59min, 59s)));
+
+ assert_range("[1977-10-20 23:00:00, 1978-03-24 00:00:00) 01:00:00 0min CET", // 1 d CE%sT 1979 O 26
+ tz->get_info(to_sys_seconds(1977y, std::chrono::October, 20d, 23h)),
+ tz->get_info(to_sys_seconds(1978y, std::chrono::March, 23d, 23h, 59min, 59s)));
+}
+
+static void test_africa_casablanca() {
+ // Z Africa/Casablanca -0:30:20 - LMT 1913 O 26
+ // 0 M +00/+01 1984 Mar 16
+ // 1 - +01 1986
+ // 0 M +00/+01 2018 O 28 3
+ // 1 M +01/+00
+ //
+ // ...
+ // R M 2013 2018 - O lastSu 3 0 -
+ // R M 2014 2018 - Mar lastSu 2 1 -
+ // R M 2014 o - Jun 28 3 0 -
+ // R M 2014 o - Au 2 2 1 -
+ // R M 2015 o - Jun 14 3 0 -
+ // R M 2015 o - Jul 19 2 1 -
+ // R M 2016 o - Jun 5 3 0 -
+ // R M 2016 o - Jul 10 2 1 -
+ // R M 2017 o - May 21 3 0 -
+ // R M 2017 o - Jul 2 2 1 -
+ // R M 2018 o - May 13 3 0 -
+ // R M 2018 o - Jun 17 2 1 -
+ // R M 2019 o - May 5 3 -1 -
+ // R M 2019 o - Jun 9 2 0 -
+ // R M 2020 o - Ap 19 3 -1 -
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Casablanca");
+
+ assert_range("[2018-06-17 02:00:00, 2018-10-28 02:00:00) 01:00:00 60min +01",
+ tz->get_info(to_sys_seconds(2018y, std::chrono::June, 17d, 2h)),
+ tz->get_info(to_sys_seconds(2018y, std::chrono::October, 28d, 1h, 59min, 59s)));
+
+ assert_range("[2018-10-28 02:00:00, 2019-05-05 02:00:00) 01:00:00 0min +01",
+ tz->get_info( // 1 M +01/+00 & R M 2018 o - Jun 17 2 1 -
+ to_sys_seconds(2018y, std::chrono::October, 28d, 2h)),
+ tz->get_info( // 1 M +01/+00 & R M 2019 o - May 5 3 -1 -
+ to_sys_seconds(2019y, std::chrono::May, 5d, 1h, 59min, 59s)));
+
+ // 1 M +01/+00
+ // Note the SAVE contains a negative value
+ assert_range("[2019-05-05 02:00:00, 2019-06-09 02:00:00) 00:00:00 -60min +00",
+ tz->get_info(to_sys_seconds(2019y, std::chrono::May, 5d, 2h)), // R M 2019 o - May 5 3 -1 -
+ tz->get_info(to_sys_seconds(2019y, std::chrono::June, 9d, 1h, 59min, 59s))); // R M 2019 o - Jun 9 2 0 -
+
+ assert_range("[2019-06-09 02:00:00, 2020-04-19 02:00:00) 01:00:00 0min +01",
+ tz->get_info( // 1 M +01/+00 & R M 2019 o - Jun 9 2 0 -
+ to_sys_seconds(2019y, std::chrono::June, 9d, 2h)),
+ tz->get_info( // 1 M +01/+00 & R M 2020 o - Ap 19 3 -1 -
+ to_sys_seconds(2020y, std::chrono::April, 19d, 1h, 59min, 59s))); //
+}
+
+static void test_africa_ceuta() {
+ // Z Africa/Ceuta -0:21:16 - LMT 1900 D 31 23:38:44
+ // 0 - WET 1918 May 6 23
+ // 0 1 WEST 1918 O 7 23
+ // 0 - WET 1924
+ // 0 s WE%sT 1929
+ // 0 - WET 1967
+ // 0 Sp WE%sT 1984 Mar 16
+ // 1 - CET 1986
+ // 1 E CE%sT
+ //
+ // ...
+ // R s 1926 o - Ap 17 23 1 S
+ // R s 1926 1929 - O Sa>=1 24s 0 -
+ // R s 1927 o - Ap 9 23 1 S
+ // R s 1928 o - Ap 15 0 1 S
+ // R s 1929 o - Ap 20 23 1 S
+ // R s 1937 o - Jun 16 23 1 S
+ // ...
+ //
+ // R Sp 1967 o - Jun 3 12 1 S
+ // R Sp 1967 o - O 1 0 0 -
+ // R Sp 1974 o - Jun 24 0 1 S
+ // R Sp 1974 o - S 1 0 0 -
+ // R Sp 1976 1977 - May 1 0 1 S
+ // R Sp 1976 o - Au 1 0 0 -
+ // R Sp 1977 o - S 28 0 0 -
+ // R Sp 1978 o - Jun 1 0 1 S
+ // R Sp 1978 o - Au 4 0 0 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Ceuta");
+
+ assert_range(
+
+ "[1928-10-07 00:00:00, 1967-06-03 12:00:00) 00:00:00 0min WET",
+ tz->get_info(to_sys_seconds(1928y, std::chrono::October, 7d)), // 0 s WE%sT 1929 & 1926 1929 O Sa>=1 24s 0 -
+ tz->get_info( // No transitions in "0 - WET 1967"
+ to_sys_seconds(1967y, std::chrono::June, 3d, 11h, 59min, 59s))); // 0 - WET 1967 & 1967 o Jun 3 12 1 S
+}
+
+static void test_africa_freetown() {
+ // Z Africa/Freetown -0:53 - LMT 1882
+ // -0:53 - FMT 1913 Jul
+ // -1 SL %s 1939 S 5
+ // -1 - -01 1941 D 6 24
+ // 0 - GMT
+ //
+ // R SL 1932 o - D 1 0 0:20 -0040
+ // R SL 1933 1938 - Mar 31 24 0 -01
+ // R SL 1933 1939 - Au 31 24 0:20 -0040
+ // R SL 1939 o - May 31 24 0 -01
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Freetown");
+
+ // When a continuation has a named rule, the tranisition time determined by
+ // the active rule can be wrong. The next continuation may set the clock to an
+ // earlier time. This is tested for San Luis. This tests the rule is not used
+ // when the rule is not a named rule.
+ //
+ // Fixes:
+ // Expected output [1882-01-01 00:53:00, 1913-07-01 00:53:00) -00:53:00 0min FMT
+ // Actual output [1882-01-01 00:53:00, 1913-07-01 00:46:00) -00:53:00 0min FMT
+
+ assert_range("[1882-01-01 00:53:00, 1913-07-01 00:53:00) -00:53:00 0min FMT",
+ tz->get_info(to_sys_seconds(1882y, std::chrono::January, 1d, 0h, 53min)), // -0:53 - FMT 1913 Jul
+ tz->get_info( // -1 SL %s 1939 S 5 & before first rule
+ to_sys_seconds(1913y, std::chrono::July, 1d, 0h, 52min, 59s)));
+
+ // Tests whether the "-1 SL %s 1939 S 5" until gets the proper local time
+ // adjustment.
+ assert_range("[1939-09-01 01:00:00, 1939-09-05 00:40:00) -00:40:00 20min -0040",
+ tz->get_info( // -1 SL %s 1939 S 5 & R SL 1933 1939 - Au 31 24 0:20 -0040
+ to_sys_seconds(1939y, std::chrono::September, 1d, 1h)),
+ tz->get_info( // -1 - -01 1941 D 6 24
+ to_sys_seconds(1939y, std::chrono::September, 5d, 0h, 39min, 59s)));
+}
+
+static void test_africa_windhoek() {
+ // Tests the LETTER/S used before the first rule per
+ // https://data.iana.org/time-zones/tz-how-to.html
+ // If switching to a named rule before any transition has happened,
+ // assume standard time (SAVE zero), and use the LETTER data from
+ // the earliest transition with a SAVE of zero.
+
+ // Z Africa/Windhoek 1:8:24 - LMT 1892 F 8
+ // 1:30 - +0130 1903 Mar
+ // 2 - SAST 1942 S 20 2
+ // 2 1 SAST 1943 Mar 21 2
+ // 2 - SAST 1990 Mar 21
+ // 2 NA %s
+ //
+ // R NA 1994 o - Mar 21 0 -1 WAT
+ // R NA 1994 2017 - S Su>=1 2 0 CAT
+ // R NA 1995 2017 - Ap Su>=1 2 -1 WAT
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("Africa/Windhoek");
+
+ assert_range( // 2 - EET 2012 N 10 2
+ "[1990-03-20 22:00:00, 1994-03-20 22:00:00) 02:00:00 0min CAT",
+ tz->get_info(to_sys_seconds(1990y, std::chrono::March, 20d, 22h)),
+ tz->get_info(to_sys_seconds(1994y, std::chrono::March, 20d, 21h, 59min, 59s)));
+}
+
+static void test_america_adak() {
+ // Z America/Adak 12:13:22 - LMT 1867 O 19 12:44:35
+ // ...
+ // -11 u B%sT 1983 O 30 2
+ // -10 u AH%sT 1983 N 30
+ // -10 u H%sT
+ //
+ // ...
+ // R u 1945 o - S 30 2 0 S
+ // R u 1967 2006 - O lastSu 2 0 S
+ // R u 1967 1973 - Ap lastSu 2 1 D
+ // R u 1974 o - Ja 6 2 1 D
+ // R u 1975 o - F lastSu 2 1 D
+ // R u 1976 1986 - Ap lastSu 2 1 D
+ // R u 1987 2006 - Ap Su>=1 2 1 D
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Adak");
+
+ assert_range( // 2 - EET 2012 N 10 2
+ "[1983-10-30 12:00:00, 1983-11-30 10:00:00) -10:00:00 0min AHST",
+ tz->get_info(to_sys_seconds(1983y, std::chrono::October, 30d, 12h)), // -11 u B%sT 1983 O 30 2
+ tz->get_info(to_sys_seconds(1983y, std::chrono::November, 30d, 9h, 59min, 59s))); // -10 u AH%sT 1983 N 30
+}
+
+static void test_america_auncion() {
+ // R y 2013 ma - Mar Su>=22 0 0 -
+ // Z America/Asuncion -3:50:40 - LMT 1890
+ // -3:50:40 - AMT 1931 O 10
+ // -4 - -04 1972 O
+ // -3 - -03 1974 Ap
+ // -4 y -04/-03
+ //
+ // R y 1975 1988 - O 1 0 1 -
+ // R y 1975 1978 - Mar 1 0 0 -
+ // R y 1979 1991 - Ap 1 0 0 -
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Asuncion");
+
+ assert_range("[1974-04-01 03:00:00, 1975-10-01 04:00:00) -04:00:00 0min -04",
+ tz->get_info(to_sys_seconds(1974y, std::chrono::April, 1d, 3h)),
+ tz->get_info(to_sys_seconds(1975y, std::chrono::October, 1d, 3h, 59min, 59s)));
+
+ assert_range("[1975-10-01 04:00:00, 1976-03-01 03:00:00) -03:00:00 60min -03",
+ tz->get_info(to_sys_seconds(1975y, std::chrono::October, 1d, 4h)),
+ tz->get_info(to_sys_seconds(1976y, std::chrono::March, 1d, 2h, 59min, 59s)));
+}
+
+static void test_america_ciudad_juarez() {
+ // Z America/Ciudad_Juarez -7:5:56 - LMT 1922 Ja 1 7u
+ // -7 - MST 1927 Jun 10 23
+ // -6 - CST 1930 N 15
+ // -7 m MST 1932 Ap
+ // -6 - CST 1996
+ // -6 m C%sT 1998
+ // ...
+ //
+ // R m 1939 o - F 5 0 1 D
+ // R m 1939 o - Jun 25 0 0 S
+ // R m 1940 o - D 9 0 1 D
+ // R m 1941 o - Ap 1 0 0 S
+ // R m 1943 o - D 16 0 1 W
+ // R m 1944 o - May 1 0 0 S
+ // R m 1950 o - F 12 0 1 D
+ // R m 1950 o - Jul 30 0 0 S
+ // R m 1996 2000 - Ap Su>=1 2 1 D
+ // R m 1996 2000 - O lastSu 2 0 S
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Ciudad_Juarez");
+
+ // 1996 has a similar issue, instead of __time the __until end before
+ // the first rule in 1939. Between the two usages of RULE Mexico
+ // a different continuation RULE is active
+ assert_range("[1996-04-07 08:00:00, 1996-10-27 07:00:00) -05:00:00 60min CDT",
+ tz->get_info(to_sys_seconds(1996y, std::chrono::April, 7d, 8h)),
+ tz->get_info(to_sys_seconds(1996y, std::chrono::October, 27d, 6h, 59min, 59s)));
+}
+
+static void test_america_argentina_buenos_aires() {
+ // Z America/Argentina/Buenos_Aires -3:53:48 - LMT 1894 O 31
+ // -4:16:48 - CMT 1920 May
+ // -4 - -04 1930 D
+ // -4 A -04/-03 1969 O 5
+ // -3 A -03/-02 1999 O 3
+ // -4 A -04/-03 2000 Mar 3
+ // -3 A -03/-02
+ //
+ // ...
+ // R A 1989 1992 - O Su>=15 0 1 -
+ // R A 1999 o - O Su>=1 0 1 -
+ // R A 2000 o - Mar 3 0 0 -
+ // R A 2007 o - D 30 0 1 -
+ // ...
+
+ // The 1999 switch uses the same rule, but with a different stdoff.
+ // R A 1999 o - O Su>=1 0 1 -
+ // stdoff -3 -> 1999-10-03 03:00:00
+ // stdoff -4 -> 1999-10-03 04:00:00
+ // This generates an invalid entry and this is evaluated as a transition.
+ // Looking at the zdump like output in libc++ this generates jumps in
+ // the UTC time
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/Buenos_Aires");
+
+ assert_range("[1999-10-03 03:00:00, 2000-03-03 03:00:00) -03:00:00 60min -03",
+ tz->get_info(to_sys_seconds(1999y, std::chrono::October, 3d, 3h)),
+ tz->get_info(to_sys_seconds(2000y, std::chrono::March, 3d, 2h, 59min, 59s)));
+ assert_range("[2000-03-03 03:00:00, 2007-12-30 03:00:00) -03:00:00 0min -03",
+ tz->get_info(to_sys_seconds(2000y, std::chrono::March, 3d, 3h)),
+ tz->get_info(to_sys_seconds(2007y, std::chrono::December, 30d, 2h, 59min, 59s)));
+}
+
+static void test_america_argentina_la_rioja() {
+ // Z America/Argentina/La_Rioja -4:27:24 - LMT 1894 O 31
+ // ...
+ // -4 A -04/-03 1969 O 5
+ // -3 A -03/-02 1991 Mar
+ // -4 - -04 1991 May 7
+ // -3 A -03/-02 1999 O 3
+ // ...
+ //
+ // ...
+ // R A 1988 o - D 1 0 1 -
+ // R A 1989 1993 - Mar Su>=1 0 0 -
+ // R A 1989 1992 - O Su>=15 0 1 -
+ // R A 1999 o - O Su>=1 0 1 -
+ // ...
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/La_Rioja");
+
+ assert_range("[1990-10-21 03:00:00, 1991-03-01 02:00:00) -02:00:00 60min -02",
+ tz->get_info(to_sys_seconds(1990y, std::chrono::October, 21d, 3h)),
+ tz->get_info(to_sys_seconds(1991y, std::chrono::March, 1d, 1h, 59min, 59s)));
+}
+
+static void test_america_argentina_san_luis() {
+ // Z America/Argentina/San_Luis -4:25:24 - LMT 1894 O 31
+ // ...
+ // -4 A -04/-03 1969 O 5
+ // -3 A -03/-02 1990
+ // -3 1 -02 1990 Mar 14
+ // -4 - -04 1990 O 15
+ // -4 1 -03 1991 Mar
+ // -4 - -04 1991 Jun
+ // -3 - -03 1999 O 3
+ // -4 1 -03 2000 Mar 3
+ // -4 - -04 2004 Jul 25
+ // -3 A -03/-02 2008 Ja 21
+ // -4 Sa -04/-03 2009 O 11
+ // -3 - -03
+ //
+ // ...
+ // R A 1988 o - D 1 0 1 -
+ // R A 1989 1993 - Mar Su>=1 0 0 -
+ // R A 1989 1992 - O Su>=15 0 1 -
+ // R A 1999 o - O Su>=1 0 1 -
+ // R A 2000 o - Mar 3 0 0 -
+ // R A 2007 o - D 30 0 1 -
+ // R A 2008 2009 - Mar Su>=15 0 0 -
+ // R A 2008 o - O Su>=15 0 1 -
+ //
+ // R Sa 2008 2009 - Mar Su>=8 0 0 -
+ // R Sa 2007 2008 - O Su>=8 0 1 -
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Argentina/San_Luis");
+
+ assert_range("[1989-10-15 03:00:00, 1990-03-14 02:00:00) -02:00:00 60min -02",
+ tz->get_info( // -3 A -03/-02 1990 & R A 1989 1992 - O Su>=15 0 1 -
+ to_sys_seconds(1989y, std::chrono::October, 15d, 3h)),
+ tz->get_info( // UNTIL -3 1 -02 1990 Mar 14
+ to_sys_seconds(1990y, std::chrono::March, 14d, 1h, 59min, 59s)));
+
+ assert_range("[2008-01-21 02:00:00, 2008-03-09 03:00:00) -03:00:00 60min -03",
+ tz->get_info(to_sys_seconds(2008y, std::chrono::January, 21d, 2h)),
+ tz->get_info(to_sys_seconds(2008y, std::chrono::March, 9d, 2h, 59min, 59s)));
+}
+
+static void test_america_indiana_knox() {
+ // Z America/Indiana/Knox -5:46:30 - LMT 1883 N 18 12:13:30
+ // -6 u C%sT 1947
+ // -6 St C%sT 1962 Ap 29 2
+ // -5 - EST 1963 O 27 2
+ // -6 u C%sT 1991 O 27 2
+ // -5 - EST 2006 Ap 2 2
+ // -6 u C%sT
+ //
+ // ...
+ // R u 1976 1986 - Ap lastSu 2 1 D
+ // R u 1987 2006 - Ap Su>=1 2 1 D
+ // R u 2007 ma - Mar Su>=8 2 1 D
+ // R u 2007 ma - N Su>=1 2 0 S
+
+ using namespace std::literals::chrono_literals;
+ const std::chrono::time_zone* tz = std::chrono::locate_zone("America/Indiana/Knox");
+
+ // The continuations
+ // -5 - EST
+ // -6 u C%sT
+ // have different offsets. The start time of the first active rule in
+ // RULE u should use the offset at the end of -5 - EST.
+ assert_range("[2006-04-02 07:00:00, 2006-10-29 07:00:00) -05:00:00 60min CDT",
+ tz->get_info(to_sys_seconds(2006y, std::chrono::April, 2d, 7h)),
+ tz->get_info(to_sys_seconds(2006y, std::chrono::October, 29d, 6h, 59min, 59s)));
+}
+
+int main(int, const char**) {
+ // Basic tests
+ test_gmt();
+ test_durations();
+ test_indian_kerguelen();
+ test_antarctica_syowa();
+ test_asia_hong_kong();
+ test_europe_berlin();
+
+ test_america_st_johns();
+
+ // Small tests for not-yet tested conditions
+ test_get_at_standard_time_universal();
+ test_get_at_standard_time_standard();
+ test_get_at_save_universal();
+ test_get_at_rule_standard();
+ test_get_at_rule_universal();
+
+ test_format_with_alternatives_west();
+ test_format_with_alternatives_east();
+
+ // Tests based on bugs found
+ test_africa_algiers();
+ test_africa_casablanca();
+ test_africa_ceuta();
+ test_africa_freetown();
+ test_africa_windhoek();
+ test_america_adak();
+ test_america_argentina_buenos_aires();
+ test_america_argentina_la_rioja();
+ test_america_argentina_san_luis();
+ test_america_auncion();
+ test_america_ciudad_juarez();
+ test_america_indiana_knox();
+
+ return 0;
+}
diff --git a/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/sys_info.zdump.pass.cpp b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/sys_info.zdump.pass.cpp
new file mode 100644
index 000000000000..05328e2256c7
--- /dev/null
+++ b/libcxx/test/std/time/time.zone/time.zone.timezone/time.zone.members/sys_info.zdump.pass.cpp
@@ -0,0 +1,129 @@
+//===----------------------------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+// UNSUPPORTED: c++03, c++11, c++14, c++17
+// UNSUPPORTED: no-filesystem, no-localization, no-tzdb, has-no-zdump
+
+// XFAIL: libcpp-has-no-incomplete-tzdb
+// XFAIL: availability-tzdb-missing
+
+// TODO TZDB Investigate
+// XFAIL: target={{armv(7|8)l-linux-gnueabihf}}
+
+#include <chrono>
+#include <format>
+#include <fstream>
+#include <cassert>
+
+#include "filesystem_test_helper.h"
+#include "assert_macros.h"
+#include "concat_macros.h"
+
+// The year range to validate. The dates used in practice are expected to be
+// inside the tested range.
+constexpr std::chrono::year first{1800};
+constexpr std::chrono::year last{2100};
+
+// A custom sys_info class that also stores the name of the time zone.
+// Its formatter matches the output of zdump.
+struct sys_info : public std::chrono::sys_info {
+ sys_info(std::string_view name_, std::chrono::sys_info info) : std::chrono::sys_info{info}, name{name_} {}
+
+ std::string name;
+};
+
+template <>
+struct std::formatter<sys_info, char> {
+ template <class ParseContext>
+ constexpr typename ParseContext::iterator parse(ParseContext& ctx) {
+ return ctx.begin();
+ }
+
+ template <class FormatContext>
+ typename FormatContext::iterator format(const sys_info& info, FormatContext& ctx) const {
+ using namespace std::literals::chrono_literals;
+
+ // Every "sys_info" entry of zdump consists of 2 lines.
+ // - 1 for first second of the range
+ // - 1 for last second of the range
+ // For example:
+ // Africa/Casablanca Sun Mar 25 02:00:00 2018 UT = Sun Mar 25 03:00:00 2018 +01 isdst=1 gmtoff=3600
+ // Africa/Casablanca Sun May 13 01:59:59 2018 UT = Sun May 13 02:59:59 2018 +01 isdst=1 gmtoff=3600
+
+ if (info.begin != std::chrono::sys_seconds::min())
+ ctx.advance_to(std::format_to(
+ ctx.out(),
+ "{} {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",
+ info.name,
+ info.begin,
+ info.begin + info.offset,
+ info.abbrev,
+ info.save != 0s,
+ info.offset));
+
+ if (info.end != std::chrono::sys_seconds::max())
+ ctx.advance_to(std::format_to(
+ ctx.out(),
+ "{} {:%a %b %e %H:%M:%S %Y} UT = {:%a %b %e %H:%M:%S %Y} {} isdst={:d} gmtoff={:%Q}\n",
+ info.name,
+ info.end - 1s,
+ info.end - 1s + info.offset,
+ info.abbrev,
+ info.save != 0s,
+ info.offset));
+
+ return ctx.out();
+ }
+};
+
+void process(std::ostream& stream, const std::chrono::time_zone& zone) {
+ using namespace std::literals::chrono_literals;
+
+ constexpr auto begin = std::chrono::time_point_cast<std::chrono::seconds>(
+ static_cast<std::chrono::sys_days>(std::chrono::year_month_day{first, std::chrono::January, 1d}));
+ constexpr auto end = std::chrono::time_point_cast<std::chrono::seconds>(
+ static_cast<std::chrono::sys_days>(std::chrono::year_month_day{last, std::chrono::January, 1d}));
+
+ std::chrono::sys_seconds s = begin;
+ do {
+ sys_info info{zone.name(), zone.get_info(s)};
+
+ if (info.end >= end)
+ info.end = std::chrono::sys_seconds::max();
+
+ stream << std::format("{}", info);
+ s = info.end;
+ } while (s != std::chrono::sys_seconds::max());
+}
+
+// This test compares the output of the zdump against the output based on the
+// standard library implementation. It tests all available time zones and
+// validates them. The specification of how to use the IANA database is limited
+// and the real database contains quite a number of "interesting" cases.
+int main(int, const char**) {
+ scoped_test_env env;
+ const std::string file = env.create_file("zdump.txt");
+
+ const std::chrono::tzdb& tzdb = std::chrono::get_tzdb();
+ for (const auto& zone : tzdb.zones) {
+ std::stringstream libcxx;
+ process(libcxx, zone);
+
+ int result = std::system(std::format("zdump -V -c{},{} {} > {}", first, last, zone.name(), file).c_str());
+ assert(result == 0);
+
+ std::stringstream zdump;
+ zdump << std::ifstream(file).rdbuf();
+
+ TEST_REQUIRE(
+ libcxx.str() == zdump.str(),
+ TEST_WRITE_CONCATENATED("\nTZ=", zone.name(), "\nlibc++\n", libcxx.str(), "|\n\nzdump\n", zdump.str(), "|"));
+ }
+
+ return 0;
+}
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
index 994ccc70a38d..284b03c32cd0 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.pass.cpp
@@ -8,7 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// The tested functionality needs deducing this.
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
index b2c40d160454..4c60cb0e9ae1 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit.return_type.pass.cpp
@@ -8,7 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
// The tested functionality needs deducing this.
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <format>
diff --git a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
index acd9228369e6..6a3896c8965c 100644
--- a/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
+++ b/libcxx/test/std/utilities/format/format.arguments/format.arg/visit_format_arg.deprecated.verify.cpp
@@ -7,7 +7,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// UNSUPPORTED: GCC-ALWAYS_INLINE-FIXME
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <format>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
index c54f2b722d46..bea6d949924b 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/robust_against_adl.pass.cpp
@@ -8,7 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// The tested functionality needs deducing this.
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
index d0c909985bbb..857e85d00857 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit.pass.cpp
@@ -8,7 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// The tested functionality needs deducing this.
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <variant>
diff --git a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
index 3312197d8df9..2c1cbb06e706 100644
--- a/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
+++ b/libcxx/test/std/utilities/variant/variant.visit.member/visit_return_type.pass.cpp
@@ -8,7 +8,7 @@
// UNSUPPORTED: c++03, c++11, c++14, c++17, c++20, c++23
// The tested functionality needs deducing this.
-// UNSUPPORTED: clang-16 || clang-17
+// UNSUPPORTED: clang-17
// XFAIL: apple-clang
// <variant>
diff --git a/libcxx/test/support/test_chrono_leap_second.h b/libcxx/test/support/test_chrono_leap_second.h
index 485f68d91b1a..be5ce760bfe9 100644
--- a/libcxx/test/support/test_chrono_leap_second.h
+++ b/libcxx/test/support/test_chrono_leap_second.h
@@ -32,16 +32,11 @@
#ifdef _LIBCPP_VERSION
-// In order to find this include the calling test needs to provide this path in
-// the search path. Typically this looks like:
-// ADDITIONAL_COMPILE_FLAGS(stdlib=libc++): -I %{libcxx-dir}/src/include
-// where the number of `../` sequences depends on the subdirectory level of the
-// test.
-# include "tzdb/leap_second_private.h" // Header in the dylib
+# include <__utility/private_constructor_tag.h>
inline constexpr std::chrono::leap_second
test_leap_second_create(const std::chrono::sys_seconds& date, const std::chrono::seconds& value) {
- return std::chrono::leap_second{std::chrono::leap_second::__constructor_tag{}, date, value};
+ return std::chrono::leap_second{std::__private_constructor_tag{}, date, value};
}
#else // _LIBCPP_VERSION
diff --git a/libcxx/utils/ci/Dockerfile b/libcxx/utils/ci/Dockerfile
index db88da20b977..c77f6c435baf 100644
--- a/libcxx/utils/ci/Dockerfile
+++ b/libcxx/utils/ci/Dockerfile
@@ -72,33 +72,32 @@ RUN sudo apt-get update \
RUN sudo apt-get update \
&& sudo apt-get install -y \
- python3 \
- python3-distutils \
- python3-psutil \
- git \
- gdb \
- ccache \
- gpg \
- wget \
bash \
+ ccache \
curl \
- python3 \
- python3-dev \
- libpython3-dev \
- uuid-dev \
- libncurses5-dev \
- swig3.0 \
- libxml2-dev \
- libedit-dev \
+ gdb \
+ git \
+ gpg \
language-pack-en \
language-pack-fr \
language-pack-ja \
language-pack-ru \
language-pack-zh-hans \
+ libedit-dev \
+ libncurses5-dev \
+ libpython3-dev \
+ libxml2-dev \
lsb-release \
- wget \
- unzip \
+ make \
+ python3 \
+ python3-dev \
+ python3-distutils \
+ python3-psutil \
software-properties-common \
+ swig4.0 \
+ unzip \
+ uuid-dev \
+ wget \
&& sudo rm -rf /var/lib/apt/lists/*
diff --git a/libcxx/utils/ci/run-buildbot b/libcxx/utils/ci/run-buildbot
index 2905745355b6..a6f3eb174308 100755
--- a/libcxx/utils/ci/run-buildbot
+++ b/libcxx/utils/ci/run-buildbot
@@ -374,7 +374,7 @@ bootstrapping-build)
-B "${BUILD_DIR}" \
-GNinja -DCMAKE_MAKE_PROGRAM="${NINJA}" \
-DCMAKE_CXX_COMPILER_LAUNCHER="ccache" \
- -DCMAKE_BUILD_TYPE=RelWithDebInfo \
+ -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_INSTALL_PREFIX="${INSTALL_DIR}" \
-DLLVM_ENABLE_PROJECTS="clang" \
-DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" \
diff --git a/libcxx/utils/generate_iwyu_mapping.py b/libcxx/utils/generate_iwyu_mapping.py
index 8ab7b86299ed..2265438ab49c 100644
--- a/libcxx/utils/generate_iwyu_mapping.py
+++ b/libcxx/utils/generate_iwyu_mapping.py
@@ -11,6 +11,7 @@ def IWYU_mapping(header: str) -> typing.Optional[typing.List[str]]:
"__debug_utils/.+",
"__fwd/get[.]h",
"__support/.+",
+ "__utility/private_constructor_tag.h",
]
if any(re.match(pattern, header) for pattern in ignore):
return None
diff --git a/libcxx/utils/libcxx/test/features.py b/libcxx/utils/libcxx/test/features.py
index 0793c34fd7f0..6ff16309546b 100644
--- a/libcxx/utils/libcxx/test/features.py
+++ b/libcxx/utils/libcxx/test/features.py
@@ -286,6 +286,12 @@ DEFAULT_FEATURES = [
# Avoid building on platforms that don't support modules properly.
or not hasCompileFlag(cfg, "-Wno-reserved-module-identifier"),
),
+ # The time zone validation tests compare the output of zdump against the
+ # output generated by <chrono>'s time zone support.
+ Feature(
+ name="has-no-zdump",
+ when=lambda cfg: runScriptExitCode(cfg, ["zdump --version"]) != 0,
+ ),
]
# Deduce and add the test features that that are implied by the #defines in
diff --git a/lld/COFF/ICF.cpp b/lld/COFF/ICF.cpp
index 013ffcfb3d5d..b899a2532423 100644
--- a/lld/COFF/ICF.cpp
+++ b/lld/COFF/ICF.cpp
@@ -178,7 +178,7 @@ bool ICF::equalsConstant(const SectionChunk *a, const SectionChunk *b) {
a->getSectionName() == b->getSectionName() &&
a->header->SizeOfRawData == b->header->SizeOfRawData &&
a->checksum == b->checksum && a->getContents() == b->getContents() &&
- assocEquals(a, b);
+ a->getMachine() == b->getMachine() && assocEquals(a, b);
}
// Compare "moving" part of two sections, namely relocation targets.
diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index 4427a1200868..0d7f393a9f3f 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2769,7 +2769,8 @@ readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
SmallVector<GdbIndexSection::NameAttrEntry, 0> ret;
for (const LLDDWARFSection *pub : {&pubNames, &pubTypes}) {
- DWARFDataExtractor data(obj, *pub, config->isLE, config->wordsize);
+ DWARFDataExtractor data(obj, *pub, ELFT::Endianness == endianness::little,
+ ELFT::Is64Bits ? 8 : 4);
DWARFDebugPubTable table;
table.extract(data, /*GnuStyle=*/true, [&](Error e) {
warn(toString(pub->sec) + ": " + toString(std::move(e)));
@@ -2872,7 +2873,8 @@ createSymbols(
}
// Returns a newly-created .gdb_index section.
-template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
+template <class ELFT>
+std::unique_ptr<GdbIndexSection> GdbIndexSection::create() {
llvm::TimeTraceScope timeScope("Create gdb index");
// Collect InputFiles with .debug_info. See the comment in
@@ -2918,7 +2920,7 @@ template <class ELFT> GdbIndexSection *GdbIndexSection::create() {
nameAttrs[i] = readPubNamesAndTypes<ELFT>(dobj, chunks[i].compilationUnits);
});
- auto *ret = make<GdbIndexSection>();
+ auto ret = std::make_unique<GdbIndexSection>();
ret->chunks = std::move(chunks);
std::tie(ret->symbols, ret->size) = createSymbols(nameAttrs, ret->chunks);
@@ -3743,8 +3745,9 @@ template <typename ELFT> void elf::writeEhdr(uint8_t *buf, Partition &part) {
memcpy(buf, "\177ELF", 4);
auto *eHdr = reinterpret_cast<typename ELFT::Ehdr *>(buf);
- eHdr->e_ident[EI_CLASS] = config->is64 ? ELFCLASS64 : ELFCLASS32;
- eHdr->e_ident[EI_DATA] = config->isLE ? ELFDATA2LSB : ELFDATA2MSB;
+ eHdr->e_ident[EI_CLASS] = ELFT::Is64Bits ? ELFCLASS64 : ELFCLASS32;
+ eHdr->e_ident[EI_DATA] =
+ ELFT::Endianness == endianness::little ? ELFDATA2LSB : ELFDATA2MSB;
eHdr->e_ident[EI_VERSION] = EV_CURRENT;
eHdr->e_ident[EI_OSABI] = config->osabi;
eHdr->e_ident[EI_ABIVERSION] = getAbiVersion();
@@ -3860,12 +3863,34 @@ void InStruct::reset() {
ppc32Got2.reset();
ibtPlt.reset();
relaPlt.reset();
+ gdbIndex.reset();
shStrTab.reset();
strTab.reset();
symTab.reset();
symTabShndx.reset();
}
+static bool needsInterpSection() {
+ return !config->relocatable && !config->shared &&
+ !config->dynamicLinker.empty() && script->needsInterpSection();
+}
+
+bool elf::hasMemtag() {
+ return config->emachine == EM_AARCH64 &&
+ config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE;
+}
+
+// Fully static executables don't support MTE globals at this point in time, as
+// we currently rely on:
+// - A dynamic loader to process relocations, and
+// - Dynamic entries.
+// This restriction could be removed in future by re-using some of the ideas
+// that ifuncs use in fully static executables.
+bool elf::canHaveMemtagGlobals() {
+ return hasMemtag() &&
+ (config->relocatable || config->shared || needsInterpSection());
+}
+
constexpr char kMemtagAndroidNoteName[] = "Android";
void MemtagAndroidNote::writeTo(uint8_t *buf) {
static_assert(
@@ -3981,31 +4006,304 @@ size_t MemtagGlobalDescriptors::getSize() const {
return createMemtagGlobalDescriptors(symbols);
}
+static OutputSection *findSection(StringRef name) {
+ for (SectionCommand *cmd : script->sectionCommands)
+ if (auto *osd = dyn_cast<OutputDesc>(cmd))
+ if (osd->osec.name == name)
+ return &osd->osec;
+ return nullptr;
+}
+
+static Defined *addOptionalRegular(StringRef name, SectionBase *sec,
+ uint64_t val, uint8_t stOther = STV_HIDDEN) {
+ Symbol *s = symtab.find(name);
+ if (!s || s->isDefined() || s->isCommon())
+ return nullptr;
+
+ s->resolve(Defined{ctx.internalFile, StringRef(), STB_GLOBAL, stOther,
+ STT_NOTYPE, val,
+ /*size=*/0, sec});
+ s->isUsedInRegularObj = true;
+ return cast<Defined>(s);
+}
+
+template <class ELFT> void elf::createSyntheticSections() {
+ // Initialize all pointers with NULL. This is needed because
+ // you can call lld::elf::main more than once as a library.
+ Out::tlsPhdr = nullptr;
+ Out::preinitArray = nullptr;
+ Out::initArray = nullptr;
+ Out::finiArray = nullptr;
+
+ // Add the .interp section first because it is not a SyntheticSection.
+ // The removeUnusedSyntheticSections() function relies on the
+ // SyntheticSections coming last.
+ if (needsInterpSection()) {
+ for (size_t i = 1; i <= partitions.size(); ++i) {
+ InputSection *sec = createInterpSection();
+ sec->partition = i;
+ ctx.inputSections.push_back(sec);
+ }
+ }
+
+ auto add = [](SyntheticSection &sec) { ctx.inputSections.push_back(&sec); };
+
+ in.shStrTab = std::make_unique<StringTableSection>(".shstrtab", false);
+
+ Out::programHeaders = make<OutputSection>("", 0, SHF_ALLOC);
+ Out::programHeaders->addralign = config->wordsize;
+
+ if (config->strip != StripPolicy::All) {
+ in.strTab = std::make_unique<StringTableSection>(".strtab", false);
+ in.symTab = std::make_unique<SymbolTableSection<ELFT>>(*in.strTab);
+ in.symTabShndx = std::make_unique<SymtabShndxSection>();
+ }
+
+ in.bss = std::make_unique<BssSection>(".bss", 0, 1);
+ add(*in.bss);
+
+ // If there is a SECTIONS command and a .data.rel.ro section name use name
+ // .data.rel.ro.bss so that we match in the .data.rel.ro output section.
+ // This makes sure our relro is contiguous.
+ bool hasDataRelRo = script->hasSectionsCommand && findSection(".data.rel.ro");
+ in.bssRelRo = std::make_unique<BssSection>(
+ hasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
+ add(*in.bssRelRo);
+
+ // Add MIPS-specific sections.
+ if (config->emachine == EM_MIPS) {
+ if (!config->shared && config->hasDynSymTab) {
+ in.mipsRldMap = std::make_unique<MipsRldMapSection>();
+ add(*in.mipsRldMap);
+ }
+ if ((in.mipsAbiFlags = MipsAbiFlagsSection<ELFT>::create()))
+ add(*in.mipsAbiFlags);
+ if ((in.mipsOptions = MipsOptionsSection<ELFT>::create()))
+ add(*in.mipsOptions);
+ if ((in.mipsReginfo = MipsReginfoSection<ELFT>::create()))
+ add(*in.mipsReginfo);
+ }
+
+ StringRef relaDynName = config->isRela ? ".rela.dyn" : ".rel.dyn";
+
+ const unsigned threadCount = config->threadCount;
+ for (Partition &part : partitions) {
+ auto add = [&](SyntheticSection &sec) {
+ sec.partition = part.getNumber();
+ ctx.inputSections.push_back(&sec);
+ };
+
+ if (!part.name.empty()) {
+ part.elfHeader = std::make_unique<PartitionElfHeaderSection<ELFT>>();
+ part.elfHeader->name = part.name;
+ add(*part.elfHeader);
+
+ part.programHeaders =
+ std::make_unique<PartitionProgramHeadersSection<ELFT>>();
+ add(*part.programHeaders);
+ }
+
+ if (config->buildId != BuildIdKind::None) {
+ part.buildId = std::make_unique<BuildIdSection>();
+ add(*part.buildId);
+ }
+
+ part.dynStrTab = std::make_unique<StringTableSection>(".dynstr", true);
+ part.dynSymTab =
+ std::make_unique<SymbolTableSection<ELFT>>(*part.dynStrTab);
+ part.dynamic = std::make_unique<DynamicSection<ELFT>>();
+
+ if (hasMemtag()) {
+ part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>();
+ add(*part.memtagAndroidNote);
+ if (canHaveMemtagGlobals()) {
+ part.memtagGlobalDescriptors =
+ std::make_unique<MemtagGlobalDescriptors>();
+ add(*part.memtagGlobalDescriptors);
+ }
+ }
+
+ if (config->androidPackDynRelocs)
+ part.relaDyn = std::make_unique<AndroidPackedRelocationSection<ELFT>>(
+ relaDynName, threadCount);
+ else
+ part.relaDyn = std::make_unique<RelocationSection<ELFT>>(
+ relaDynName, config->zCombreloc, threadCount);
+
+ if (config->hasDynSymTab) {
+ add(*part.dynSymTab);
+
+ part.verSym = std::make_unique<VersionTableSection>();
+ add(*part.verSym);
+
+ if (!namedVersionDefs().empty()) {
+ part.verDef = std::make_unique<VersionDefinitionSection>();
+ add(*part.verDef);
+ }
+
+ part.verNeed = std::make_unique<VersionNeedSection<ELFT>>();
+ add(*part.verNeed);
+
+ if (config->gnuHash) {
+ part.gnuHashTab = std::make_unique<GnuHashTableSection>();
+ add(*part.gnuHashTab);
+ }
+
+ if (config->sysvHash) {
+ part.hashTab = std::make_unique<HashTableSection>();
+ add(*part.hashTab);
+ }
+
+ add(*part.dynamic);
+ add(*part.dynStrTab);
+ }
+ add(*part.relaDyn);
+
+ if (config->relrPackDynRelocs) {
+ part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount);
+ add(*part.relrDyn);
+ }
+
+ if (!config->relocatable) {
+ if (config->ehFrameHdr) {
+ part.ehFrameHdr = std::make_unique<EhFrameHeader>();
+ add(*part.ehFrameHdr);
+ }
+ part.ehFrame = std::make_unique<EhFrameSection>();
+ add(*part.ehFrame);
+
+ if (config->emachine == EM_ARM) {
+ // This section replaces all the individual .ARM.exidx InputSections.
+ part.armExidx = std::make_unique<ARMExidxSyntheticSection>();
+ add(*part.armExidx);
+ }
+ }
+
+ if (!config->packageMetadata.empty()) {
+ part.packageMetadataNote = std::make_unique<PackageMetadataNote>();
+ add(*part.packageMetadataNote);
+ }
+ }
+
+ if (partitions.size() != 1) {
+ // Create the partition end marker. This needs to be in partition number 255
+ // so that it is sorted after all other partitions. It also has other
+ // special handling (see createPhdrs() and combineEhSections()).
+ in.partEnd =
+ std::make_unique<BssSection>(".part.end", config->maxPageSize, 1);
+ in.partEnd->partition = 255;
+ add(*in.partEnd);
+
+ in.partIndex = std::make_unique<PartitionIndexSection>();
+ addOptionalRegular("__part_index_begin", in.partIndex.get(), 0);
+ addOptionalRegular("__part_index_end", in.partIndex.get(),
+ in.partIndex->getSize());
+ add(*in.partIndex);
+ }
+
+ // Add .got. MIPS' .got is so different from the other archs,
+ // it has its own class.
+ if (config->emachine == EM_MIPS) {
+ in.mipsGot = std::make_unique<MipsGotSection>();
+ add(*in.mipsGot);
+ } else {
+ in.got = std::make_unique<GotSection>();
+ add(*in.got);
+ }
+
+ if (config->emachine == EM_PPC) {
+ in.ppc32Got2 = std::make_unique<PPC32Got2Section>();
+ add(*in.ppc32Got2);
+ }
+
+ if (config->emachine == EM_PPC64) {
+ in.ppc64LongBranchTarget = std::make_unique<PPC64LongBranchTargetSection>();
+ add(*in.ppc64LongBranchTarget);
+ }
+
+ in.gotPlt = std::make_unique<GotPltSection>();
+ add(*in.gotPlt);
+ in.igotPlt = std::make_unique<IgotPltSection>();
+ add(*in.igotPlt);
+ // Add .relro_padding if DATA_SEGMENT_RELRO_END is used; otherwise, add the
+ // section in the absence of PHDRS/SECTIONS commands.
+ if (config->zRelro &&
+ ((script->phdrsCommands.empty() && !script->hasSectionsCommand) ||
+ script->seenRelroEnd)) {
+ in.relroPadding = std::make_unique<RelroPaddingSection>();
+ add(*in.relroPadding);
+ }
+
+ if (config->emachine == EM_ARM) {
+ in.armCmseSGSection = std::make_unique<ArmCmseSGSection>();
+ add(*in.armCmseSGSection);
+ }
+
+ // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat
+ // it as a relocation and ensure the referenced section is created.
+ if (ElfSym::globalOffsetTable && config->emachine != EM_MIPS) {
+ if (target->gotBaseSymInGotPlt)
+ in.gotPlt->hasGotPltOffRel = true;
+ else
+ in.got->hasGotOffRel = true;
+ }
+
+ // We always need to add rel[a].plt to output if it has entries.
+ // Even for static linking it can contain R_[*]_IRELATIVE relocations.
+ in.relaPlt = std::make_unique<RelocationSection<ELFT>>(
+ config->isRela ? ".rela.plt" : ".rel.plt", /*sort=*/false,
+ /*threadCount=*/1);
+ add(*in.relaPlt);
+
+ if ((config->emachine == EM_386 || config->emachine == EM_X86_64) &&
+ (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
+ in.ibtPlt = std::make_unique<IBTPltSection>();
+ add(*in.ibtPlt);
+ }
+
+ if (config->emachine == EM_PPC)
+ in.plt = std::make_unique<PPC32GlinkSection>();
+ else
+ in.plt = std::make_unique<PltSection>();
+ add(*in.plt);
+ in.iplt = std::make_unique<IpltSection>();
+ add(*in.iplt);
+
+ if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
+ add(*make<GnuPropertySection>());
+
+ if (config->gdbIndex) {
+ in.gdbIndex = GdbIndexSection::create<ELFT>();
+ add(*in.gdbIndex);
+ }
+
+ // .note.GNU-stack is always added when we are creating a re-linkable
+ // object file. Other linkers are using the presence of this marker
+ // section to control the executable-ness of the stack area, but that
+ // is irrelevant these days. Stack area should always be non-executable
+ // by default. So we emit this section unconditionally.
+ if (config->relocatable)
+ add(*make<GnuStackSection>());
+
+ if (in.symTab)
+ add(*in.symTab);
+ if (in.symTabShndx)
+ add(*in.symTabShndx);
+ add(*in.shStrTab);
+ if (in.strTab)
+ add(*in.strTab);
+}
+
InStruct elf::in;
std::vector<Partition> elf::partitions;
Partition *elf::mainPart;
-template GdbIndexSection *GdbIndexSection::create<ELF32LE>();
-template GdbIndexSection *GdbIndexSection::create<ELF32BE>();
-template GdbIndexSection *GdbIndexSection::create<ELF64LE>();
-template GdbIndexSection *GdbIndexSection::create<ELF64BE>();
-
template void elf::splitSections<ELF32LE>();
template void elf::splitSections<ELF32BE>();
template void elf::splitSections<ELF64LE>();
template void elf::splitSections<ELF64BE>();
-template class elf::MipsAbiFlagsSection<ELF32LE>;
-template class elf::MipsAbiFlagsSection<ELF32BE>;
-template class elf::MipsAbiFlagsSection<ELF64LE>;
-template class elf::MipsAbiFlagsSection<ELF64BE>;
-
-template class elf::MipsOptionsSection<ELF32LE>;
-template class elf::MipsOptionsSection<ELF32BE>;
-template class elf::MipsOptionsSection<ELF64LE>;
-template class elf::MipsOptionsSection<ELF64BE>;
-
template void EhFrameSection::iterateFDEWithLSDA<ELF32LE>(
function_ref<void(InputSection &)>);
template void EhFrameSection::iterateFDEWithLSDA<ELF32BE>(
@@ -4015,41 +4313,11 @@ template void EhFrameSection::iterateFDEWithLSDA<ELF64LE>(
template void EhFrameSection::iterateFDEWithLSDA<ELF64BE>(
function_ref<void(InputSection &)>);
-template class elf::MipsReginfoSection<ELF32LE>;
-template class elf::MipsReginfoSection<ELF32BE>;
-template class elf::MipsReginfoSection<ELF64LE>;
-template class elf::MipsReginfoSection<ELF64BE>;
-
-template class elf::DynamicSection<ELF32LE>;
-template class elf::DynamicSection<ELF32BE>;
-template class elf::DynamicSection<ELF64LE>;
-template class elf::DynamicSection<ELF64BE>;
-
-template class elf::RelocationSection<ELF32LE>;
-template class elf::RelocationSection<ELF32BE>;
-template class elf::RelocationSection<ELF64LE>;
-template class elf::RelocationSection<ELF64BE>;
-
-template class elf::AndroidPackedRelocationSection<ELF32LE>;
-template class elf::AndroidPackedRelocationSection<ELF32BE>;
-template class elf::AndroidPackedRelocationSection<ELF64LE>;
-template class elf::AndroidPackedRelocationSection<ELF64BE>;
-
-template class elf::RelrSection<ELF32LE>;
-template class elf::RelrSection<ELF32BE>;
-template class elf::RelrSection<ELF64LE>;
-template class elf::RelrSection<ELF64BE>;
-
template class elf::SymbolTableSection<ELF32LE>;
template class elf::SymbolTableSection<ELF32BE>;
template class elf::SymbolTableSection<ELF64LE>;
template class elf::SymbolTableSection<ELF64BE>;
-template class elf::VersionNeedSection<ELF32LE>;
-template class elf::VersionNeedSection<ELF32BE>;
-template class elf::VersionNeedSection<ELF64LE>;
-template class elf::VersionNeedSection<ELF64BE>;
-
template void elf::writeEhdr<ELF32LE>(uint8_t *Buf, Partition &Part);
template void elf::writeEhdr<ELF32BE>(uint8_t *Buf, Partition &Part);
template void elf::writeEhdr<ELF64LE>(uint8_t *Buf, Partition &Part);
@@ -4060,12 +4328,7 @@ template void elf::writePhdrs<ELF32BE>(uint8_t *Buf, Partition &Part);
template void elf::writePhdrs<ELF64LE>(uint8_t *Buf, Partition &Part);
template void elf::writePhdrs<ELF64BE>(uint8_t *Buf, Partition &Part);
-template class elf::PartitionElfHeaderSection<ELF32LE>;
-template class elf::PartitionElfHeaderSection<ELF32BE>;
-template class elf::PartitionElfHeaderSection<ELF64LE>;
-template class elf::PartitionElfHeaderSection<ELF64BE>;
-
-template class elf::PartitionProgramHeadersSection<ELF32LE>;
-template class elf::PartitionProgramHeadersSection<ELF32BE>;
-template class elf::PartitionProgramHeadersSection<ELF64LE>;
-template class elf::PartitionProgramHeadersSection<ELF64BE>;
+template void elf::createSyntheticSections<ELF32LE>();
+template void elf::createSyntheticSections<ELF32BE>();
+template void elf::createSyntheticSections<ELF64LE>();
+template void elf::createSyntheticSections<ELF64BE>();
diff --git a/lld/ELF/SyntheticSections.h b/lld/ELF/SyntheticSections.h
index 7490fb61fb6f..759b78668f54 100644
--- a/lld/ELF/SyntheticSections.h
+++ b/lld/ELF/SyntheticSections.h
@@ -822,7 +822,7 @@ public:
};
GdbIndexSection();
- template <typename ELFT> static GdbIndexSection *create();
+ template <typename ELFT> static std::unique_ptr<GdbIndexSection> create();
void writeTo(uint8_t *buf) override;
size_t getSize() const override { return size; }
bool isNeeded() const override;
@@ -1284,11 +1284,15 @@ private:
SmallVector<const Symbol *, 0> symbols;
};
+template <class ELFT> void createSyntheticSections();
InputSection *createInterpSection();
MergeInputSection *createCommentSection();
template <class ELFT> void splitSections();
void combineEhSections();
+bool hasMemtag();
+bool canHaveMemtagGlobals();
+
template <typename ELFT> void writeEhdr(uint8_t *buf, Partition &part);
template <typename ELFT> void writePhdrs(uint8_t *buf, Partition &part);
@@ -1359,6 +1363,8 @@ struct InStruct {
std::unique_ptr<PPC32Got2Section> ppc32Got2;
std::unique_ptr<IBTPltSection> ibtPlt;
std::unique_ptr<RelocationBaseSection> relaPlt;
+ // Non-SHF_ALLOC sections
+ std::unique_ptr<GdbIndexSection> gdbIndex;
std::unique_ptr<StringTableSection> shStrTab;
std::unique_ptr<StringTableSection> strTab;
std::unique_ptr<SymbolTableBaseSection> symTab;
diff --git a/lld/ELF/Writer.cpp b/lld/ELF/Writer.cpp
index fc9084f40044..d2a9e872dab9 100644
--- a/lld/ELF/Writer.cpp
+++ b/lld/ELF/Writer.cpp
@@ -91,11 +91,6 @@ private:
};
} // anonymous namespace
-static bool needsInterpSection() {
- return !config->relocatable && !config->shared &&
- !config->dynamicLinker.empty() && script->needsInterpSection();
-}
-
template <class ELFT> void elf::writeResult() {
Writer<ELFT>().run();
}
@@ -297,22 +292,6 @@ static void demoteSymbolsAndComputeIsPreemptible() {
}
}
-bool elf::hasMemtag() {
- return config->emachine == EM_AARCH64 &&
- config->androidMemtagMode != ELF::NT_MEMTAG_LEVEL_NONE;
-}
-
-// Fully static executables don't support MTE globals at this point in time, as
-// we currently rely on:
-// - A dynamic loader to process relocations, and
-// - Dynamic entries.
-// This restriction could be removed in future by re-using some of the ideas
-// that ifuncs use in fully static executables.
-bool elf::canHaveMemtagGlobals() {
- return hasMemtag() &&
- (config->relocatable || config->shared || needsInterpSection());
-}
-
static OutputSection *findSection(StringRef name, unsigned partition = 1) {
for (SectionCommand *cmd : script->sectionCommands)
if (auto *osd = dyn_cast<OutputDesc>(cmd))
@@ -321,270 +300,6 @@ static OutputSection *findSection(StringRef name, unsigned partition = 1) {
return nullptr;
}
-template <class ELFT> void elf::createSyntheticSections() {
- // Initialize all pointers with NULL. This is needed because
- // you can call lld::elf::main more than once as a library.
- Out::tlsPhdr = nullptr;
- Out::preinitArray = nullptr;
- Out::initArray = nullptr;
- Out::finiArray = nullptr;
-
- // Add the .interp section first because it is not a SyntheticSection.
- // The removeUnusedSyntheticSections() function relies on the
- // SyntheticSections coming last.
- if (needsInterpSection()) {
- for (size_t i = 1; i <= partitions.size(); ++i) {
- InputSection *sec = createInterpSection();
- sec->partition = i;
- ctx.inputSections.push_back(sec);
- }
- }
-
- auto add = [](SyntheticSection &sec) { ctx.inputSections.push_back(&sec); };
-
- in.shStrTab = std::make_unique<StringTableSection>(".shstrtab", false);
-
- Out::programHeaders = make<OutputSection>("", 0, SHF_ALLOC);
- Out::programHeaders->addralign = config->wordsize;
-
- if (config->strip != StripPolicy::All) {
- in.strTab = std::make_unique<StringTableSection>(".strtab", false);
- in.symTab = std::make_unique<SymbolTableSection<ELFT>>(*in.strTab);
- in.symTabShndx = std::make_unique<SymtabShndxSection>();
- }
-
- in.bss = std::make_unique<BssSection>(".bss", 0, 1);
- add(*in.bss);
-
- // If there is a SECTIONS command and a .data.rel.ro section name use name
- // .data.rel.ro.bss so that we match in the .data.rel.ro output section.
- // This makes sure our relro is contiguous.
- bool hasDataRelRo = script->hasSectionsCommand && findSection(".data.rel.ro");
- in.bssRelRo = std::make_unique<BssSection>(
- hasDataRelRo ? ".data.rel.ro.bss" : ".bss.rel.ro", 0, 1);
- add(*in.bssRelRo);
-
- // Add MIPS-specific sections.
- if (config->emachine == EM_MIPS) {
- if (!config->shared && config->hasDynSymTab) {
- in.mipsRldMap = std::make_unique<MipsRldMapSection>();
- add(*in.mipsRldMap);
- }
- if ((in.mipsAbiFlags = MipsAbiFlagsSection<ELFT>::create()))
- add(*in.mipsAbiFlags);
- if ((in.mipsOptions = MipsOptionsSection<ELFT>::create()))
- add(*in.mipsOptions);
- if ((in.mipsReginfo = MipsReginfoSection<ELFT>::create()))
- add(*in.mipsReginfo);
- }
-
- StringRef relaDynName = config->isRela ? ".rela.dyn" : ".rel.dyn";
-
- const unsigned threadCount = config->threadCount;
- for (Partition &part : partitions) {
- auto add = [&](SyntheticSection &sec) {
- sec.partition = part.getNumber();
- ctx.inputSections.push_back(&sec);
- };
-
- if (!part.name.empty()) {
- part.elfHeader = std::make_unique<PartitionElfHeaderSection<ELFT>>();
- part.elfHeader->name = part.name;
- add(*part.elfHeader);
-
- part.programHeaders =
- std::make_unique<PartitionProgramHeadersSection<ELFT>>();
- add(*part.programHeaders);
- }
-
- if (config->buildId != BuildIdKind::None) {
- part.buildId = std::make_unique<BuildIdSection>();
- add(*part.buildId);
- }
-
- part.dynStrTab = std::make_unique<StringTableSection>(".dynstr", true);
- part.dynSymTab =
- std::make_unique<SymbolTableSection<ELFT>>(*part.dynStrTab);
- part.dynamic = std::make_unique<DynamicSection<ELFT>>();
-
- if (hasMemtag()) {
- part.memtagAndroidNote = std::make_unique<MemtagAndroidNote>();
- add(*part.memtagAndroidNote);
- if (canHaveMemtagGlobals()) {
- part.memtagGlobalDescriptors =
- std::make_unique<MemtagGlobalDescriptors>();
- add(*part.memtagGlobalDescriptors);
- }
- }
-
- if (config->androidPackDynRelocs)
- part.relaDyn = std::make_unique<AndroidPackedRelocationSection<ELFT>>(
- relaDynName, threadCount);
- else
- part.relaDyn = std::make_unique<RelocationSection<ELFT>>(
- relaDynName, config->zCombreloc, threadCount);
-
- if (config->hasDynSymTab) {
- add(*part.dynSymTab);
-
- part.verSym = std::make_unique<VersionTableSection>();
- add(*part.verSym);
-
- if (!namedVersionDefs().empty()) {
- part.verDef = std::make_unique<VersionDefinitionSection>();
- add(*part.verDef);
- }
-
- part.verNeed = std::make_unique<VersionNeedSection<ELFT>>();
- add(*part.verNeed);
-
- if (config->gnuHash) {
- part.gnuHashTab = std::make_unique<GnuHashTableSection>();
- add(*part.gnuHashTab);
- }
-
- if (config->sysvHash) {
- part.hashTab = std::make_unique<HashTableSection>();
- add(*part.hashTab);
- }
-
- add(*part.dynamic);
- add(*part.dynStrTab);
- }
- add(*part.relaDyn);
-
- if (config->relrPackDynRelocs) {
- part.relrDyn = std::make_unique<RelrSection<ELFT>>(threadCount);
- add(*part.relrDyn);
- }
-
- if (!config->relocatable) {
- if (config->ehFrameHdr) {
- part.ehFrameHdr = std::make_unique<EhFrameHeader>();
- add(*part.ehFrameHdr);
- }
- part.ehFrame = std::make_unique<EhFrameSection>();
- add(*part.ehFrame);
-
- if (config->emachine == EM_ARM) {
- // This section replaces all the individual .ARM.exidx InputSections.
- part.armExidx = std::make_unique<ARMExidxSyntheticSection>();
- add(*part.armExidx);
- }
- }
-
- if (!config->packageMetadata.empty()) {
- part.packageMetadataNote = std::make_unique<PackageMetadataNote>();
- add(*part.packageMetadataNote);
- }
- }
-
- if (partitions.size() != 1) {
- // Create the partition end marker. This needs to be in partition number 255
- // so that it is sorted after all other partitions. It also has other
- // special handling (see createPhdrs() and combineEhSections()).
- in.partEnd =
- std::make_unique<BssSection>(".part.end", config->maxPageSize, 1);
- in.partEnd->partition = 255;
- add(*in.partEnd);
-
- in.partIndex = std::make_unique<PartitionIndexSection>();
- addOptionalRegular("__part_index_begin", in.partIndex.get(), 0);
- addOptionalRegular("__part_index_end", in.partIndex.get(),
- in.partIndex->getSize());
- add(*in.partIndex);
- }
-
- // Add .got. MIPS' .got is so different from the other archs,
- // it has its own class.
- if (config->emachine == EM_MIPS) {
- in.mipsGot = std::make_unique<MipsGotSection>();
- add(*in.mipsGot);
- } else {
- in.got = std::make_unique<GotSection>();
- add(*in.got);
- }
-
- if (config->emachine == EM_PPC) {
- in.ppc32Got2 = std::make_unique<PPC32Got2Section>();
- add(*in.ppc32Got2);
- }
-
- if (config->emachine == EM_PPC64) {
- in.ppc64LongBranchTarget = std::make_unique<PPC64LongBranchTargetSection>();
- add(*in.ppc64LongBranchTarget);
- }
-
- in.gotPlt = std::make_unique<GotPltSection>();
- add(*in.gotPlt);
- in.igotPlt = std::make_unique<IgotPltSection>();
- add(*in.igotPlt);
- // Add .relro_padding if DATA_SEGMENT_RELRO_END is used; otherwise, add the
- // section in the absence of PHDRS/SECTIONS commands.
- if (config->zRelro && ((script->phdrsCommands.empty() &&
- !script->hasSectionsCommand) || script->seenRelroEnd)) {
- in.relroPadding = std::make_unique<RelroPaddingSection>();
- add(*in.relroPadding);
- }
-
- if (config->emachine == EM_ARM) {
- in.armCmseSGSection = std::make_unique<ArmCmseSGSection>();
- add(*in.armCmseSGSection);
- }
-
- // _GLOBAL_OFFSET_TABLE_ is defined relative to either .got.plt or .got. Treat
- // it as a relocation and ensure the referenced section is created.
- if (ElfSym::globalOffsetTable && config->emachine != EM_MIPS) {
- if (target->gotBaseSymInGotPlt)
- in.gotPlt->hasGotPltOffRel = true;
- else
- in.got->hasGotOffRel = true;
- }
-
- if (config->gdbIndex)
- add(*GdbIndexSection::create<ELFT>());
-
- // We always need to add rel[a].plt to output if it has entries.
- // Even for static linking it can contain R_[*]_IRELATIVE relocations.
- in.relaPlt = std::make_unique<RelocationSection<ELFT>>(
- config->isRela ? ".rela.plt" : ".rel.plt", /*sort=*/false,
- /*threadCount=*/1);
- add(*in.relaPlt);
-
- if ((config->emachine == EM_386 || config->emachine == EM_X86_64) &&
- (config->andFeatures & GNU_PROPERTY_X86_FEATURE_1_IBT)) {
- in.ibtPlt = std::make_unique<IBTPltSection>();
- add(*in.ibtPlt);
- }
-
- if (config->emachine == EM_PPC)
- in.plt = std::make_unique<PPC32GlinkSection>();
- else
- in.plt = std::make_unique<PltSection>();
- add(*in.plt);
- in.iplt = std::make_unique<IpltSection>();
- add(*in.iplt);
-
- if (config->andFeatures || !ctx.aarch64PauthAbiCoreInfo.empty())
- add(*make<GnuPropertySection>());
-
- // .note.GNU-stack is always added when we are creating a re-linkable
- // object file. Other linkers are using the presence of this marker
- // section to control the executable-ness of the stack area, but that
- // is irrelevant these days. Stack area should always be non-executable
- // by default. So we emit this section unconditionally.
- if (config->relocatable)
- add(*make<GnuStackSection>());
-
- if (in.symTab)
- add(*in.symTab);
- if (in.symTabShndx)
- add(*in.symTabShndx);
- add(*in.shStrTab);
- if (in.strTab)
- add(*in.strTab);
-}
-
// The main function of the writer.
template <class ELFT> void Writer<ELFT>::run() {
// Now that we have a complete set of output sections. This function
@@ -3112,11 +2827,6 @@ template <class ELFT> void Writer<ELFT>::writeBuildId() {
part.buildId->writeBuildId(output);
}
-template void elf::createSyntheticSections<ELF32LE>();
-template void elf::createSyntheticSections<ELF32BE>();
-template void elf::createSyntheticSections<ELF64LE>();
-template void elf::createSyntheticSections<ELF64BE>();
-
template void elf::writeResult<ELF32LE>();
template void elf::writeResult<ELF32BE>();
template void elf::writeResult<ELF64LE>();
diff --git a/lld/ELF/Writer.h b/lld/ELF/Writer.h
index aac8176d9098..7aa06dbcb131 100644
--- a/lld/ELF/Writer.h
+++ b/lld/ELF/Writer.h
@@ -17,7 +17,6 @@ namespace lld::elf {
class InputFile;
class OutputSection;
void copySectionsIntoPartitions();
-template <class ELFT> void createSyntheticSections();
template <class ELFT> void writeResult();
// This describes a program header entry.
@@ -57,8 +56,6 @@ bool isMipsN32Abi(const InputFile *f);
bool isMicroMips();
bool isMipsR6();
-bool hasMemtag();
-bool canHaveMemtagGlobals();
} // namespace lld::elf
#endif
diff --git a/lld/test/COFF/arm64x-icf.s b/lld/test/COFF/arm64x-icf.s
new file mode 100644
index 000000000000..c8df21d3e496
--- /dev/null
+++ b/lld/test/COFF/arm64x-icf.s
@@ -0,0 +1,37 @@
+// REQUIRES: aarch64
+// RUN: split-file %s %t.dir && cd %t.dir
+
+// RUN: llvm-mc -filetype=obj -triple=arm64ec-windows func-arm64ec.s -o func-arm64ec.obj
+// RUN: llvm-mc -filetype=obj -triple=aarch64-windows func-arm64.s -o func-arm64.obj
+// RUN: lld-link -machine:arm64x -dll -noentry -out:out.dll func-arm64ec.obj func-arm64.obj
+// RUN: llvm-objdump -d out.dll | FileCheck %s
+
+// CHECK: 0000000180001000 <.text>:
+// CHECK-NEXT: 180001000: 52800020 mov w0, #0x1 // =1
+// CHECK-NEXT: 180001004: d65f03c0 ret
+// CHECK-NEXT: ...
+// CHECK-NEXT: 180002000: 52800020 mov w0, #0x1 // =1
+// CHECK-NEXT: 180002004: d65f03c0 ret
+
+
+#--- func-arm64.s
+ .section .text,"xr",discard,func
+ .globl func
+ .p2align 2
+func:
+ mov w0, #1
+ ret
+
+ .data
+ .rva func
+
+#--- func-arm64ec.s
+ .section .text,"xr",discard,"#func"
+ .globl "#func"
+ .p2align 2
+"#func":
+ mov w0, #1
+ ret
+
+ .data
+ .rva "#func"
diff --git a/lldb/cmake/caches/Apple-lldb-Linux.cmake b/lldb/cmake/caches/Apple-lldb-Linux.cmake
index 9258f01e2ec2..bfa660d8654b 100644
--- a/lldb/cmake/caches/Apple-lldb-Linux.cmake
+++ b/lldb/cmake/caches/Apple-lldb-Linux.cmake
@@ -1,5 +1,5 @@
include(${CMAKE_CURRENT_LIST_DIR}/Apple-lldb-base.cmake)
-set(LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES ON CACHE BOOL "")
+set(LLVM_ENABLE_EXPORTED_SYMBOLS_IN_EXECUTABLES ON CACHE BOOL "" FORCE)
set(LLVM_DISTRIBUTION_COMPONENTS
lldb
diff --git a/llvm/include/llvm/Analysis/VecFuncs.def b/llvm/include/llvm/Analysis/VecFuncs.def
index 394e4a05fbc0..10f1333cf888 100644
--- a/llvm/include/llvm/Analysis/VecFuncs.def
+++ b/llvm/include/llvm/Analysis/VecFuncs.def
@@ -1005,6 +1005,8 @@ TLI_DEFINE_VECFUNC("llvm.log2.f32", "armpl_svlog2_f32_x", SCALABLE(4), MASKED, "
TLI_DEFINE_VECFUNC("modf", "armpl_vmodfq_f64", FIXED(2), NOMASK, "_ZGV_LLVM_N2vl8")
TLI_DEFINE_VECFUNC("modff", "armpl_vmodfq_f32", FIXED(4), NOMASK, "_ZGV_LLVM_N4vl4")
+TLI_DEFINE_VECFUNC("modf", "armpl_svmodf_f64_x", SCALABLE(2), MASKED, "_ZGVsMxvl8")
+TLI_DEFINE_VECFUNC("modff", "armpl_svmodf_f32_x", SCALABLE(4), MASKED, "_ZGVsMxvl4")
TLI_DEFINE_VECFUNC("nextafter", "armpl_vnextafterq_f64", FIXED(2), NOMASK, "_ZGV_LLVM_N2vv")
TLI_DEFINE_VECFUNC("nextafterf", "armpl_vnextafterq_f32", FIXED(4), NOMASK, "_ZGV_LLVM_N4vv")
@@ -1033,9 +1035,13 @@ TLI_DEFINE_VECFUNC("llvm.sin.f32", "armpl_svsin_f32_x", SCALABLE(4), MASKED, "_Z
TLI_DEFINE_VECFUNC("sincos", "armpl_vsincosq_f64", FIXED(2), NOMASK, "_ZGV_LLVM_N2vl8l8")
TLI_DEFINE_VECFUNC("sincosf", "armpl_vsincosq_f32", FIXED(4), NOMASK, "_ZGV_LLVM_N4vl4l4")
+TLI_DEFINE_VECFUNC("sincos", "armpl_svsincos_f64_x", SCALABLE(2), MASKED, "_ZGVsMxvl8l8")
+TLI_DEFINE_VECFUNC("sincosf", "armpl_svsincos_f32_x", SCALABLE(4), MASKED, "_ZGVsMxvl4l4")
TLI_DEFINE_VECFUNC("sincospi", "armpl_vsincospiq_f64", FIXED(2), NOMASK, "_ZGV_LLVM_N2vl8l8")
TLI_DEFINE_VECFUNC("sincospif", "armpl_vsincospiq_f32", FIXED(4), NOMASK, "_ZGV_LLVM_N4vl4l4")
+TLI_DEFINE_VECFUNC("sincospi", "armpl_svsincospi_f64_x", SCALABLE(2), MASKED, "_ZGVsMxvl8l8")
+TLI_DEFINE_VECFUNC("sincospif", "armpl_svsincospi_f32_x", SCALABLE(4), MASKED, "_ZGVsMxvl4l4")
TLI_DEFINE_VECFUNC("sinh", "armpl_vsinhq_f64", FIXED(2), NOMASK, "_ZGV_LLVM_N2v")
TLI_DEFINE_VECFUNC("sinhf", "armpl_vsinhq_f32", FIXED(4), NOMASK, "_ZGV_LLVM_N4v")
diff --git a/llvm/include/llvm/CodeGen/MachineCombinerPattern.h b/llvm/include/llvm/CodeGen/MachineCombinerPattern.h
index 89eed7463bd7..41b73eaae029 100644
--- a/llvm/include/llvm/CodeGen/MachineCombinerPattern.h
+++ b/llvm/include/llvm/CodeGen/MachineCombinerPattern.h
@@ -175,6 +175,8 @@ enum class MachineCombinerPattern {
FMADD_XA,
FMSUB,
FNMSUB,
+ SHXADD_ADD_SLLI_OP1,
+ SHXADD_ADD_SLLI_OP2,
// X86 VNNI
DPWSSD,
diff --git a/llvm/include/llvm/Support/raw_socket_stream.h b/llvm/include/llvm/Support/raw_socket_stream.h
index c219792d8246..bddd47eb75e1 100644
--- a/llvm/include/llvm/Support/raw_socket_stream.h
+++ b/llvm/include/llvm/Support/raw_socket_stream.h
@@ -17,12 +17,17 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"
+#include <atomic>
+#include <chrono>
+
namespace llvm {
class raw_socket_stream;
-// Make sure that calls to WSAStartup and WSACleanup are balanced.
#ifdef _WIN32
+/// Ensures proper initialization and cleanup of winsock resources
+///
+/// Make sure that calls to WSAStartup and WSACleanup are balanced.
class WSABalancer {
public:
WSABalancer();
@@ -30,22 +35,87 @@ public:
};
#endif // _WIN32
+/// Manages a passive (i.e., listening) UNIX domain socket
+///
+/// The ListeningSocket class encapsulates a UNIX domain socket that can listen
+/// and accept incoming connections. ListeningSocket is portable and supports
+/// Windows builds begining with Insider Build 17063. ListeningSocket is
+/// designed for server-side operations, working alongside \p raw_socket_streams
+/// that function as client connections.
+///
+/// Usage example:
+/// \code{.cpp}
+/// std::string Path = "/path/to/socket"
+/// Expected<ListeningSocket> S = ListeningSocket::createUnix(Path);
+///
+/// if (S) {
+/// Expected<std::unique_ptr<raw_socket_stream>> connection = S->accept();
+/// if (connection) {
+/// // Use the accepted raw_socket_stream for communication.
+/// }
+/// }
+/// \endcode
+///
class ListeningSocket {
- int FD;
- std::string SocketPath;
- ListeningSocket(int SocketFD, StringRef SocketPath);
+
+ std::atomic<int> FD;
+ std::string SocketPath; // Not modified after construction
+
+ /// If a seperate thread calls ListeningSocket::shutdown, the ListeningSocket
+ /// file descriptor (FD) could be closed while ::poll is waiting for it to be
+ /// ready to perform a I/O operations. ::poll will continue to block even
+ /// after FD is closed so use a self-pipe mechanism to get ::poll to return
+ int PipeFD[2]; // Not modified after construction other then move constructor
+
+ ListeningSocket(int SocketFD, StringRef SocketPath, int PipeFD[2]);
+
#ifdef _WIN32
WSABalancer _;
#endif // _WIN32
public:
+ ~ListeningSocket();
+ ListeningSocket(ListeningSocket &&LS);
+ ListeningSocket(const ListeningSocket &LS) = delete;
+ ListeningSocket &operator=(const ListeningSocket &) = delete;
+
+ /// Closes the FD, unlinks the socket file, and writes to PipeFD.
+ ///
+ /// After the construction of the ListeningSocket, shutdown is signal safe if
+ /// it is called during the lifetime of the object. shutdown can be called
+ /// concurrently with ListeningSocket::accept as writing to PipeFD will cause
+ /// a blocking call to ::poll to return.
+ ///
+ /// Once shutdown is called there is no way to reinitialize ListeningSocket.
+ void shutdown();
+
+ /// Accepts an incoming connection on the listening socket. This method can
+ /// optionally either block until a connection is available or timeout after a
+ /// specified amount of time has passed. By default the method will block
+ /// until the socket has recieved a connection.
+ ///
+ /// \param Timeout An optional timeout duration in milliseconds. Setting
+ /// Timeout to -1 causes accept to block indefinitely
+ ///
+ Expected<std::unique_ptr<raw_socket_stream>>
+ accept(std::chrono::milliseconds Timeout = std::chrono::milliseconds(-1));
+
+ /// Creates a listening socket bound to the specified file system path.
+ /// Handles the socket creation, binding, and immediately starts listening for
+ /// incoming connections.
+ ///
+ /// \param SocketPath The file system path where the socket will be created
+ /// \param MaxBacklog The max number of connections in a socket's backlog
+ ///
static Expected<ListeningSocket> createUnix(
StringRef SocketPath,
int MaxBacklog = llvm::hardware_concurrency().compute_thread_count());
- Expected<std::unique_ptr<raw_socket_stream>> accept();
- ListeningSocket(ListeningSocket &&LS);
- ~ListeningSocket();
};
+
+//===----------------------------------------------------------------------===//
+// raw_socket_stream
+//===----------------------------------------------------------------------===//
+
class raw_socket_stream : public raw_fd_stream {
uint64_t current_pos() const override { return 0; }
#ifdef _WIN32
@@ -54,7 +124,7 @@ class raw_socket_stream : public raw_fd_stream {
public:
raw_socket_stream(int SocketFD);
- /// Create a \p raw_socket_stream connected to the Unix domain socket at \p
+ /// Create a \p raw_socket_stream connected to the UNIX domain socket at \p
/// SocketPath.
static Expected<std::unique_ptr<raw_socket_stream>>
createConnectedUnix(StringRef SocketPath);
diff --git a/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h b/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h
index 581d354fc476..7c725a3c1216 100644
--- a/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h
+++ b/llvm/include/llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h
@@ -86,12 +86,9 @@ template <> struct IRTraits<BasicBlock> {
// SampleProfileProber.
class PseudoProbeManager {
DenseMap<uint64_t, PseudoProbeDescriptor> GUIDToProbeDescMap;
- const ThinOrFullLTOPhase LTOPhase;
public:
- PseudoProbeManager(const Module &M,
- ThinOrFullLTOPhase LTOPhase = ThinOrFullLTOPhase::None)
- : LTOPhase(LTOPhase) {
+ PseudoProbeManager(const Module &M) {
if (NamedMDNode *FuncInfo =
M.getNamedMetadata(PseudoProbeDescMetadataName)) {
for (const auto *Operand : FuncInfo->operands()) {
@@ -140,13 +137,9 @@ public:
// be different and result in different checksums. So we should use the
// state from the new (available_externally) function, which is saved in its
// attribute.
- assert((LTOPhase != ThinOrFullLTOPhase::ThinLTOPostLink ||
- IsAvailableExternallyLinkage || !Desc ||
- profileIsHashMismatched(*Desc, Samples) ==
- F.hasFnAttribute("profile-checksum-mismatch")) &&
- "In post-link, profile checksum matching state doesn't match the "
- "internal function's 'profile-checksum-mismatch' attribute.");
- (void)LTOPhase;
+ // TODO: If the function's profile only exists as nested inlinee profile in
+ // a different module, we don't have the attr mismatch state(unknown), we
+ // need to fix it later.
if (IsAvailableExternallyLinkage || !Desc)
return !F.hasFnAttribute("profile-checksum-mismatch");
diff --git a/llvm/lib/Analysis/LoopAccessAnalysis.cpp b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
index c25eede96a18..3bfc9700a145 100644
--- a/llvm/lib/Analysis/LoopAccessAnalysis.cpp
+++ b/llvm/lib/Analysis/LoopAccessAnalysis.cpp
@@ -1917,14 +1917,30 @@ isLoopVariantIndirectAddress(ArrayRef<const Value *> UnderlyingObjects,
});
}
-// Get the dependence distance, stride, type size in whether i is a write for
+namespace {
+struct DepDistanceStrideAndSizeInfo {
+ const SCEV *Dist;
+ uint64_t Stride;
+ uint64_t TypeByteSize;
+ bool AIsWrite;
+ bool BIsWrite;
+
+ DepDistanceStrideAndSizeInfo(const SCEV *Dist, uint64_t Stride,
+ uint64_t TypeByteSize, bool AIsWrite,
+ bool BIsWrite)
+ : Dist(Dist), Stride(Stride), TypeByteSize(TypeByteSize),
+ AIsWrite(AIsWrite), BIsWrite(BIsWrite) {}
+};
+} // namespace
+
+// Get the dependence distance, stride, type size and whether it is a write for
// the dependence between A and B. Returns a DepType, if we can prove there's
// no dependence or the analysis fails. Outlined to lambda to limit he scope
// of various temporary variables, like A/BPtr, StrideA/BPtr and others.
// Returns either the dependence result, if it could already be determined, or a
-// tuple with (Distance, Stride, TypeSize, AIsWrite, BIsWrite).
+// struct containing (Distance, Stride, TypeSize, AIsWrite, BIsWrite).
static std::variant<MemoryDepChecker::Dependence::DepType,
- std::tuple<const SCEV *, uint64_t, uint64_t, bool, bool>>
+ DepDistanceStrideAndSizeInfo>
getDependenceDistanceStrideAndSize(
const AccessAnalysis::MemAccessInfo &A, Instruction *AInst,
const AccessAnalysis::MemAccessInfo &B, Instruction *BInst,
@@ -1993,7 +2009,8 @@ getDependenceDistanceStrideAndSize(
if (!HasSameSize)
TypeByteSize = 0;
uint64_t Stride = std::abs(StrideAPtr);
- return std::make_tuple(Dist, Stride, TypeByteSize, AIsWrite, BIsWrite);
+ return DepDistanceStrideAndSizeInfo(Dist, Stride, TypeByteSize, AIsWrite,
+ BIsWrite);
}
MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
@@ -2012,7 +2029,7 @@ MemoryDepChecker::Dependence::DepType MemoryDepChecker::isDependent(
return std::get<Dependence::DepType>(Res);
const auto &[Dist, Stride, TypeByteSize, AIsWrite, BIsWrite] =
- std::get<std::tuple<const SCEV *, uint64_t, uint64_t, bool, bool>>(Res);
+ std::get<DepDistanceStrideAndSizeInfo>(Res);
bool HasSameSize = TypeByteSize > 0;
ScalarEvolution &SE = *PSE.getSE();
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index e030b9fc7dac..9fcce797f559 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -928,11 +928,9 @@ static const SCEV *BinomialCoefficient(const SCEV *It, unsigned K,
APInt OddFactorial(W, 1);
unsigned T = 1;
for (unsigned i = 3; i <= K; ++i) {
- APInt Mult(W, i);
- unsigned TwoFactors = Mult.countr_zero();
+ unsigned TwoFactors = countr_zero(i);
T += TwoFactors;
- Mult.lshrInPlace(TwoFactors);
- OddFactorial *= Mult;
+ OddFactorial *= (i >> TwoFactors);
}
// We need at least W + T bits for the multiplication step
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index ca48cfe77381..3a10de72a275 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -1621,6 +1621,14 @@ static void computeKnownBitsFromOperator(const Operator *I,
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
Known = KnownBits::ssub_sat(Known, Known2);
break;
+ // for min/max reduce, any bit common to each element in the input vec
+ // is set in the output.
+ case Intrinsic::vector_reduce_umax:
+ case Intrinsic::vector_reduce_umin:
+ case Intrinsic::vector_reduce_smax:
+ case Intrinsic::vector_reduce_smin:
+ computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
+ break;
case Intrinsic::umin:
computeKnownBits(I->getOperand(0), Known, Depth + 1, Q);
computeKnownBits(I->getOperand(1), Known2, Depth + 1, Q);
@@ -2463,6 +2471,34 @@ static bool isNonZeroSub(const APInt &DemandedElts, unsigned Depth,
return ::isKnownNonEqual(X, Y, Depth, Q);
}
+static bool isNonZeroMul(const APInt &DemandedElts, unsigned Depth,
+ const SimplifyQuery &Q, unsigned BitWidth, Value *X,
+ Value *Y, bool NSW, bool NUW) {
+ // If X and Y are non-zero then so is X * Y as long as the multiplication
+ // does not overflow.
+ if (NSW || NUW)
+ return isKnownNonZero(X, DemandedElts, Depth, Q) &&
+ isKnownNonZero(Y, DemandedElts, Depth, Q);
+
+ // If either X or Y is odd, then if the other is non-zero the result can't
+ // be zero.
+ KnownBits XKnown = computeKnownBits(X, DemandedElts, Depth, Q);
+ if (XKnown.One[0])
+ return isKnownNonZero(Y, DemandedElts, Depth, Q);
+
+ KnownBits YKnown = computeKnownBits(Y, DemandedElts, Depth, Q);
+ if (YKnown.One[0])
+ return XKnown.isNonZero() || isKnownNonZero(X, DemandedElts, Depth, Q);
+
+ // If there exists any subset of X (sX) and subset of Y (sY) s.t sX * sY is
+ // non-zero, then X * Y is non-zero. We can find sX and sY by just taking
+ // the lowest known One of X and Y. If they are non-zero, the result
+ // must be non-zero. We can check if LSB(X) * LSB(Y) != 0 by doing
+ // X.CountLeadingZeros + Y.CountLeadingZeros < BitWidth.
+ return (XKnown.countMaxTrailingZeros() + YKnown.countMaxTrailingZeros()) <
+ BitWidth;
+}
+
static bool isNonZeroShift(const Operator *I, const APInt &DemandedElts,
unsigned Depth, const SimplifyQuery &Q,
const KnownBits &KnownVal) {
@@ -2658,33 +2694,10 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
Q.IIQ.hasNoUnsignedWrap(BO));
}
case Instruction::Mul: {
- // If X and Y are non-zero then so is X * Y as long as the multiplication
- // does not overflow.
const OverflowingBinaryOperator *BO = cast<OverflowingBinaryOperator>(I);
- if (Q.IIQ.hasNoSignedWrap(BO) || Q.IIQ.hasNoUnsignedWrap(BO))
- return isKnownNonZero(I->getOperand(0), DemandedElts, Depth, Q) &&
- isKnownNonZero(I->getOperand(1), DemandedElts, Depth, Q);
-
- // If either X or Y is odd, then if the other is non-zero the result can't
- // be zero.
- KnownBits XKnown =
- computeKnownBits(I->getOperand(0), DemandedElts, Depth, Q);
- if (XKnown.One[0])
- return isKnownNonZero(I->getOperand(1), DemandedElts, Depth, Q);
-
- KnownBits YKnown =
- computeKnownBits(I->getOperand(1), DemandedElts, Depth, Q);
- if (YKnown.One[0])
- return XKnown.isNonZero() ||
- isKnownNonZero(I->getOperand(0), DemandedElts, Depth, Q);
-
- // If there exists any subset of X (sX) and subset of Y (sY) s.t sX * sY is
- // non-zero, then X * Y is non-zero. We can find sX and sY by just taking
- // the lowest known One of X and Y. If they are non-zero, the result
- // must be non-zero. We can check if LSB(X) * LSB(Y) != 0 by doing
- // X.CountLeadingZeros + Y.CountLeadingZeros < BitWidth.
- return (XKnown.countMaxTrailingZeros() + YKnown.countMaxTrailingZeros()) <
- BitWidth;
+ return isNonZeroMul(DemandedElts, Depth, Q, BitWidth, I->getOperand(0),
+ I->getOperand(1), Q.IIQ.hasNoSignedWrap(BO),
+ Q.IIQ.hasNoUnsignedWrap(BO));
}
case Instruction::Select: {
// (C ? X : Y) != 0 if X != 0 and Y != 0.
@@ -2750,6 +2763,29 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
return isKnownNonZero(U.get(), DemandedElts, NewDepth, RecQ);
});
}
+ case Instruction::InsertElement: {
+ if (isa<ScalableVectorType>(I->getType()))
+ break;
+
+ const Value *Vec = I->getOperand(0);
+ const Value *Elt = I->getOperand(1);
+ auto *CIdx = dyn_cast<ConstantInt>(I->getOperand(2));
+
+ unsigned NumElts = DemandedElts.getBitWidth();
+ APInt DemandedVecElts = DemandedElts;
+ bool SkipElt = false;
+ // If we know the index we are inserting too, clear it from Vec check.
+ if (CIdx && CIdx->getValue().ult(NumElts)) {
+ DemandedVecElts.clearBit(CIdx->getZExtValue());
+ SkipElt = !DemandedElts[CIdx->getZExtValue()];
+ }
+
+ // Result is zero if Elt is non-zero and rest of the demanded elts in Vec
+ // are non-zero.
+ return (SkipElt || isKnownNonZero(Elt, Depth, Q)) &&
+ (DemandedVecElts.isZero() ||
+ isKnownNonZero(Vec, DemandedVecElts, Depth, Q));
+ }
case Instruction::ExtractElement:
if (const auto *EEI = dyn_cast<ExtractElementInst>(I)) {
const Value *Vec = EEI->getVectorOperand();
@@ -2764,6 +2800,21 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
}
}
break;
+ case Instruction::ShuffleVector: {
+ auto *Shuf = dyn_cast<ShuffleVectorInst>(I);
+ if (!Shuf)
+ break;
+ APInt DemandedLHS, DemandedRHS;
+ // For undef elements, we don't know anything about the common state of
+ // the shuffle result.
+ if (!getShuffleDemandedElts(Shuf, DemandedElts, DemandedLHS, DemandedRHS))
+ break;
+ // If demanded elements for both vecs are non-zero, the shuffle is non-zero.
+ return (DemandedRHS.isZero() ||
+ isKnownNonZero(Shuf->getOperand(1), DemandedRHS, Depth, Q)) &&
+ (DemandedLHS.isZero() ||
+ isKnownNonZero(Shuf->getOperand(0), DemandedLHS, Depth, Q));
+ }
case Instruction::Freeze:
return isKnownNonZero(I->getOperand(0), Depth, Q) &&
isGuaranteedNotToBePoison(I->getOperand(0), Q.AC, Q.CxtI, Q.DT,
@@ -2785,6 +2836,29 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
// handled in isKnownNonZero.
return false;
}
+ case Instruction::ExtractValue: {
+ const WithOverflowInst *WO;
+ if (match(I, m_ExtractValue<0>(m_WithOverflowInst(WO)))) {
+ switch (WO->getBinaryOp()) {
+ default:
+ break;
+ case Instruction::Add:
+ return isNonZeroAdd(DemandedElts, Depth, Q, BitWidth,
+ WO->getArgOperand(0), WO->getArgOperand(1),
+ /*NSW=*/false,
+ /*NUW=*/false);
+ case Instruction::Sub:
+ return isNonZeroSub(DemandedElts, Depth, Q, BitWidth,
+ WO->getArgOperand(0), WO->getArgOperand(1));
+ case Instruction::Mul:
+ return isNonZeroMul(DemandedElts, Depth, Q, BitWidth,
+ WO->getArgOperand(0), WO->getArgOperand(1),
+ /*NSW=*/false, /*NUW=*/false);
+ break;
+ }
+ }
+ break;
+ }
case Instruction::Call:
case Instruction::Invoke: {
const auto *Call = cast<CallBase>(I);
@@ -2824,27 +2898,54 @@ static bool isKnownNonZeroFromOperator(const Operator *I,
return isNonZeroAdd(DemandedElts, Depth, Q, BitWidth,
II->getArgOperand(0), II->getArgOperand(1),
/*NSW=*/true, /* NUW=*/false);
+ // umin/smin/smax/smin of all non-zero elements is always non-zero.
+ case Intrinsic::vector_reduce_umax:
+ case Intrinsic::vector_reduce_umin:
+ case Intrinsic::vector_reduce_smax:
+ case Intrinsic::vector_reduce_smin:
+ return isKnownNonZero(II->getArgOperand(0), Depth, Q);
case Intrinsic::umax:
case Intrinsic::uadd_sat:
return isKnownNonZero(II->getArgOperand(1), DemandedElts, Depth, Q) ||
isKnownNonZero(II->getArgOperand(0), DemandedElts, Depth, Q);
- case Intrinsic::smin:
case Intrinsic::smax: {
- auto KnownOpImpliesNonZero = [&](const KnownBits &K) {
- return II->getIntrinsicID() == Intrinsic::smin
- ? K.isNegative()
- : K.isStrictlyPositive();
+ // If either arg is strictly positive the result is non-zero. Otherwise
+ // the result is non-zero if both ops are non-zero.
+ auto IsNonZero = [&](Value *Op, std::optional<bool> &OpNonZero,
+ const KnownBits &OpKnown) {
+ if (!OpNonZero.has_value())
+ OpNonZero = OpKnown.isNonZero() ||
+ isKnownNonZero(Op, DemandedElts, Depth, Q);
+ return *OpNonZero;
};
- KnownBits XKnown =
+ // Avoid re-computing isKnownNonZero.
+ std::optional<bool> Op0NonZero, Op1NonZero;
+ KnownBits Op1Known =
+ computeKnownBits(II->getArgOperand(1), DemandedElts, Depth, Q);
+ if (Op1Known.isNonNegative() &&
+ IsNonZero(II->getArgOperand(1), Op1NonZero, Op1Known))
+ return true;
+ KnownBits Op0Known =
computeKnownBits(II->getArgOperand(0), DemandedElts, Depth, Q);
- if (KnownOpImpliesNonZero(XKnown))
+ if (Op0Known.isNonNegative() &&
+ IsNonZero(II->getArgOperand(0), Op0NonZero, Op0Known))
return true;
- KnownBits YKnown =
+ return IsNonZero(II->getArgOperand(1), Op1NonZero, Op1Known) &&
+ IsNonZero(II->getArgOperand(0), Op0NonZero, Op0Known);
+ }
+ case Intrinsic::smin: {
+ // If either arg is negative the result is non-zero. Otherwise
+ // the result is non-zero if both ops are non-zero.
+ KnownBits Op1Known =
computeKnownBits(II->getArgOperand(1), DemandedElts, Depth, Q);
- if (KnownOpImpliesNonZero(YKnown))
+ if (Op1Known.isNegative())
+ return true;
+ KnownBits Op0Known =
+ computeKnownBits(II->getArgOperand(0), DemandedElts, Depth, Q);
+ if (Op0Known.isNegative())
return true;
- if (XKnown.isNonZero() && YKnown.isNonZero())
+ if (Op1Known.isNonZero() && Op0Known.isNonZero())
return true;
}
[[fallthrough]];
@@ -3005,7 +3106,20 @@ getInvertibleOperands(const Operator *Op1,
switch (Op1->getOpcode()) {
default:
break;
- case Instruction::Add:
+ case Instruction::Or:
+ if (!cast<PossiblyDisjointInst>(Op1)->isDisjoint() ||
+ !cast<PossiblyDisjointInst>(Op2)->isDisjoint())
+ break;
+ [[fallthrough]];
+ case Instruction::Xor:
+ case Instruction::Add: {
+ Value *Other;
+ if (match(Op2, m_c_BinOp(m_Specific(Op1->getOperand(0)), m_Value(Other))))
+ return std::make_pair(Op1->getOperand(1), Other);
+ if (match(Op2, m_c_BinOp(m_Specific(Op1->getOperand(1)), m_Value(Other))))
+ return std::make_pair(Op1->getOperand(0), Other);
+ break;
+ }
case Instruction::Sub:
if (Op1->getOperand(0) == Op2->getOperand(0))
return getOperands(1);
@@ -3093,20 +3207,33 @@ getInvertibleOperands(const Operator *Op1,
return std::nullopt;
}
-/// Return true if V2 == V1 + X, where X is known non-zero.
-static bool isAddOfNonZero(const Value *V1, const Value *V2, unsigned Depth,
- const SimplifyQuery &Q) {
+/// Return true if V1 == (binop V2, X), where X is known non-zero.
+/// Only handle a small subset of binops where (binop V2, X) with non-zero X
+/// implies V2 != V1.
+static bool isModifyingBinopOfNonZero(const Value *V1, const Value *V2,
+ unsigned Depth, const SimplifyQuery &Q) {
const BinaryOperator *BO = dyn_cast<BinaryOperator>(V1);
- if (!BO || BO->getOpcode() != Instruction::Add)
+ if (!BO)
return false;
- Value *Op = nullptr;
- if (V2 == BO->getOperand(0))
- Op = BO->getOperand(1);
- else if (V2 == BO->getOperand(1))
- Op = BO->getOperand(0);
- else
- return false;
- return isKnownNonZero(Op, Depth + 1, Q);
+ switch (BO->getOpcode()) {
+ default:
+ break;
+ case Instruction::Or:
+ if (!cast<PossiblyDisjointInst>(V1)->isDisjoint())
+ break;
+ [[fallthrough]];
+ case Instruction::Xor:
+ case Instruction::Add:
+ Value *Op = nullptr;
+ if (V2 == BO->getOperand(0))
+ Op = BO->getOperand(1);
+ else if (V2 == BO->getOperand(1))
+ Op = BO->getOperand(0);
+ else
+ return false;
+ return isKnownNonZero(Op, Depth + 1, Q);
+ }
+ return false;
}
/// Return true if V2 == V1 * C, where V1 is known non-zero, C is not 0/1 and
@@ -3266,7 +3393,8 @@ static bool isKnownNonEqual(const Value *V1, const Value *V2, unsigned Depth,
};
}
- if (isAddOfNonZero(V1, V2, Depth, Q) || isAddOfNonZero(V2, V1, Depth, Q))
+ if (isModifyingBinopOfNonZero(V1, V2, Depth, Q) ||
+ isModifyingBinopOfNonZero(V2, V1, Depth, Q))
return true;
if (isNonEqualMul(V1, V2, Depth, Q) || isNonEqualMul(V2, V1, Depth, Q))
diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
index 4ba27157ec1c..3f69f7ad5447 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGBuilder.cpp
@@ -3882,7 +3882,11 @@ void SelectionDAGBuilder::visitUIToFP(const User &I) {
SDValue N = getValue(I.getOperand(0));
EVT DestVT = DAG.getTargetLoweringInfo().getValueType(DAG.getDataLayout(),
I.getType());
- setValue(&I, DAG.getNode(ISD::UINT_TO_FP, getCurSDLoc(), DestVT, N));
+ SDNodeFlags Flags;
+ if (auto *PNI = dyn_cast<PossiblyNonNegInst>(&I))
+ Flags.setNonNeg(PNI->hasNonNeg());
+
+ setValue(&I, DAG.getNode(ISD::UINT_TO_FP, getCurSDLoc(), DestVT, N, Flags));
}
void SelectionDAGBuilder::visitSIToFP(const User &I) {
diff --git a/llvm/lib/Support/raw_socket_stream.cpp b/llvm/lib/Support/raw_socket_stream.cpp
index afb0ed11b2c2..1dcf6352f2cc 100644
--- a/llvm/lib/Support/raw_socket_stream.cpp
+++ b/llvm/lib/Support/raw_socket_stream.cpp
@@ -14,8 +14,14 @@
#include "llvm/Support/raw_socket_stream.h"
#include "llvm/Config/config.h"
#include "llvm/Support/Error.h"
+#include "llvm/Support/FileSystem.h"
+
+#include <atomic>
+#include <fcntl.h>
+#include <thread>
#ifndef _WIN32
+#include <poll.h>
#include <sys/socket.h>
#include <sys/un.h>
#else
@@ -45,7 +51,6 @@ WSABalancer::WSABalancer() {
}
WSABalancer::~WSABalancer() { WSACleanup(); }
-
#endif // _WIN32
static std::error_code getLastSocketErrorCode() {
@@ -56,104 +61,231 @@ static std::error_code getLastSocketErrorCode() {
#endif
}
-ListeningSocket::ListeningSocket(int SocketFD, StringRef SocketPath)
- : FD(SocketFD), SocketPath(SocketPath) {}
+static sockaddr_un setSocketAddr(StringRef SocketPath) {
+ struct sockaddr_un Addr;
+ memset(&Addr, 0, sizeof(Addr));
+ Addr.sun_family = AF_UNIX;
+ strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+ return Addr;
+}
+
+static Expected<int> getSocketFD(StringRef SocketPath) {
+#ifdef _WIN32
+ SOCKET Socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (Socket == INVALID_SOCKET) {
+#else
+ int Socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (Socket == -1) {
+#endif // _WIN32
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Create socket failed");
+ }
+
+ struct sockaddr_un Addr = setSocketAddr(SocketPath);
+ if (::connect(Socket, (struct sockaddr *)&Addr, sizeof(Addr)) == -1)
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "Connect socket failed");
+
+#ifdef _WIN32
+ return _open_osfhandle(Socket, 0);
+#else
+ return Socket;
+#endif // _WIN32
+}
+
+ListeningSocket::ListeningSocket(int SocketFD, StringRef SocketPath,
+ int PipeFD[2])
+ : FD(SocketFD), SocketPath(SocketPath), PipeFD{PipeFD[0], PipeFD[1]} {}
ListeningSocket::ListeningSocket(ListeningSocket &&LS)
- : FD(LS.FD), SocketPath(LS.SocketPath) {
+ : FD(LS.FD.load()), SocketPath(LS.SocketPath),
+ PipeFD{LS.PipeFD[0], LS.PipeFD[1]} {
+
LS.FD = -1;
+ LS.SocketPath.clear();
+ LS.PipeFD[0] = -1;
+ LS.PipeFD[1] = -1;
}
Expected<ListeningSocket> ListeningSocket::createUnix(StringRef SocketPath,
int MaxBacklog) {
+ // Handle instances where the target socket address already exists and
+ // differentiate between a preexisting file with and without a bound socket
+ //
+ // ::bind will return std::errc:address_in_use if a file at the socket address
+ // already exists (e.g., the file was not properly unlinked due to a crash)
+ // even if another socket has not yet binded to that address
+ if (llvm::sys::fs::exists(SocketPath)) {
+ Expected<int> MaybeFD = getSocketFD(SocketPath);
+ if (!MaybeFD) {
+
+ // Regardless of the error, notify the caller that a file already exists
+ // at the desired socket address and that there is no bound socket at that
+ // address. The file must be removed before ::bind can use the address
+ consumeError(MaybeFD.takeError());
+ return llvm::make_error<StringError>(
+ std::make_error_code(std::errc::file_exists),
+ "Socket address unavailable");
+ }
+ ::close(std::move(*MaybeFD));
+
+ // Notify caller that the provided socket address already has a bound socket
+ return llvm::make_error<StringError>(
+ std::make_error_code(std::errc::address_in_use),
+ "Socket address unavailable");
+ }
+
#ifdef _WIN32
WSABalancer _;
- SOCKET MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (MaybeWinsocket == INVALID_SOCKET) {
+ SOCKET Socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (Socket == INVALID_SOCKET)
#else
- int MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (MaybeWinsocket == -1) {
+ int Socket = socket(AF_UNIX, SOCK_STREAM, 0);
+ if (Socket == -1)
#endif
return llvm::make_error<StringError>(getLastSocketErrorCode(),
"socket create failed");
- }
- struct sockaddr_un Addr;
- memset(&Addr, 0, sizeof(Addr));
- Addr.sun_family = AF_UNIX;
- strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
-
- if (bind(MaybeWinsocket, (struct sockaddr *)&Addr, sizeof(Addr)) == -1) {
- std::error_code Err = getLastSocketErrorCode();
- if (Err == std::errc::address_in_use)
- ::close(MaybeWinsocket);
- return llvm::make_error<StringError>(Err, "Bind error");
+ struct sockaddr_un Addr = setSocketAddr(SocketPath);
+ if (::bind(Socket, (struct sockaddr *)&Addr, sizeof(Addr)) == -1) {
+ // Grab error code from call to ::bind before calling ::close
+ std::error_code EC = getLastSocketErrorCode();
+ ::close(Socket);
+ return llvm::make_error<StringError>(EC, "Bind error");
}
- if (listen(MaybeWinsocket, MaxBacklog) == -1) {
+
+ // Mark socket as passive so incoming connections can be accepted
+ if (::listen(Socket, MaxBacklog) == -1)
return llvm::make_error<StringError>(getLastSocketErrorCode(),
"Listen error");
- }
- int UnixSocket;
+
+ int PipeFD[2];
#ifdef _WIN32
- UnixSocket = _open_osfhandle(MaybeWinsocket, 0);
+ // Reserve 1 byte for the pipe and use default textmode
+ if (::_pipe(PipeFD, 1, 0) == -1)
#else
- UnixSocket = MaybeWinsocket;
+ if (::pipe(PipeFD) == -1)
+#endif // _WIN32
+ return llvm::make_error<StringError>(getLastSocketErrorCode(),
+ "pipe failed");
+
+#ifdef _WIN32
+ return ListeningSocket{_open_osfhandle(Socket, 0), SocketPath, PipeFD};
+#else
+ return ListeningSocket{Socket, SocketPath, PipeFD};
#endif // _WIN32
- return ListeningSocket{UnixSocket, SocketPath};
}
-Expected<std::unique_ptr<raw_socket_stream>> ListeningSocket::accept() {
- int AcceptFD;
+Expected<std::unique_ptr<raw_socket_stream>>
+ListeningSocket::accept(std::chrono::milliseconds Timeout) {
+
+ struct pollfd FDs[2];
+ FDs[0].events = POLLIN;
#ifdef _WIN32
SOCKET WinServerSock = _get_osfhandle(FD);
+ FDs[0].fd = WinServerSock;
+#else
+ FDs[0].fd = FD;
+#endif
+ FDs[1].events = POLLIN;
+ FDs[1].fd = PipeFD[0];
+
+ // Keep track of how much time has passed in case poll is interupted by a
+ // signal and needs to be recalled
+ int RemainingTime = Timeout.count();
+ std::chrono::milliseconds ElapsedTime = std::chrono::milliseconds(0);
+ int PollStatus = -1;
+
+ while (PollStatus == -1 && (Timeout.count() == -1 || ElapsedTime < Timeout)) {
+ if (Timeout.count() != -1)
+ RemainingTime -= ElapsedTime.count();
+
+ auto Start = std::chrono::steady_clock::now();
+#ifdef _WIN32
+ PollStatus = WSAPoll(FDs, 2, RemainingTime);
+ if (PollStatus == SOCKET_ERROR) {
+#else
+ PollStatus = ::poll(FDs, 2, RemainingTime);
+ if (PollStatus == -1) {
+#endif
+ // Ignore error if caused by interupting signal
+ std::error_code PollErrCode = getLastSocketErrorCode();
+ if (PollErrCode != std::errc::interrupted)
+ return llvm::make_error<StringError>(PollErrCode, "FD poll failed");
+ }
+
+ if (PollStatus == 0)
+ return llvm::make_error<StringError>(
+ std::make_error_code(std::errc::timed_out),
+ "No client requests within timeout window");
+
+ if (FDs[0].revents & POLLNVAL)
+ return llvm::make_error<StringError>(
+ std::make_error_code(std::errc::bad_file_descriptor),
+ "File descriptor closed by another thread");
+
+ if (FDs[1].revents & POLLIN)
+ return llvm::make_error<StringError>(
+ std::make_error_code(std::errc::operation_canceled),
+ "Accept canceled");
+
+ auto Stop = std::chrono::steady_clock::now();
+ ElapsedTime +=
+ std::chrono::duration_cast<std::chrono::milliseconds>(Stop - Start);
+ }
+
+ int AcceptFD;
+#ifdef _WIN32
SOCKET WinAcceptSock = ::accept(WinServerSock, NULL, NULL);
AcceptFD = _open_osfhandle(WinAcceptSock, 0);
#else
AcceptFD = ::accept(FD, NULL, NULL);
-#endif //_WIN32
+#endif
+
if (AcceptFD == -1)
return llvm::make_error<StringError>(getLastSocketErrorCode(),
- "Accept failed");
+ "Socket accept failed");
return std::make_unique<raw_socket_stream>(AcceptFD);
}
-ListeningSocket::~ListeningSocket() {
- if (FD == -1)
+void ListeningSocket::shutdown() {
+ int ObservedFD = FD.load();
+
+ if (ObservedFD == -1)
return;
- ::close(FD);
- unlink(SocketPath.c_str());
-}
-static Expected<int> GetSocketFD(StringRef SocketPath) {
-#ifdef _WIN32
- SOCKET MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (MaybeWinsocket == INVALID_SOCKET) {
-#else
- int MaybeWinsocket = socket(AF_UNIX, SOCK_STREAM, 0);
- if (MaybeWinsocket == -1) {
-#endif // _WIN32
- return llvm::make_error<StringError>(getLastSocketErrorCode(),
- "Create socket failed");
- }
+ // If FD equals ObservedFD set FD to -1; If FD doesn't equal ObservedFD then
+ // another thread is responsible for shutdown so return
+ if (!FD.compare_exchange_strong(ObservedFD, -1))
+ return;
- struct sockaddr_un Addr;
- memset(&Addr, 0, sizeof(Addr));
- Addr.sun_family = AF_UNIX;
- strncpy(Addr.sun_path, SocketPath.str().c_str(), sizeof(Addr.sun_path) - 1);
+ ::close(ObservedFD);
+ ::unlink(SocketPath.c_str());
- int status = connect(MaybeWinsocket, (struct sockaddr *)&Addr, sizeof(Addr));
- if (status == -1) {
- return llvm::make_error<StringError>(getLastSocketErrorCode(),
- "Connect socket failed");
- }
-#ifdef _WIN32
- return _open_osfhandle(MaybeWinsocket, 0);
-#else
- return MaybeWinsocket;
-#endif // _WIN32
+ // Ensure ::poll returns if shutdown is called by a seperate thread
+ char Byte = 'A';
+ ::write(PipeFD[1], &Byte, 1);
}
+ListeningSocket::~ListeningSocket() {
+ shutdown();
+
+ // Close the pipe's FDs in the destructor instead of within
+ // ListeningSocket::shutdown to avoid unnecessary synchronization issues that
+ // would occur as PipeFD's values would have to be changed to -1
+ //
+ // The move constructor sets PipeFD to -1
+ if (PipeFD[0] != -1)
+ ::close(PipeFD[0]);
+ if (PipeFD[1] != -1)
+ ::close(PipeFD[1]);
+}
+
+//===----------------------------------------------------------------------===//
+// raw_socket_stream
+//===----------------------------------------------------------------------===//
+
raw_socket_stream::raw_socket_stream(int SocketFD)
: raw_fd_stream(SocketFD, true) {}
@@ -162,11 +294,10 @@ raw_socket_stream::createConnectedUnix(StringRef SocketPath) {
#ifdef _WIN32
WSABalancer _;
#endif // _WIN32
- Expected<int> FD = GetSocketFD(SocketPath);
+ Expected<int> FD = getSocketFD(SocketPath);
if (!FD)
return FD.takeError();
return std::make_unique<raw_socket_stream>(*FD);
}
raw_socket_stream::~raw_socket_stream() {}
-
diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
index 819e8ccd5c33..744b2cdef504 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -17930,16 +17930,14 @@ static SDValue tryCombineToBSL(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
EVT VT = N->getValueType(0);
SelectionDAG &DAG = DCI.DAG;
SDLoc DL(N);
+ const auto &Subtarget = DAG.getSubtarget<AArch64Subtarget>();
if (!VT.isVector())
return SDValue();
- // The combining code currently only works for NEON vectors. In particular,
- // it does not work for SVE when dealing with vectors wider than 128 bits.
- // It also doesn't work for streaming mode because it causes generating
- // bsl instructions that are invalid in streaming mode.
- if (TLI.useSVEForFixedLengthVectorVT(
- VT, !DAG.getSubtarget<AArch64Subtarget>().isNeonAvailable()))
+ // The combining code works for NEON, SVE2 and SME.
+ if (TLI.useSVEForFixedLengthVectorVT(VT, !Subtarget.isNeonAvailable()) ||
+ (VT.isScalableVector() && !Subtarget.hasSVE2()))
return SDValue();
SDValue N0 = N->getOperand(0);
@@ -17994,6 +17992,14 @@ static SDValue tryCombineToBSL(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
uint64_t BitMask = Bits == 64 ? -1ULL : ((1ULL << Bits) - 1);
for (int i = 1; i >= 0; --i)
for (int j = 1; j >= 0; --j) {
+ APInt Val1, Val2;
+
+ if (ISD::isConstantSplatVector(N0->getOperand(i).getNode(), Val1) &&
+ ISD::isConstantSplatVector(N1->getOperand(j).getNode(), Val2) &&
+ (BitMask & ~Val1.getZExtValue()) == Val2.getZExtValue()) {
+ return DAG.getNode(AArch64ISD::BSP, DL, VT, N0->getOperand(i),
+ N0->getOperand(1 - i), N1->getOperand(1 - j));
+ }
BuildVectorSDNode *BVN0 = dyn_cast<BuildVectorSDNode>(N0->getOperand(i));
BuildVectorSDNode *BVN1 = dyn_cast<BuildVectorSDNode>(N1->getOperand(j));
if (!BVN0 || !BVN1)
@@ -18009,9 +18015,8 @@ static SDValue tryCombineToBSL(SDNode *N, TargetLowering::DAGCombinerInfo &DCI,
break;
}
}
-
if (FoundMatch)
- return DAG.getNode(AArch64ISD::BSP, DL, VT, SDValue(BVN0, 0),
+ return DAG.getNode(AArch64ISD::BSP, DL, VT, N0->getOperand(i),
N0->getOperand(1 - i), N1->getOperand(1 - j));
}
diff --git a/llvm/lib/Target/AMDGPU/AMDGPU.td b/llvm/lib/Target/AMDGPU/AMDGPU.td
index 37dcfef3b2a3..9b0955015999 100644
--- a/llvm/lib/Target/AMDGPU/AMDGPU.td
+++ b/llvm/lib/Target/AMDGPU/AMDGPU.td
@@ -168,6 +168,10 @@ def FeatureCuMode : SubtargetFeature<"cumode",
"Enable CU wavefront execution mode"
>;
+def FeaturePreciseMemory
+ : SubtargetFeature<"precise-memory", "EnablePreciseMemory",
+ "true", "Enable precise memory mode">;
+
def FeatureSGPRInitBug : SubtargetFeature<"sgpr-init-bug",
"SGPRInitBug",
"true",
diff --git a/llvm/lib/Target/AMDGPU/GCNSubtarget.h b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
index e24a18a2842f..04ff53a6647b 100644
--- a/llvm/lib/Target/AMDGPU/GCNSubtarget.h
+++ b/llvm/lib/Target/AMDGPU/GCNSubtarget.h
@@ -87,6 +87,7 @@ protected:
bool EnableTgSplit = false;
bool EnableCuMode = false;
bool TrapHandler = false;
+ bool EnablePreciseMemory = false;
// Used as options.
bool EnableLoadStoreOpt = false;
@@ -599,6 +600,8 @@ public:
return EnableCuMode;
}
+ bool isPreciseMemoryEnabled() const { return EnablePreciseMemory; }
+
bool hasFlatAddressSpace() const {
return FlatAddressSpace;
}
diff --git a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
index bb499c5c8c57..556ec3e231ff 100644
--- a/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
+++ b/llvm/lib/Target/AMDGPU/SIInsertWaitcnts.cpp
@@ -2305,6 +2305,14 @@ bool SIInsertWaitcnts::insertWaitcntInBlock(MachineFunction &MF,
}
#endif
+ if (ST->isPreciseMemoryEnabled() && Inst.mayLoadOrStore()) {
+ AMDGPU::Waitcnt Wait = WCG->getAllZeroWaitcnt(
+ Inst.mayStore() && !SIInstrInfo::isAtomicRet(Inst));
+ ScoreBrackets.simplifyWaitcnt(Wait);
+ Modified |= generateWaitcnt(Wait, std::next(Inst.getIterator()), Block,
+ ScoreBrackets, /*OldWaitcntInstr=*/nullptr);
+ }
+
LLVM_DEBUG({
Inst.print(dbgs());
ScoreBrackets.dump();
diff --git a/llvm/lib/Target/AMDGPU/SIInstructions.td b/llvm/lib/Target/AMDGPU/SIInstructions.td
index 04f3a2f57605..d6d49889656b 100644
--- a/llvm/lib/Target/AMDGPU/SIInstructions.td
+++ b/llvm/lib/Target/AMDGPU/SIInstructions.td
@@ -2087,7 +2087,7 @@ def : GCNPat <
def : GCNPat <
(DivergentUnaryFrag<fneg> (v2f32 VReg_64:$src)),
(V_PK_ADD_F32 11 /* OP_SEL_1 | NEG_LO | HEG_HI */, VReg_64:$src,
- 11 /* OP_SEL_1 | NEG_LO | HEG_HI */, 0,
+ 11 /* OP_SEL_1 | NEG_LO | HEG_HI */, (i64 0),
0, 0, 0, 0, 0)
> {
let SubtargetPredicate = HasPackedFP32Ops;
@@ -2999,7 +2999,7 @@ def : GCNPat<
let SubtargetPredicate = HasPackedFP32Ops in {
def : GCNPat<
(fcanonicalize (v2f32 (VOP3PMods v2f32:$src, i32:$src_mods))),
- (V_PK_MUL_F32 0, CONST.FP32_ONE, $src_mods, $src)
+ (V_PK_MUL_F32 0, (i64 CONST.FP32_ONE), $src_mods, $src)
>;
}
@@ -3007,7 +3007,7 @@ def : GCNPat<
let SubtargetPredicate = isNotGFX12Plus in {
def : GCNPat<
(fcanonicalize (f64 (VOP3Mods f64:$src, i32:$src_mods))),
- (V_MUL_F64_e64 0, CONST.FP64_ONE, $src_mods, $src)
+ (V_MUL_F64_e64 0, (i64 CONST.FP64_ONE), $src_mods, $src)
>;
}
} // End AddedComplexity = -5
@@ -3369,7 +3369,7 @@ def : GCNPat <
SRCMODS.NONE,
(V_FRACT_F64_e64 $mods, $x),
SRCMODS.NONE,
- (V_MOV_B64_PSEUDO 0x3fefffffffffffff)),
+ (V_MOV_B64_PSEUDO (i64 0x3fefffffffffffff))),
$x,
(V_CMP_CLASS_F64_e64 SRCMODS.NONE, $x, (i32 3 /*NaN*/))))
>;
diff --git a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
index cb6591bf6244..01ed565bb756 100644
--- a/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
+++ b/llvm/lib/Target/AMDGPU/SIRegisterInfo.td
@@ -1046,7 +1046,7 @@ def VS_32_Lo128 : SIRegisterClass<"AMDGPU", [i32, f32, i16, f16, bf16, v2i16, v2
let HasSGPR = 1;
}
-def VS_64 : SIRegisterClass<"AMDGPU", [i64, f64, v2f32], 32, (add VReg_64, SReg_64)> {
+def VS_64 : SIRegisterClass<"AMDGPU", VReg_64.RegTypes, 32, (add VReg_64, SReg_64)> {
let isAllocatable = 0;
let HasVGPR = 1;
let HasSGPR = 1;
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
index dc2d61a6e474..2993726d2b64 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.cpp
@@ -206,22 +206,19 @@ void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
if (StackSize == 0 && !MFI.adjustsStack())
return;
- uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF, true);
- uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
+ uint64_t FirstSPAdjustAmount = getFirstSPAdjustAmount(MF);
// Split the SP adjustment to reduce the offsets of callee saved spill.
if (FirstSPAdjustAmount)
StackSize = FirstSPAdjustAmount;
// Adjust stack.
adjustReg(MBB, MBBI, DL, SPReg, SPReg, -StackSize, MachineInstr::FrameSetup);
- if (FirstSPAdjustAmount != 2048 || SecondSPAdjustAmount == 0) {
- // Emit ".cfi_def_cfa_offset StackSize".
- unsigned CFIIndex =
- MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
- BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
- .addCFIIndex(CFIIndex)
- .setMIFlag(MachineInstr::FrameSetup);
- }
+ // Emit ".cfi_def_cfa_offset StackSize".
+ unsigned CFIIndex =
+ MF.addFrameInst(MCCFIInstruction::cfiDefCfaOffset(nullptr, StackSize));
+ BuildMI(MBB, MBBI, DL, TII->get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex)
+ .setMIFlag(MachineInstr::FrameSetup);
const auto &CSI = MFI.getCalleeSavedInfo();
@@ -258,25 +255,14 @@ void LoongArchFrameLowering::emitPrologue(MachineFunction &MF,
}
// Emit the second SP adjustment after saving callee saved registers.
- if (FirstSPAdjustAmount && SecondSPAdjustAmount) {
- if (hasFP(MF)) {
- assert(SecondSPAdjustAmount > 0 &&
- "SecondSPAdjustAmount should be greater than zero");
- adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
- MachineInstr::FrameSetup);
- } else {
- // FIXME: RegScavenger will place the spill instruction before the
- // prologue if a VReg is created in the prologue. This will pollute the
- // caller's stack data. Therefore, until there is better way, we just use
- // the `addi.w/d` instruction for stack adjustment to ensure that VReg
- // will not be created.
- for (int Val = SecondSPAdjustAmount; Val > 0; Val -= 2048)
- BuildMI(MBB, MBBI, DL,
- TII->get(IsLA64 ? LoongArch::ADDI_D : LoongArch::ADDI_W), SPReg)
- .addReg(SPReg)
- .addImm(Val < 2048 ? -Val : -2048)
- .setMIFlag(MachineInstr::FrameSetup);
+ if (FirstSPAdjustAmount) {
+ uint64_t SecondSPAdjustAmount = RealStackSize - FirstSPAdjustAmount;
+ assert(SecondSPAdjustAmount > 0 &&
+ "SecondSPAdjustAmount should be greater than zero");
+ adjustReg(MBB, MBBI, DL, SPReg, SPReg, -SecondSPAdjustAmount,
+ MachineInstr::FrameSetup);
+ if (!hasFP(MF)) {
// If we are using a frame-pointer, and thus emitted ".cfi_def_cfa fp, 0",
// don't emit an sp-based .cfi_def_cfa_offset
// Emit ".cfi_def_cfa_offset RealStackSize"
@@ -369,27 +355,20 @@ void LoongArchFrameLowering::emitEpilogue(MachineFunction &MF,
// st.d $ra, $sp, 2024
// st.d $fp, $sp, 2016
// addi.d $sp, $sp, -16
-uint64_t
-LoongArchFrameLowering::getFirstSPAdjustAmount(const MachineFunction &MF,
- bool IsPrologue) const {
+uint64_t LoongArchFrameLowering::getFirstSPAdjustAmount(
+ const MachineFunction &MF) const {
const MachineFrameInfo &MFI = MF.getFrameInfo();
const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
// Return the FirstSPAdjustAmount if the StackSize can not fit in a signed
// 12-bit and there exists a callee-saved register needing to be pushed.
- if (!isInt<12>(MFI.getStackSize())) {
+ if (!isInt<12>(MFI.getStackSize()) && (CSI.size() > 0)) {
// FirstSPAdjustAmount is chosen as (2048 - StackAlign) because 2048 will
// cause sp = sp + 2048 in the epilogue to be split into multiple
// instructions. Offsets smaller than 2048 can fit in a single load/store
// instruction, and we have to stick with the stack alignment.
// So (2048 - StackAlign) will satisfy the stack alignment.
- //
- // FIXME: This place may seem odd. When using multiple ADDI instructions to
- // adjust the stack in Prologue, and there are no callee-saved registers, we
- // can take advantage of the logic of split sp ajustment to reduce code
- // changes.
- return CSI.size() > 0 ? 2048 - getStackAlign().value()
- : (IsPrologue ? 2048 : 0);
+ return 2048 - getStackAlign().value();
}
return 0;
}
diff --git a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
index 57d2565c32c0..bc2ac02c91f8 100644
--- a/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
+++ b/llvm/lib/Target/LoongArch/LoongArchFrameLowering.h
@@ -52,8 +52,7 @@ public:
bool hasFP(const MachineFunction &MF) const override;
bool hasBP(const MachineFunction &MF) const;
- uint64_t getFirstSPAdjustAmount(const MachineFunction &MF,
- bool IsPrologue = false) const;
+ uint64_t getFirstSPAdjustAmount(const MachineFunction &MF) const;
bool enableShrinkWrapping(const MachineFunction &MF) const override;
diff --git a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
index 5bf594c0b5ea..9982a73ee914 100644
--- a/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
+++ b/llvm/lib/Target/RISCV/RISCVAsmPrinter.cpp
@@ -80,7 +80,8 @@ public:
bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
const char *ExtraCode, raw_ostream &OS) override;
- void EmitToStreamer(MCStreamer &S, const MCInst &Inst);
+ // Returns whether Inst is compressed.
+ bool EmitToStreamer(MCStreamer &S, const MCInst &Inst);
bool emitPseudoExpansionLowering(MCStreamer &OutStreamer,
const MachineInstr *MI);
@@ -180,12 +181,13 @@ void RISCVAsmPrinter::LowerSTATEPOINT(MCStreamer &OutStreamer, StackMaps &SM,
SM.recordStatepoint(*MILabel, MI);
}
-void RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
+bool RISCVAsmPrinter::EmitToStreamer(MCStreamer &S, const MCInst &Inst) {
MCInst CInst;
bool Res = RISCVRVC::compress(CInst, Inst, *STI);
if (Res)
++RISCVNumInstrsCompressed;
AsmPrinter::EmitToStreamer(*OutStreamer, Res ? CInst : Inst);
+ return Res;
}
// Simple pseudo-instructions have their lowering (with expansion to real
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index 39075c81b292..71672ed7b4ae 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -1001,46 +1001,6 @@ void RISCVFrameLowering::determineCalleeSaves(MachineFunction &MF,
// Mark BP as used if function has dedicated base pointer.
if (hasBP(MF))
SavedRegs.set(RISCVABI::getBPReg());
-
- // If interrupt is enabled and there are calls in the handler,
- // unconditionally save all Caller-saved registers and
- // all FP registers, regardless whether they are used.
- MachineFrameInfo &MFI = MF.getFrameInfo();
- auto &Subtarget = MF.getSubtarget<RISCVSubtarget>();
-
- if (MF.getFunction().hasFnAttribute("interrupt") && MFI.hasCalls()) {
-
- static const MCPhysReg CSRegs[] = { RISCV::X1, /* ra */
- RISCV::X5, RISCV::X6, RISCV::X7, /* t0-t2 */
- RISCV::X10, RISCV::X11, /* a0-a1, a2-a7 */
- RISCV::X12, RISCV::X13, RISCV::X14, RISCV::X15, RISCV::X16, RISCV::X17,
- RISCV::X28, RISCV::X29, RISCV::X30, RISCV::X31 /* t3-t6 */
- };
-
- for (auto Reg : CSRegs)
- SavedRegs.set(Reg);
-
- // According to psABI, if ilp32e/lp64e ABIs are used with an ISA that
- // has any of the registers x16-x31 and f0-f31, then these registers are
- // considered temporaries, so we should also save x16-x31 here.
- if (STI.getTargetABI() == RISCVABI::ABI_ILP32E ||
- STI.getTargetABI() == RISCVABI::ABI_LP64E) {
- for (MCPhysReg Reg = RISCV::X16; Reg <= RISCV::X31; Reg++)
- SavedRegs.set(Reg);
- }
-
- if (Subtarget.hasStdExtF()) {
-
- // If interrupt is enabled, this list contains all FP registers.
- const MCPhysReg * Regs = MF.getRegInfo().getCalleeSavedRegs();
-
- for (unsigned i = 0; Regs[i]; ++i)
- if (RISCV::FPR16RegClass.contains(Regs[i]) ||
- RISCV::FPR32RegClass.contains(Regs[i]) ||
- RISCV::FPR64RegClass.contains(Regs[i]))
- SavedRegs.set(Regs[i]);
- }
- }
}
std::pair<int64_t, Align>
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 80cc41b458ca..944d8b6de895 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -4638,8 +4638,17 @@ static SDValue getWideningInterleave(SDValue EvenV, SDValue OddV,
Subtarget.getXLenVT()));
Interleaved = DAG.getNode(RISCVISD::VWSLL_VL, DL, WideContainerVT, OddV,
OffsetVec, Passthru, Mask, VL);
- Interleaved = DAG.getNode(RISCVISD::VWADDU_W_VL, DL, WideContainerVT,
- Interleaved, EvenV, Passthru, Mask, VL);
+ if (!EvenV.isUndef())
+ Interleaved = DAG.getNode(RISCVISD::VWADDU_W_VL, DL, WideContainerVT,
+ Interleaved, EvenV, Passthru, Mask, VL);
+ } else if (EvenV.isUndef()) {
+ Interleaved =
+ DAG.getNode(RISCVISD::VZEXT_VL, DL, WideContainerVT, OddV, Mask, VL);
+
+ SDValue OffsetVec =
+ DAG.getConstant(VecVT.getScalarSizeInBits(), DL, WideContainerVT);
+ Interleaved = DAG.getNode(RISCVISD::SHL_VL, DL, WideContainerVT,
+ Interleaved, OffsetVec, Passthru, Mask, VL);
} else {
// FIXME: We should freeze the odd vector here. We already handled the case
// of provably undef/poison above.
@@ -13597,7 +13606,8 @@ struct NodeExtensionHelper {
/// Check if this instance represents a splat.
bool isSplat() const {
- return OrigOperand.getOpcode() == RISCVISD::VMV_V_X_VL;
+ return OrigOperand.getOpcode() == RISCVISD::VMV_V_X_VL ||
+ OrigOperand.getOpcode() == ISD::SPLAT_VECTOR;
}
/// Get the extended opcode.
@@ -13641,6 +13651,8 @@ struct NodeExtensionHelper {
case RISCVISD::VZEXT_VL:
case RISCVISD::FP_EXTEND_VL:
return DAG.getNode(ExtOpc, DL, NarrowVT, Source, Mask, VL);
+ case ISD::SPLAT_VECTOR:
+ return DAG.getSplat(NarrowVT, DL, Source.getOperand(0));
case RISCVISD::VMV_V_X_VL:
return DAG.getNode(RISCVISD::VMV_V_X_VL, DL, NarrowVT,
DAG.getUNDEF(NarrowVT), Source.getOperand(1), VL);
@@ -13776,6 +13788,47 @@ struct NodeExtensionHelper {
/// Check if this node needs to be fully folded or extended for all users.
bool needToPromoteOtherUsers() const { return EnforceOneUse; }
+ void fillUpExtensionSupportForSplat(SDNode *Root, SelectionDAG &DAG,
+ const RISCVSubtarget &Subtarget) {
+ unsigned Opc = OrigOperand.getOpcode();
+ MVT VT = OrigOperand.getSimpleValueType();
+
+ assert((Opc == ISD::SPLAT_VECTOR || Opc == RISCVISD::VMV_V_X_VL) &&
+ "Unexpected Opcode");
+
+ // The pasthru must be undef for tail agnostic.
+ if (Opc == RISCVISD::VMV_V_X_VL && !OrigOperand.getOperand(0).isUndef())
+ return;
+
+ // Get the scalar value.
+ SDValue Op = Opc == ISD::SPLAT_VECTOR ? OrigOperand.getOperand(0)
+ : OrigOperand.getOperand(1);
+
+ // See if we have enough sign bits or zero bits in the scalar to use a
+ // widening opcode by splatting to smaller element size.
+ unsigned EltBits = VT.getScalarSizeInBits();
+ unsigned ScalarBits = Op.getValueSizeInBits();
+ // Make sure we're getting all element bits from the scalar register.
+ // FIXME: Support implicit sign extension of vmv.v.x?
+ if (ScalarBits < EltBits)
+ return;
+
+ unsigned NarrowSize = VT.getScalarSizeInBits() / 2;
+ // If the narrow type cannot be expressed with a legal VMV,
+ // this is not a valid candidate.
+ if (NarrowSize < 8)
+ return;
+
+ if (DAG.ComputeMaxSignificantBits(Op) <= NarrowSize)
+ SupportsSExt = true;
+
+ if (DAG.MaskedValueIsZero(Op,
+ APInt::getBitsSetFrom(ScalarBits, NarrowSize)))
+ SupportsZExt = true;
+
+ EnforceOneUse = false;
+ }
+
/// Helper method to set the various fields of this struct based on the
/// type of \p Root.
void fillUpExtensionSupport(SDNode *Root, SelectionDAG &DAG,
@@ -13814,43 +13867,10 @@ struct NodeExtensionHelper {
case RISCVISD::FP_EXTEND_VL:
SupportsFPExt = true;
break;
- case RISCVISD::VMV_V_X_VL: {
- // Historically, we didn't care about splat values not disappearing during
- // combines.
- EnforceOneUse = false;
-
- // The operand is a splat of a scalar.
-
- // The pasthru must be undef for tail agnostic.
- if (!OrigOperand.getOperand(0).isUndef())
- break;
-
- // Get the scalar value.
- SDValue Op = OrigOperand.getOperand(1);
-
- // See if we have enough sign bits or zero bits in the scalar to use a
- // widening opcode by splatting to smaller element size.
- MVT VT = Root->getSimpleValueType(0);
- unsigned EltBits = VT.getScalarSizeInBits();
- unsigned ScalarBits = Op.getValueSizeInBits();
- // Make sure we're getting all element bits from the scalar register.
- // FIXME: Support implicit sign extension of vmv.v.x?
- if (ScalarBits < EltBits)
- break;
-
- unsigned NarrowSize = VT.getScalarSizeInBits() / 2;
- // If the narrow type cannot be expressed with a legal VMV,
- // this is not a valid candidate.
- if (NarrowSize < 8)
- break;
-
- if (DAG.ComputeMaxSignificantBits(Op) <= NarrowSize)
- SupportsSExt = true;
- if (DAG.MaskedValueIsZero(Op,
- APInt::getBitsSetFrom(ScalarBits, NarrowSize)))
- SupportsZExt = true;
+ case ISD::SPLAT_VECTOR:
+ case RISCVISD::VMV_V_X_VL:
+ fillUpExtensionSupportForSplat(Root, DAG, Subtarget);
break;
- }
default:
break;
}
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index be63bc936ae8..6b75efe684d9 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -1775,6 +1775,86 @@ static bool getFPPatterns(MachineInstr &Root,
return getFPFusedMultiplyPatterns(Root, Patterns, DoRegPressureReduce);
}
+/// Utility routine that checks if \param MO is defined by an
+/// \param CombineOpc instruction in the basic block \param MBB
+static const MachineInstr *canCombine(const MachineBasicBlock &MBB,
+ const MachineOperand &MO,
+ unsigned CombineOpc) {
+ const MachineRegisterInfo &MRI = MBB.getParent()->getRegInfo();
+ const MachineInstr *MI = nullptr;
+
+ if (MO.isReg() && MO.getReg().isVirtual())
+ MI = MRI.getUniqueVRegDef(MO.getReg());
+ // And it needs to be in the trace (otherwise, it won't have a depth).
+ if (!MI || MI->getParent() != &MBB || MI->getOpcode() != CombineOpc)
+ return nullptr;
+ // Must only used by the user we combine with.
+ if (!MRI.hasOneNonDBGUse(MI->getOperand(0).getReg()))
+ return nullptr;
+
+ return MI;
+}
+
+/// Utility routine that checks if \param MO is defined by a SLLI in \param
+/// MBB that can be combined by splitting across 2 SHXADD instructions. The
+/// first SHXADD shift amount is given by \param OuterShiftAmt.
+static bool canCombineShiftIntoShXAdd(const MachineBasicBlock &MBB,
+ const MachineOperand &MO,
+ unsigned OuterShiftAmt) {
+ const MachineInstr *ShiftMI = canCombine(MBB, MO, RISCV::SLLI);
+ if (!ShiftMI)
+ return false;
+
+ unsigned InnerShiftAmt = ShiftMI->getOperand(2).getImm();
+ if (InnerShiftAmt < OuterShiftAmt || (InnerShiftAmt - OuterShiftAmt) > 3)
+ return false;
+
+ return true;
+}
+
+// Returns the shift amount from a SHXADD instruction. Returns 0 if the
+// instruction is not a SHXADD.
+static unsigned getSHXADDShiftAmount(unsigned Opc) {
+ switch (Opc) {
+ default:
+ return 0;
+ case RISCV::SH1ADD:
+ return 1;
+ case RISCV::SH2ADD:
+ return 2;
+ case RISCV::SH3ADD:
+ return 3;
+ }
+}
+
+// Look for opportunities to combine (sh3add Z, (add X, (slli Y, 5))) into
+// (sh3add (sh2add Y, Z), X).
+static bool
+getSHXADDPatterns(const MachineInstr &Root,
+ SmallVectorImpl<MachineCombinerPattern> &Patterns) {
+ unsigned ShiftAmt = getSHXADDShiftAmount(Root.getOpcode());
+ if (!ShiftAmt)
+ return false;
+
+ const MachineBasicBlock &MBB = *Root.getParent();
+
+ const MachineInstr *AddMI = canCombine(MBB, Root.getOperand(2), RISCV::ADD);
+ if (!AddMI)
+ return false;
+
+ bool Found = false;
+ if (canCombineShiftIntoShXAdd(MBB, AddMI->getOperand(1), ShiftAmt)) {
+ Patterns.push_back(MachineCombinerPattern::SHXADD_ADD_SLLI_OP1);
+ Found = true;
+ }
+ if (canCombineShiftIntoShXAdd(MBB, AddMI->getOperand(2), ShiftAmt)) {
+ Patterns.push_back(MachineCombinerPattern::SHXADD_ADD_SLLI_OP2);
+ Found = true;
+ }
+
+ return Found;
+}
+
bool RISCVInstrInfo::getMachineCombinerPatterns(
MachineInstr &Root, SmallVectorImpl<MachineCombinerPattern> &Patterns,
bool DoRegPressureReduce) const {
@@ -1782,6 +1862,9 @@ bool RISCVInstrInfo::getMachineCombinerPatterns(
if (getFPPatterns(Root, Patterns, DoRegPressureReduce))
return true;
+ if (getSHXADDPatterns(Root, Patterns))
+ return true;
+
return TargetInstrInfo::getMachineCombinerPatterns(Root, Patterns,
DoRegPressureReduce);
}
@@ -1864,6 +1947,68 @@ static void combineFPFusedMultiply(MachineInstr &Root, MachineInstr &Prev,
DelInstrs.push_back(&Root);
}
+// Combine patterns like (sh3add Z, (add X, (slli Y, 5))) to
+// (sh3add (sh2add Y, Z), X) if the shift amount can be split across two
+// shXadd instructions. The outer shXadd keeps its original opcode.
+static void
+genShXAddAddShift(MachineInstr &Root, unsigned AddOpIdx,
+ SmallVectorImpl<MachineInstr *> &InsInstrs,
+ SmallVectorImpl<MachineInstr *> &DelInstrs,
+ DenseMap<unsigned, unsigned> &InstrIdxForVirtReg) {
+ MachineFunction *MF = Root.getMF();
+ MachineRegisterInfo &MRI = MF->getRegInfo();
+ const TargetInstrInfo *TII = MF->getSubtarget().getInstrInfo();
+
+ unsigned OuterShiftAmt = getSHXADDShiftAmount(Root.getOpcode());
+ assert(OuterShiftAmt != 0 && "Unexpected opcode");
+
+ MachineInstr *AddMI = MRI.getUniqueVRegDef(Root.getOperand(2).getReg());
+ MachineInstr *ShiftMI =
+ MRI.getUniqueVRegDef(AddMI->getOperand(AddOpIdx).getReg());
+
+ unsigned InnerShiftAmt = ShiftMI->getOperand(2).getImm();
+ assert(InnerShiftAmt > OuterShiftAmt && "Unexpected shift amount");
+
+ unsigned InnerOpc;
+ switch (InnerShiftAmt - OuterShiftAmt) {
+ default:
+ llvm_unreachable("Unexpected shift amount");
+ case 0:
+ InnerOpc = RISCV::ADD;
+ break;
+ case 1:
+ InnerOpc = RISCV::SH1ADD;
+ break;
+ case 2:
+ InnerOpc = RISCV::SH2ADD;
+ break;
+ case 3:
+ InnerOpc = RISCV::SH3ADD;
+ break;
+ }
+
+ const MachineOperand &X = AddMI->getOperand(3 - AddOpIdx);
+ const MachineOperand &Y = ShiftMI->getOperand(1);
+ const MachineOperand &Z = Root.getOperand(1);
+
+ Register NewVR = MRI.createVirtualRegister(&RISCV::GPRRegClass);
+
+ auto MIB1 = BuildMI(*MF, MIMetadata(Root), TII->get(InnerOpc), NewVR)
+ .addReg(Y.getReg(), getKillRegState(Y.isKill()))
+ .addReg(Z.getReg(), getKillRegState(Z.isKill()));
+ auto MIB2 = BuildMI(*MF, MIMetadata(Root), TII->get(Root.getOpcode()),
+ Root.getOperand(0).getReg())
+ .addReg(NewVR, RegState::Kill)
+ .addReg(X.getReg(), getKillRegState(X.isKill()));
+
+ InstrIdxForVirtReg.insert(std::make_pair(NewVR, 0));
+ InsInstrs.push_back(MIB1);
+ InsInstrs.push_back(MIB2);
+ DelInstrs.push_back(ShiftMI);
+ DelInstrs.push_back(AddMI);
+ DelInstrs.push_back(&Root);
+}
+
void RISCVInstrInfo::genAlternativeCodeSequence(
MachineInstr &Root, MachineCombinerPattern Pattern,
SmallVectorImpl<MachineInstr *> &InsInstrs,
@@ -1887,6 +2032,12 @@ void RISCVInstrInfo::genAlternativeCodeSequence(
combineFPFusedMultiply(Root, Prev, Pattern, InsInstrs, DelInstrs);
return;
}
+ case MachineCombinerPattern::SHXADD_ADD_SLLI_OP1:
+ genShXAddAddShift(Root, 1, InsInstrs, DelInstrs, InstrIdxForVirtReg);
+ return;
+ case MachineCombinerPattern::SHXADD_ADD_SLLI_OP2:
+ genShXAddAddShift(Root, 2, InsInstrs, DelInstrs, InstrIdxForVirtReg);
+ return;
}
}
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 46e79272d60e..84af6eec40ee 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -210,8 +210,7 @@ void RISCVRegisterInfo::adjustReg(MachineBasicBlock &MBB,
unsigned Opc = NumOfVReg == 2 ? RISCV::SH1ADD :
(NumOfVReg == 4 ? RISCV::SH2ADD : RISCV::SH3ADD);
BuildMI(MBB, II, DL, TII->get(Opc), DestReg)
- .addReg(ScratchReg, RegState::Kill)
- .addReg(SrcReg, getKillRegState(KillSrcReg))
+ .addReg(ScratchReg, RegState::Kill).addReg(SrcReg)
.setMIFlag(Flag);
} else {
TII->mulImm(MF, MBB, II, DL, ScratchReg, NumOfVReg, Flag);
diff --git a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
index 55637b8ea47f..bc9756c5e6dd 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetTransformInfo.cpp
@@ -864,6 +864,21 @@ RISCVTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA,
}
break;
}
+ case Intrinsic::get_active_lane_mask: {
+ if (ST->hasVInstructions()) {
+ Type *ExpRetTy = VectorType::get(
+ ICA.getArgTypes()[0], cast<VectorType>(RetTy)->getElementCount());
+ auto LT = getTypeLegalizationCost(ExpRetTy);
+
+ // vid.v v8 // considered hoisted
+ // vsaddu.vx v8, v8, a0
+ // vmsltu.vx v0, v8, a1
+ return LT.first *
+ getRISCVInstructionCost({RISCV::VSADDU_VX, RISCV::VMSLTU_VX},
+ LT.second, CostKind);
+ }
+ break;
+ }
// TODO: add more intrinsic
case Intrinsic::experimental_stepvector: {
auto LT = getTypeLegalizationCost(RetTy);
@@ -1327,10 +1342,14 @@ InstructionCost RISCVTTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
// vmandn.mm v8, v8, v9
// vmand.mm v9, v0, v9
// vmor.mm v0, v9, v8
- return LT.first * 3;
+ return LT.first *
+ getRISCVInstructionCost(
+ {RISCV::VMANDN_MM, RISCV::VMAND_MM, RISCV::VMOR_MM},
+ LT.second, CostKind);
}
// vselect and max/min are supported natively.
- return LT.first * 1;
+ return LT.first *
+ getRISCVInstructionCost(RISCV::VMERGE_VVM, LT.second, CostKind);
}
if (ValTy->getScalarSizeInBits() == 1) {
@@ -1339,13 +1358,21 @@ InstructionCost RISCVTTIImpl::getCmpSelInstrCost(unsigned Opcode, Type *ValTy,
// vmandn.mm v8, v8, v9
// vmand.mm v9, v0, v9
// vmor.mm v0, v9, v8
- return LT.first * 5;
+ MVT InterimVT = LT.second.changeVectorElementType(MVT::i8);
+ return LT.first *
+ getRISCVInstructionCost({RISCV::VMV_V_X, RISCV::VMSNE_VI},
+ InterimVT, CostKind) +
+ LT.first * getRISCVInstructionCost(
+ {RISCV::VMANDN_MM, RISCV::VMAND_MM, RISCV::VMOR_MM},
+ LT.second, CostKind);
}
// vmv.v.x v10, a0
// vmsne.vi v0, v10, 0
// vmerge.vvm v8, v9, v8, v0
- return LT.first * 3;
+ return LT.first * getRISCVInstructionCost(
+ {RISCV::VMV_V_X, RISCV::VMSNE_VI, RISCV::VMERGE_VVM},
+ LT.second, CostKind);
}
if ((Opcode == Instruction::ICmp || Opcode == Instruction::FCmp) &&
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
index 9592f3e81b40..70197e948c65 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.cpp
@@ -20,7 +20,12 @@
#include "SPIRVSubtarget.h"
#include "SPIRVTargetMachine.h"
#include "SPIRVUtils.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/IR/Constants.h"
+#include "llvm/IR/Type.h"
#include "llvm/IR/TypedPointerType.h"
+#include "llvm/Support/Casting.h"
+#include <cassert>
using namespace llvm;
SPIRVGlobalRegistry::SPIRVGlobalRegistry(unsigned PointerSize)
@@ -35,6 +40,15 @@ SPIRVType *SPIRVGlobalRegistry::assignIntTypeToVReg(unsigned BitWidth,
return SpirvType;
}
+SPIRVType *
+SPIRVGlobalRegistry::assignFloatTypeToVReg(unsigned BitWidth, Register VReg,
+ MachineInstr &I,
+ const SPIRVInstrInfo &TII) {
+ SPIRVType *SpirvType = getOrCreateSPIRVFloatType(BitWidth, I, TII);
+ assignSPIRVTypeToVReg(SpirvType, VReg, *CurMF);
+ return SpirvType;
+}
+
SPIRVType *SPIRVGlobalRegistry::assignVectTypeToVReg(
SPIRVType *BaseType, unsigned NumElements, Register VReg, MachineInstr &I,
const SPIRVInstrInfo &TII) {
@@ -151,6 +165,8 @@ SPIRVGlobalRegistry::getOrCreateConstIntReg(uint64_t Val, SPIRVType *SpvType,
Register Res = DT.find(CI, CurMF);
if (!Res.isValid()) {
unsigned BitWidth = SpvType ? getScalarOrVectorBitWidth(SpvType) : 32;
+ // TODO: handle cases where the type is not 32bit wide
+ // TODO: https://github.com/llvm/llvm-project/issues/88129
LLT LLTy = LLT::scalar(32);
Res = CurMF->getRegInfo().createGenericVirtualRegister(LLTy);
CurMF->getRegInfo().setRegClass(Res, &SPIRV::IDRegClass);
@@ -164,9 +180,83 @@ SPIRVGlobalRegistry::getOrCreateConstIntReg(uint64_t Val, SPIRVType *SpvType,
return std::make_tuple(Res, CI, NewInstr);
}
+std::tuple<Register, ConstantFP *, bool, unsigned>
+SPIRVGlobalRegistry::getOrCreateConstFloatReg(APFloat Val, SPIRVType *SpvType,
+ MachineIRBuilder *MIRBuilder,
+ MachineInstr *I,
+ const SPIRVInstrInfo *TII) {
+ const Type *LLVMFloatTy;
+ LLVMContext &Ctx = CurMF->getFunction().getContext();
+ unsigned BitWidth = 32;
+ if (SpvType)
+ LLVMFloatTy = getTypeForSPIRVType(SpvType);
+ else {
+ LLVMFloatTy = Type::getFloatTy(Ctx);
+ if (MIRBuilder)
+ SpvType = getOrCreateSPIRVType(LLVMFloatTy, *MIRBuilder);
+ }
+ bool NewInstr = false;
+ // Find a constant in DT or build a new one.
+ auto *const CI = ConstantFP::get(Ctx, Val);
+ Register Res = DT.find(CI, CurMF);
+ if (!Res.isValid()) {
+ if (SpvType)
+ BitWidth = getScalarOrVectorBitWidth(SpvType);
+ // TODO: handle cases where the type is not 32bit wide
+ // TODO: https://github.com/llvm/llvm-project/issues/88129
+ LLT LLTy = LLT::scalar(32);
+ Res = CurMF->getRegInfo().createGenericVirtualRegister(LLTy);
+ CurMF->getRegInfo().setRegClass(Res, &SPIRV::IDRegClass);
+ if (MIRBuilder)
+ assignTypeToVReg(LLVMFloatTy, Res, *MIRBuilder);
+ else
+ assignFloatTypeToVReg(BitWidth, Res, *I, *TII);
+ DT.add(CI, CurMF, Res);
+ NewInstr = true;
+ }
+ return std::make_tuple(Res, CI, NewInstr, BitWidth);
+}
+
+Register SPIRVGlobalRegistry::getOrCreateConstFP(APFloat Val, MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ bool ZeroAsNull) {
+ assert(SpvType);
+ ConstantFP *CI;
+ Register Res;
+ bool New;
+ unsigned BitWidth;
+ std::tie(Res, CI, New, BitWidth) =
+ getOrCreateConstFloatReg(Val, SpvType, nullptr, &I, &TII);
+ // If we have found Res register which is defined by the passed G_CONSTANT
+ // machine instruction, a new constant instruction should be created.
+ if (!New && (!I.getOperand(0).isReg() || Res != I.getOperand(0).getReg()))
+ return Res;
+ MachineInstrBuilder MIB;
+ MachineBasicBlock &BB = *I.getParent();
+ // In OpenCL OpConstantNull - Scalar floating point: +0.0 (all bits 0)
+ if (Val.isPosZero() && ZeroAsNull) {
+ MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantNull))
+ .addDef(Res)
+ .addUse(getSPIRVTypeID(SpvType));
+ } else {
+ MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantF))
+ .addDef(Res)
+ .addUse(getSPIRVTypeID(SpvType));
+ addNumImm(
+ APInt(BitWidth, CI->getValueAPF().bitcastToAPInt().getZExtValue()),
+ MIB);
+ }
+ const auto &ST = CurMF->getSubtarget();
+ constrainSelectedInstRegOperands(*MIB, *ST.getInstrInfo(),
+ *ST.getRegisterInfo(), *ST.getRegBankInfo());
+ return Res;
+}
+
Register SPIRVGlobalRegistry::getOrCreateConstInt(uint64_t Val, MachineInstr &I,
SPIRVType *SpvType,
- const SPIRVInstrInfo &TII) {
+ const SPIRVInstrInfo &TII,
+ bool ZeroAsNull) {
assert(SpvType);
ConstantInt *CI;
Register Res;
@@ -179,7 +269,7 @@ Register SPIRVGlobalRegistry::getOrCreateConstInt(uint64_t Val, MachineInstr &I,
return Res;
MachineInstrBuilder MIB;
MachineBasicBlock &BB = *I.getParent();
- if (Val) {
+ if (Val || !ZeroAsNull) {
MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantI))
.addDef(Res)
.addUse(getSPIRVTypeID(SpvType));
@@ -270,21 +360,46 @@ Register SPIRVGlobalRegistry::buildConstantFP(APFloat Val,
return Res;
}
-Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull(
- uint64_t Val, MachineInstr &I, SPIRVType *SpvType,
+Register SPIRVGlobalRegistry::getOrCreateBaseRegister(Constant *Val,
+ MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ unsigned BitWidth) {
+ SPIRVType *Type = SpvType;
+ if (SpvType->getOpcode() == SPIRV::OpTypeVector ||
+ SpvType->getOpcode() == SPIRV::OpTypeArray) {
+ auto EleTypeReg = SpvType->getOperand(1).getReg();
+ Type = getSPIRVTypeForVReg(EleTypeReg);
+ }
+ if (Type->getOpcode() == SPIRV::OpTypeFloat) {
+ SPIRVType *SpvBaseType = getOrCreateSPIRVFloatType(BitWidth, I, TII);
+ return getOrCreateConstFP(dyn_cast<ConstantFP>(Val)->getValue(), I,
+ SpvBaseType, TII);
+ }
+ assert(Type->getOpcode() == SPIRV::OpTypeInt);
+ SPIRVType *SpvBaseType = getOrCreateSPIRVIntegerType(BitWidth, I, TII);
+ return getOrCreateConstInt(Val->getUniqueInteger().getSExtValue(), I,
+ SpvBaseType, TII);
+}
+
+Register SPIRVGlobalRegistry::getOrCreateCompositeOrNull(
+ Constant *Val, MachineInstr &I, SPIRVType *SpvType,
const SPIRVInstrInfo &TII, Constant *CA, unsigned BitWidth,
- unsigned ElemCnt) {
+ unsigned ElemCnt, bool ZeroAsNull) {
// Find a constant vector in DT or build a new one.
Register Res = DT.find(CA, CurMF);
+ // If no values are attached, the composite is null constant.
+ bool IsNull = Val->isNullValue() && ZeroAsNull;
if (!Res.isValid()) {
- SPIRVType *SpvBaseType = getOrCreateSPIRVIntegerType(BitWidth, I, TII);
// SpvScalConst should be created before SpvVecConst to avoid undefined ID
// error on validation.
// TODO: can moved below once sorting of types/consts/defs is implemented.
Register SpvScalConst;
- if (Val)
- SpvScalConst = getOrCreateConstInt(Val, I, SpvBaseType, TII);
- // TODO: maybe use bitwidth of base type.
+ if (!IsNull)
+ SpvScalConst = getOrCreateBaseRegister(Val, I, SpvType, TII, BitWidth);
+
+ // TODO: handle cases where the type is not 32bit wide
+ // TODO: https://github.com/llvm/llvm-project/issues/88129
LLT LLTy = LLT::scalar(32);
Register SpvVecConst =
CurMF->getRegInfo().createGenericVirtualRegister(LLTy);
@@ -293,7 +408,7 @@ Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull(
DT.add(CA, CurMF, SpvVecConst);
MachineInstrBuilder MIB;
MachineBasicBlock &BB = *I.getParent();
- if (Val) {
+ if (!IsNull) {
MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpConstantComposite))
.addDef(SpvVecConst)
.addUse(getSPIRVTypeID(SpvType));
@@ -313,20 +428,42 @@ Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull(
return Res;
}
-Register
-SPIRVGlobalRegistry::getOrCreateConsIntVector(uint64_t Val, MachineInstr &I,
- SPIRVType *SpvType,
- const SPIRVInstrInfo &TII) {
+Register SPIRVGlobalRegistry::getOrCreateConstVector(uint64_t Val,
+ MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ bool ZeroAsNull) {
const Type *LLVMTy = getTypeForSPIRVType(SpvType);
assert(LLVMTy->isVectorTy());
const FixedVectorType *LLVMVecTy = cast<FixedVectorType>(LLVMTy);
Type *LLVMBaseTy = LLVMVecTy->getElementType();
- const auto ConstInt = ConstantInt::get(LLVMBaseTy, Val);
- auto ConstVec =
- ConstantVector::getSplat(LLVMVecTy->getElementCount(), ConstInt);
+ assert(LLVMBaseTy->isIntegerTy());
+ auto *ConstVal = ConstantInt::get(LLVMBaseTy, Val);
+ auto *ConstVec =
+ ConstantVector::getSplat(LLVMVecTy->getElementCount(), ConstVal);
unsigned BW = getScalarOrVectorBitWidth(SpvType);
- return getOrCreateIntCompositeOrNull(Val, I, SpvType, TII, ConstVec, BW,
- SpvType->getOperand(2).getImm());
+ return getOrCreateCompositeOrNull(ConstVal, I, SpvType, TII, ConstVec, BW,
+ SpvType->getOperand(2).getImm(),
+ ZeroAsNull);
+}
+
+Register SPIRVGlobalRegistry::getOrCreateConstVector(APFloat Val,
+ MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ bool ZeroAsNull) {
+ const Type *LLVMTy = getTypeForSPIRVType(SpvType);
+ assert(LLVMTy->isVectorTy());
+ const FixedVectorType *LLVMVecTy = cast<FixedVectorType>(LLVMTy);
+ Type *LLVMBaseTy = LLVMVecTy->getElementType();
+ assert(LLVMBaseTy->isFloatingPointTy());
+ auto *ConstVal = ConstantFP::get(LLVMBaseTy, Val);
+ auto *ConstVec =
+ ConstantVector::getSplat(LLVMVecTy->getElementCount(), ConstVal);
+ unsigned BW = getScalarOrVectorBitWidth(SpvType);
+ return getOrCreateCompositeOrNull(ConstVal, I, SpvType, TII, ConstVec, BW,
+ SpvType->getOperand(2).getImm(),
+ ZeroAsNull);
}
Register
@@ -337,13 +474,13 @@ SPIRVGlobalRegistry::getOrCreateConsIntArray(uint64_t Val, MachineInstr &I,
assert(LLVMTy->isArrayTy());
const ArrayType *LLVMArrTy = cast<ArrayType>(LLVMTy);
Type *LLVMBaseTy = LLVMArrTy->getElementType();
- const auto ConstInt = ConstantInt::get(LLVMBaseTy, Val);
- auto ConstArr =
+ auto *ConstInt = ConstantInt::get(LLVMBaseTy, Val);
+ auto *ConstArr =
ConstantArray::get(const_cast<ArrayType *>(LLVMArrTy), {ConstInt});
SPIRVType *SpvBaseTy = getSPIRVTypeForVReg(SpvType->getOperand(1).getReg());
unsigned BW = getScalarOrVectorBitWidth(SpvBaseTy);
- return getOrCreateIntCompositeOrNull(Val, I, SpvType, TII, ConstArr, BW,
- LLVMArrTy->getNumElements());
+ return getOrCreateCompositeOrNull(ConstInt, I, SpvType, TII, ConstArr, BW,
+ LLVMArrTy->getNumElements());
}
Register SPIRVGlobalRegistry::getOrCreateIntCompositeOrNull(
@@ -1093,14 +1230,16 @@ SPIRVType *SPIRVGlobalRegistry::finishCreatingSPIRVType(const Type *LLVMTy,
return SpirvType;
}
-SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(
- unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) {
- Type *LLVMTy = IntegerType::get(CurMF->getFunction().getContext(), BitWidth);
+SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVType(unsigned BitWidth,
+ MachineInstr &I,
+ const SPIRVInstrInfo &TII,
+ unsigned SPIRVOPcode,
+ Type *LLVMTy) {
Register Reg = DT.find(LLVMTy, CurMF);
if (Reg.isValid())
return getSPIRVTypeForVReg(Reg);
MachineBasicBlock &BB = *I.getParent();
- auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpTypeInt))
+ auto MIB = BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRVOPcode))
.addDef(createTypeVReg(CurMF->getRegInfo()))
.addImm(BitWidth)
.addImm(0);
@@ -1108,6 +1247,31 @@ SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(
return finishCreatingSPIRVType(LLVMTy, MIB);
}
+SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVIntegerType(
+ unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) {
+ Type *LLVMTy = IntegerType::get(CurMF->getFunction().getContext(), BitWidth);
+ return getOrCreateSPIRVType(BitWidth, I, TII, SPIRV::OpTypeInt, LLVMTy);
+}
+SPIRVType *SPIRVGlobalRegistry::getOrCreateSPIRVFloatType(
+ unsigned BitWidth, MachineInstr &I, const SPIRVInstrInfo &TII) {
+ LLVMContext &Ctx = CurMF->getFunction().getContext();
+ Type *LLVMTy;
+ switch (BitWidth) {
+ case 16:
+ LLVMTy = Type::getHalfTy(Ctx);
+ break;
+ case 32:
+ LLVMTy = Type::getFloatTy(Ctx);
+ break;
+ case 64:
+ LLVMTy = Type::getDoubleTy(Ctx);
+ break;
+ default:
+ llvm_unreachable("Bit width is of unexpected size.");
+ }
+ return getOrCreateSPIRVType(BitWidth, I, TII, SPIRV::OpTypeFloat, LLVMTy);
+}
+
SPIRVType *
SPIRVGlobalRegistry::getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder) {
return getOrCreateSPIRVType(
diff --git a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
index 37f575e884ef..2e3e69456ac2 100644
--- a/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
+++ b/llvm/lib/Target/SPIRV/SPIRVGlobalRegistry.h
@@ -20,6 +20,7 @@
#include "SPIRVDuplicatesTracker.h"
#include "SPIRVInstrInfo.h"
#include "llvm/CodeGen/GlobalISel/MachineIRBuilder.h"
+#include "llvm/IR/Constant.h"
namespace llvm {
using SPIRVType = const MachineInstr;
@@ -234,6 +235,8 @@ public:
bool EmitIR = true);
SPIRVType *assignIntTypeToVReg(unsigned BitWidth, Register VReg,
MachineInstr &I, const SPIRVInstrInfo &TII);
+ SPIRVType *assignFloatTypeToVReg(unsigned BitWidth, Register VReg,
+ MachineInstr &I, const SPIRVInstrInfo &TII);
SPIRVType *assignVectTypeToVReg(SPIRVType *BaseType, unsigned NumElements,
Register VReg, MachineInstr &I,
const SPIRVInstrInfo &TII);
@@ -372,12 +375,20 @@ private:
std::tuple<Register, ConstantInt *, bool> getOrCreateConstIntReg(
uint64_t Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder,
MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr);
+ std::tuple<Register, ConstantFP *, bool, unsigned> getOrCreateConstFloatReg(
+ APFloat Val, SPIRVType *SpvType, MachineIRBuilder *MIRBuilder,
+ MachineInstr *I = nullptr, const SPIRVInstrInfo *TII = nullptr);
SPIRVType *finishCreatingSPIRVType(const Type *LLVMTy, SPIRVType *SpirvType);
- Register getOrCreateIntCompositeOrNull(uint64_t Val, MachineInstr &I,
- SPIRVType *SpvType,
- const SPIRVInstrInfo &TII,
- Constant *CA, unsigned BitWidth,
- unsigned ElemCnt);
+ Register getOrCreateBaseRegister(Constant *Val, MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ unsigned BitWidth);
+ Register getOrCreateCompositeOrNull(Constant *Val, MachineInstr &I,
+ SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII, Constant *CA,
+ unsigned BitWidth, unsigned ElemCnt,
+ bool ZeroAsNull = true);
+
Register getOrCreateIntCompositeOrNull(uint64_t Val,
MachineIRBuilder &MIRBuilder,
SPIRVType *SpvType, bool EmitIR,
@@ -388,12 +399,20 @@ public:
Register buildConstantInt(uint64_t Val, MachineIRBuilder &MIRBuilder,
SPIRVType *SpvType = nullptr, bool EmitIR = true);
Register getOrCreateConstInt(uint64_t Val, MachineInstr &I,
- SPIRVType *SpvType, const SPIRVInstrInfo &TII);
+ SPIRVType *SpvType, const SPIRVInstrInfo &TII,
+ bool ZeroAsNull = true);
+ Register getOrCreateConstFP(APFloat Val, MachineInstr &I, SPIRVType *SpvType,
+ const SPIRVInstrInfo &TII,
+ bool ZeroAsNull = true);
Register buildConstantFP(APFloat Val, MachineIRBuilder &MIRBuilder,
SPIRVType *SpvType = nullptr);
- Register getOrCreateConsIntVector(uint64_t Val, MachineInstr &I,
- SPIRVType *SpvType,
- const SPIRVInstrInfo &TII);
+
+ Register getOrCreateConstVector(uint64_t Val, MachineInstr &I,
+ SPIRVType *SpvType, const SPIRVInstrInfo &TII,
+ bool ZeroAsNull = true);
+ Register getOrCreateConstVector(APFloat Val, MachineInstr &I,
+ SPIRVType *SpvType, const SPIRVInstrInfo &TII,
+ bool ZeroAsNull = true);
Register getOrCreateConsIntArray(uint64_t Val, MachineInstr &I,
SPIRVType *SpvType,
const SPIRVInstrInfo &TII);
@@ -423,6 +442,11 @@ public:
MachineIRBuilder &MIRBuilder);
SPIRVType *getOrCreateSPIRVIntegerType(unsigned BitWidth, MachineInstr &I,
const SPIRVInstrInfo &TII);
+ SPIRVType *getOrCreateSPIRVType(unsigned BitWidth, MachineInstr &I,
+ const SPIRVInstrInfo &TII,
+ unsigned SPIRVOPcode, Type *LLVMTy);
+ SPIRVType *getOrCreateSPIRVFloatType(unsigned BitWidth, MachineInstr &I,
+ const SPIRVInstrInfo &TII);
SPIRVType *getOrCreateSPIRVBoolType(MachineIRBuilder &MIRBuilder);
SPIRVType *getOrCreateSPIRVBoolType(MachineInstr &I,
const SPIRVInstrInfo &TII);
diff --git a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
index 45a70da7f869..c1c0fc4b7dd4 100644
--- a/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVInstructionSelector.cpp
@@ -28,6 +28,7 @@
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineModuleInfoImpls.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetOpcodes.h"
#include "llvm/IR/IntrinsicsSPIRV.h"
#include "llvm/Support/Debug.h"
@@ -144,6 +145,9 @@ private:
bool selectAddrSpaceCast(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I) const;
+ bool selectAll(Register ResVReg, const SPIRVType *ResType,
+ MachineInstr &I) const;
+
bool selectBitreverse(Register ResVReg, const SPIRVType *ResType,
MachineInstr &I) const;
@@ -229,6 +233,7 @@ private:
const SPIRVType *ResType = nullptr) const;
Register buildZerosVal(const SPIRVType *ResType, MachineInstr &I) const;
+ Register buildZerosValF(const SPIRVType *ResType, MachineInstr &I) const;
Register buildOnesVal(bool AllOnes, const SPIRVType *ResType,
MachineInstr &I) const;
@@ -1155,6 +1160,65 @@ static unsigned getBoolCmpOpcode(unsigned PredNum) {
}
}
+bool SPIRVInstructionSelector::selectAll(Register ResVReg,
+ const SPIRVType *ResType,
+ MachineInstr &I) const {
+ assert(I.getNumOperands() == 3);
+ assert(I.getOperand(2).isReg());
+ MachineBasicBlock &BB = *I.getParent();
+ Register InputRegister = I.getOperand(2).getReg();
+ SPIRVType *InputType = GR.getSPIRVTypeForVReg(InputRegister);
+
+ if (!InputType)
+ report_fatal_error("Input Type could not be determined.");
+
+ bool IsBoolTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeBool);
+ bool IsVectorTy = InputType->getOpcode() == SPIRV::OpTypeVector;
+ if (IsBoolTy && !IsVectorTy) {
+ assert(ResVReg == I.getOperand(0).getReg());
+ return BuildMI(*I.getParent(), I, I.getDebugLoc(),
+ TII.get(TargetOpcode::COPY))
+ .addDef(ResVReg)
+ .addUse(InputRegister)
+ .constrainAllUses(TII, TRI, RBI);
+ }
+
+ bool IsFloatTy = GR.isScalarOrVectorOfType(InputRegister, SPIRV::OpTypeFloat);
+ unsigned SpirvNotEqualId =
+ IsFloatTy ? SPIRV::OpFOrdNotEqual : SPIRV::OpINotEqual;
+ SPIRVType *SpvBoolScalarTy = GR.getOrCreateSPIRVBoolType(I, TII);
+ SPIRVType *SpvBoolTy = SpvBoolScalarTy;
+ Register NotEqualReg = ResVReg;
+
+ if (IsVectorTy) {
+ NotEqualReg = IsBoolTy ? InputRegister
+ : MRI->createVirtualRegister(&SPIRV::IDRegClass);
+ const unsigned NumElts = InputType->getOperand(2).getImm();
+ SpvBoolTy = GR.getOrCreateSPIRVVectorType(SpvBoolTy, NumElts, I, TII);
+ }
+
+ if (!IsBoolTy) {
+ Register ConstZeroReg =
+ IsFloatTy ? buildZerosValF(InputType, I) : buildZerosVal(InputType, I);
+
+ BuildMI(BB, I, I.getDebugLoc(), TII.get(SpirvNotEqualId))
+ .addDef(NotEqualReg)
+ .addUse(GR.getSPIRVTypeID(SpvBoolTy))
+ .addUse(InputRegister)
+ .addUse(ConstZeroReg)
+ .constrainAllUses(TII, TRI, RBI);
+ }
+
+ if (!IsVectorTy)
+ return true;
+
+ return BuildMI(BB, I, I.getDebugLoc(), TII.get(SPIRV::OpAll))
+ .addDef(ResVReg)
+ .addUse(GR.getSPIRVTypeID(SpvBoolScalarTy))
+ .addUse(NotEqualReg)
+ .constrainAllUses(TII, TRI, RBI);
+}
+
bool SPIRVInstructionSelector::selectBitreverse(Register ResVReg,
const SPIRVType *ResType,
MachineInstr &I) const {
@@ -1391,9 +1455,35 @@ bool SPIRVInstructionSelector::selectFCmp(Register ResVReg,
Register SPIRVInstructionSelector::buildZerosVal(const SPIRVType *ResType,
MachineInstr &I) const {
+ // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
+ bool ZeroAsNull = STI.isOpenCLEnv();
+ if (ResType->getOpcode() == SPIRV::OpTypeVector)
+ return GR.getOrCreateConstVector(0UL, I, ResType, TII, ZeroAsNull);
+ return GR.getOrCreateConstInt(0, I, ResType, TII, ZeroAsNull);
+}
+
+static APFloat getZeroFP(const Type *LLVMFloatTy) {
+ if (!LLVMFloatTy)
+ return APFloat::getZero(APFloat::IEEEsingle());
+ switch (LLVMFloatTy->getScalarType()->getTypeID()) {
+ case Type::HalfTyID:
+ return APFloat::getZero(APFloat::IEEEhalf());
+ default:
+ case Type::FloatTyID:
+ return APFloat::getZero(APFloat::IEEEsingle());
+ case Type::DoubleTyID:
+ return APFloat::getZero(APFloat::IEEEdouble());
+ }
+}
+
+Register SPIRVInstructionSelector::buildZerosValF(const SPIRVType *ResType,
+ MachineInstr &I) const {
+ // OpenCL uses nulls for Zero. In HLSL we don't use null constants.
+ bool ZeroAsNull = STI.isOpenCLEnv();
+ APFloat VZero = getZeroFP(GR.getTypeForSPIRVType(ResType));
if (ResType->getOpcode() == SPIRV::OpTypeVector)
- return GR.getOrCreateConsIntVector(0, I, ResType, TII);
- return GR.getOrCreateConstInt(0, I, ResType, TII);
+ return GR.getOrCreateConstVector(VZero, I, ResType, TII, ZeroAsNull);
+ return GR.getOrCreateConstFP(VZero, I, ResType, TII, ZeroAsNull);
}
Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
@@ -1403,7 +1493,7 @@ Register SPIRVInstructionSelector::buildOnesVal(bool AllOnes,
APInt One =
AllOnes ? APInt::getAllOnes(BitWidth) : APInt::getOneBitSet(BitWidth, 0);
if (ResType->getOpcode() == SPIRV::OpTypeVector)
- return GR.getOrCreateConsIntVector(One.getZExtValue(), I, ResType, TII);
+ return GR.getOrCreateConstVector(One.getZExtValue(), I, ResType, TII);
return GR.getOrCreateConstInt(One.getZExtValue(), I, ResType, TII);
}
@@ -1785,6 +1875,8 @@ bool SPIRVInstructionSelector::selectIntrinsic(Register ResVReg,
break;
case Intrinsic::spv_thread_id:
return selectSpvThreadId(ResVReg, ResType, I);
+ case Intrinsic::spv_all:
+ return selectAll(ResVReg, ResType, I);
case Intrinsic::spv_lifetime_start:
case Intrinsic::spv_lifetime_end: {
unsigned Op = IID == Intrinsic::spv_lifetime_start ? SPIRV::OpLifetimeStart
diff --git a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
index c87c1293c622..299a4341193b 100644
--- a/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
+++ b/llvm/lib/Target/SPIRV/SPIRVUtils.cpp
@@ -374,13 +374,21 @@ Type *parseBasicTypeName(StringRef TypeName, LLVMContext &Ctx) {
return Type::getVoidTy(Ctx);
else if (TypeName.consume_front("bool"))
return Type::getIntNTy(Ctx, 1);
- else if (TypeName.consume_front("char") || TypeName.consume_front("uchar"))
+ else if (TypeName.consume_front("char") ||
+ TypeName.consume_front("unsigned char") ||
+ TypeName.consume_front("uchar"))
return Type::getInt8Ty(Ctx);
- else if (TypeName.consume_front("short") || TypeName.consume_front("ushort"))
+ else if (TypeName.consume_front("short") ||
+ TypeName.consume_front("unsigned short") ||
+ TypeName.consume_front("ushort"))
return Type::getInt16Ty(Ctx);
- else if (TypeName.consume_front("int") || TypeName.consume_front("uint"))
+ else if (TypeName.consume_front("int") ||
+ TypeName.consume_front("unsigned int") ||
+ TypeName.consume_front("uint"))
return Type::getInt32Ty(Ctx);
- else if (TypeName.consume_front("long") || TypeName.consume_front("ulong"))
+ else if (TypeName.consume_front("long") ||
+ TypeName.consume_front("unsigned long") ||
+ TypeName.consume_front("ulong"))
return Type::getInt64Ty(Ctx);
else if (TypeName.consume_front("half"))
return Type::getHalfTy(Ctx);
diff --git a/llvm/lib/Target/X86/X86ISelLowering.cpp b/llvm/lib/Target/X86/X86ISelLowering.cpp
index 5405c2921e51..52be35aafb0f 100644
--- a/llvm/lib/Target/X86/X86ISelLowering.cpp
+++ b/llvm/lib/Target/X86/X86ISelLowering.cpp
@@ -1496,6 +1496,11 @@ X86TargetLowering::X86TargetLowering(const X86TargetMachine &TM,
setOperationAction(ISD::TRUNCATE, MVT::v32i32, Custom);
setOperationAction(ISD::TRUNCATE, MVT::v32i64, Custom);
+ if (Subtarget.hasGFNI()) {
+ setOperationAction(ISD::BITREVERSE, MVT::i32, Custom);
+ setOperationAction(ISD::BITREVERSE, MVT::i64, Custom);
+ }
+
for (auto VT : { MVT::v32i8, MVT::v16i16, MVT::v8i32, MVT::v4i64 }) {
setOperationAction(ISD::SETCC, VT, Custom);
setOperationAction(ISD::CTPOP, VT, Custom);
@@ -31332,6 +31337,23 @@ static SDValue LowerBITREVERSE(SDValue Op, const X86Subtarget &Subtarget,
if (VT.is256BitVector() && !Subtarget.hasInt256())
return splitVectorIntUnary(Op, DAG, DL);
+ // Lower i32/i64 to GFNI as vXi8 BITREVERSE + BSWAP
+ if (!VT.isVector()) {
+
+ assert((VT.getScalarType() == MVT::i32) ||
+ (VT.getScalarType() == MVT::i64));
+
+ MVT VecVT = MVT::getVectorVT(VT, 128 / VT.getSizeInBits());
+ SDValue Res = DAG.getNode(ISD::SCALAR_TO_VECTOR, DL, VecVT, In);
+ Res = DAG.getNode(ISD::BITREVERSE, DL, MVT::v16i8,
+ DAG.getBitcast(MVT::v16i8, Res));
+ Res = DAG.getNode(ISD::EXTRACT_VECTOR_ELT, DL, VT,
+ DAG.getBitcast(VecVT, Res), DAG.getIntPtrConstant(0, DL));
+ return DAG.getNode(ISD::BSWAP, DL, VT, Res);
+ }
+
+ assert(VT.isVector() && VT.getSizeInBits() >= 128);
+
// Lower vXi16/vXi32/vXi64 as BSWAP + vXi8 BITREVERSE.
if (VT.getScalarType() != MVT::i8) {
MVT ByteVT = MVT::getVectorVT(MVT::i8, VT.getSizeInBits() / 8);
@@ -54126,7 +54148,8 @@ static SDValue combineUIntToFP(SDNode *N, SelectionDAG &DAG,
// Since UINT_TO_FP is legal (it's marked custom), dag combiner won't
// optimize it to a SINT_TO_FP when the sign bit is known zero. Perform
// the optimization here.
- if (DAG.SignBitIsZero(Op0)) {
+ SDNodeFlags Flags = N->getFlags();
+ if (Flags.hasNonNeg() || DAG.SignBitIsZero(Op0)) {
if (IsStrict)
return DAG.getNode(ISD::STRICT_SINT_TO_FP, SDLoc(N), {VT, MVT::Other},
{N->getOperand(0), Op0});
diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp
index b5f45a252c7b..0b3a6931e779 100644
--- a/llvm/lib/Transforms/IPO/SampleProfile.cpp
+++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp
@@ -2059,7 +2059,7 @@ bool SampleProfileLoader::doInitialization(Module &M,
// Load pseudo probe descriptors for probe-based function samples.
if (Reader->profileIsProbeBased()) {
- ProbeManager = std::make_unique<PseudoProbeManager>(M, LTOPhase);
+ ProbeManager = std::make_unique<PseudoProbeManager>(M);
if (!ProbeManager->moduleIsProbed(M)) {
const char *Msg =
"Pseudo-probe-based profile requires SampleProfileProbePass";
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
index 4d3de76389c2..2d78fcee1152 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp
@@ -3091,6 +3091,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateOr(CondVal, FalseVal);
}
+ if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_One(), m_Value(B)))) &&
+ impliesPoison(FalseVal, B)) {
+ // (A || B) || C --> A || (B | C)
+ return replaceInstUsesWith(
+ SI, Builder.CreateLogicalOr(A, Builder.CreateOr(B, FalseVal)));
+ }
+
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(FalseVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ false,
@@ -3132,6 +3139,13 @@ Instruction *InstCombinerImpl::foldSelectOfBools(SelectInst &SI) {
return BinaryOperator::CreateAnd(CondVal, TrueVal);
}
+ if (match(CondVal, m_OneUse(m_Select(m_Value(A), m_Value(B), m_Zero()))) &&
+ impliesPoison(TrueVal, B)) {
+ // (A && B) && C --> A && (B & C)
+ return replaceInstUsesWith(
+ SI, Builder.CreateLogicalAnd(A, Builder.CreateAnd(B, TrueVal)));
+ }
+
if (auto *LHS = dyn_cast<FCmpInst>(CondVal))
if (auto *RHS = dyn_cast<FCmpInst>(TrueVal))
if (Value *V = foldLogicOfFCmps(LHS, RHS, /*IsAnd*/ true,
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index c691c8b1c55b..6739b8745d74 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -655,25 +655,33 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Value *V, APInt DemandedMask,
}
}
- // TODO: If we only want bits that already match the signbit then we don't
+ // We only want bits that already match the signbit then we don't
// need to shift.
+ uint64_t ShiftAmt = SA->getLimitedValue(BitWidth - 1);
+ if (DemandedMask.countr_zero() >= ShiftAmt) {
+ if (I->hasNoSignedWrap()) {
+ unsigned NumHiDemandedBits = BitWidth - DemandedMask.countr_zero();
+ unsigned SignBits =
+ ComputeNumSignBits(I->getOperand(0), Depth + 1, CxtI);
+ if (SignBits > ShiftAmt && SignBits - ShiftAmt >= NumHiDemandedBits)
+ return I->getOperand(0);
+ }
- // If we can pre-shift a right-shifted constant to the left without
- // losing any high bits amd we don't demand the low bits, then eliminate
- // the left-shift:
- // (C >> X) << LeftShiftAmtC --> (C << RightShiftAmtC) >> X
- uint64_t ShiftAmt = SA->getLimitedValue(BitWidth-1);
- Value *X;
- Constant *C;
- if (DemandedMask.countr_zero() >= ShiftAmt &&
- match(I->getOperand(0), m_LShr(m_ImmConstant(C), m_Value(X)))) {
- Constant *LeftShiftAmtC = ConstantInt::get(VTy, ShiftAmt);
- Constant *NewC = ConstantFoldBinaryOpOperands(Instruction::Shl, C,
- LeftShiftAmtC, DL);
- if (ConstantFoldBinaryOpOperands(Instruction::LShr, NewC, LeftShiftAmtC,
- DL) == C) {
- Instruction *Lshr = BinaryOperator::CreateLShr(NewC, X);
- return InsertNewInstWith(Lshr, I->getIterator());
+ // If we can pre-shift a right-shifted constant to the left without
+ // losing any high bits and we don't demand the low bits, then eliminate
+ // the left-shift:
+ // (C >> X) << LeftShiftAmtC --> (C << LeftShiftAmtC) >> X
+ Value *X;
+ Constant *C;
+ if (match(I->getOperand(0), m_LShr(m_ImmConstant(C), m_Value(X)))) {
+ Constant *LeftShiftAmtC = ConstantInt::get(VTy, ShiftAmt);
+ Constant *NewC = ConstantFoldBinaryOpOperands(Instruction::Shl, C,
+ LeftShiftAmtC, DL);
+ if (ConstantFoldBinaryOpOperands(Instruction::LShr, NewC,
+ LeftShiftAmtC, DL) == C) {
+ Instruction *Lshr = BinaryOperator::CreateLShr(NewC, X);
+ return InsertNewInstWith(Lshr, I->getIterator());
+ }
}
}
diff --git a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
index 46b9181c8922..ee3531bbd68d 100644
--- a/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/MemorySanitizer.cpp
@@ -3715,8 +3715,32 @@ struct MemorySanitizerVisitor : public InstVisitor<MemorySanitizerVisitor> {
setOrigin(&I, getOrigin(&I, 0));
}
+ void handleArithmeticWithOverflow(IntrinsicInst &I) {
+ IRBuilder<> IRB(&I);
+ Value *Shadow0 = getShadow(&I, 0);
+ Value *Shadow1 = getShadow(&I, 1);
+ Value *ShadowElt0 = IRB.CreateOr(Shadow0, Shadow1);
+ Value *ShadowElt1 =
+ IRB.CreateICmpNE(ShadowElt0, getCleanShadow(ShadowElt0));
+
+ Value *Shadow = PoisonValue::get(getShadowTy(&I));
+ Shadow = IRB.CreateInsertValue(Shadow, ShadowElt0, 0);
+ Shadow = IRB.CreateInsertValue(Shadow, ShadowElt1, 1);
+
+ setShadow(&I, Shadow);
+ setOriginForNaryOp(I);
+ }
+
void visitIntrinsicInst(IntrinsicInst &I) {
switch (I.getIntrinsicID()) {
+ case Intrinsic::uadd_with_overflow:
+ case Intrinsic::sadd_with_overflow:
+ case Intrinsic::usub_with_overflow:
+ case Intrinsic::ssub_with_overflow:
+ case Intrinsic::umul_with_overflow:
+ case Intrinsic::smul_with_overflow:
+ handleArithmeticWithOverflow(I);
+ break;
case Intrinsic::abs:
handleAbsIntrinsic(I);
break;
diff --git a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
index 6a2dae5bab68..ac106e4aa2a3 100644
--- a/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
+++ b/llvm/lib/Transforms/Utils/CodeMoverUtils.cpp
@@ -336,9 +336,22 @@ bool llvm::isSafeToMoveBefore(Instruction &I, Instruction &InsertPoint,
if (isReachedBefore(&I, &InsertPoint, &DT, PDT))
for (const Use &U : I.uses())
- if (auto *UserInst = dyn_cast<Instruction>(U.getUser()))
- if (UserInst != &InsertPoint && !DT.dominates(&InsertPoint, U))
+ if (auto *UserInst = dyn_cast<Instruction>(U.getUser())) {
+ // If InsertPoint is in a BB that comes after I, then we cannot move if
+ // I is used in the terminator of the current BB.
+ if (I.getParent() == InsertPoint.getParent() &&
+ UserInst == I.getParent()->getTerminator())
return false;
+ if (UserInst != &InsertPoint && !DT.dominates(&InsertPoint, U)) {
+ // If UserInst is an instruction that appears later in the same BB as
+ // I, then it is okay to move since I will still be available when
+ // UserInst is executed.
+ if (CheckForEntireBlock && I.getParent() == UserInst->getParent() &&
+ DT.dominates(&I, UserInst))
+ continue;
+ return false;
+ }
+ }
if (isReachedBefore(&InsertPoint, &I, &DT, PDT))
for (const Value *Op : I.operands())
if (auto *OpInst = dyn_cast<Instruction>(Op)) {
diff --git a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
index c3dcf73b0b76..4ac719af6029 100644
--- a/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
+++ b/llvm/lib/Transforms/Vectorize/SLPVectorizer.cpp
@@ -2325,19 +2325,17 @@ public:
~BoUpSLP();
private:
- /// Determine if a vectorized value \p V in can be demoted to
- /// a smaller type with a truncation. We collect the values that will be
- /// demoted in ToDemote and additional roots that require investigating in
- /// Roots.
- /// \param DemotedConsts list of Instruction/OperandIndex pairs that are
- /// constant and to be demoted. Required to correctly identify constant nodes
- /// to be demoted.
- bool collectValuesToDemote(
- Value *V, bool IsProfitableToDemoteRoot, unsigned &BitWidth,
- SmallVectorImpl<Value *> &ToDemote,
- DenseMap<Instruction *, SmallVector<unsigned>> &DemotedConsts,
- DenseSet<Value *> &Visited, unsigned &MaxDepthLevel,
- bool &IsProfitableToDemote, bool IsTruncRoot) const;
+ /// Determine if a node \p E in can be demoted to a smaller type with a
+ /// truncation. We collect the entries that will be demoted in ToDemote.
+ /// \param E Node for analysis
+ /// \param ToDemote indices of the nodes to be demoted.
+ bool collectValuesToDemote(const TreeEntry &E, bool IsProfitableToDemoteRoot,
+ unsigned &BitWidth,
+ SmallVectorImpl<unsigned> &ToDemote,
+ DenseSet<const TreeEntry *> &Visited,
+ unsigned &MaxDepthLevel,
+ bool &IsProfitableToDemote,
+ bool IsTruncRoot) const;
/// Check if the operands on the edges \p Edges of the \p UserTE allows
/// reordering (i.e. the operands can be reordered because they have only one
@@ -2997,6 +2995,15 @@ private:
return ScalarToTreeEntry.lookup(V);
}
+ /// Check that the operand node of alternate node does not generate
+ /// buildvector sequence. If it is, then probably not worth it to build
+ /// alternate shuffle, if number of buildvector operands + alternate
+ /// instruction > than the number of buildvector instructions.
+ /// \param S the instructions state of the analyzed values.
+ /// \param VL list of the instructions with alternate opcodes.
+ bool areAltOperandsProfitable(const InstructionsState &S,
+ ArrayRef<Value *> VL) const;
+
/// Checks if the specified list of the instructions/values can be vectorized
/// and fills required data before actual scheduling of the instructions.
TreeEntry::EntryState getScalarsVectorizationState(
@@ -5779,6 +5786,117 @@ static bool isAlternateInstruction(const Instruction *I,
const Instruction *AltOp,
const TargetLibraryInfo &TLI);
+bool BoUpSLP::areAltOperandsProfitable(const InstructionsState &S,
+ ArrayRef<Value *> VL) const {
+ unsigned Opcode0 = S.getOpcode();
+ unsigned Opcode1 = S.getAltOpcode();
+ // The opcode mask selects between the two opcodes.
+ SmallBitVector OpcodeMask(VL.size(), false);
+ for (unsigned Lane : seq<unsigned>(0, VL.size()))
+ if (cast<Instruction>(VL[Lane])->getOpcode() == Opcode1)
+ OpcodeMask.set(Lane);
+ // If this pattern is supported by the target then consider it profitable.
+ if (TTI->isLegalAltInstr(FixedVectorType::get(S.MainOp->getType(), VL.size()),
+ Opcode0, Opcode1, OpcodeMask))
+ return true;
+ SmallVector<ValueList> Operands;
+ for (unsigned I : seq<unsigned>(0, S.MainOp->getNumOperands())) {
+ Operands.emplace_back();
+ // Prepare the operand vector.
+ for (Value *V : VL)
+ Operands.back().push_back(cast<Instruction>(V)->getOperand(I));
+ }
+ if (Operands.size() == 2) {
+ // Try find best operands candidates.
+ for (unsigned I : seq<unsigned>(0, VL.size() - 1)) {
+ SmallVector<std::pair<Value *, Value *>> Candidates(3);
+ Candidates[0] = std::make_pair(Operands[0][I], Operands[0][I + 1]);
+ Candidates[1] = std::make_pair(Operands[0][I], Operands[1][I + 1]);
+ Candidates[2] = std::make_pair(Operands[1][I], Operands[0][I + 1]);
+ std::optional<int> Res = findBestRootPair(Candidates);
+ switch (Res.value_or(0)) {
+ case 0:
+ break;
+ case 1:
+ std::swap(Operands[0][I + 1], Operands[1][I + 1]);
+ break;
+ case 2:
+ std::swap(Operands[0][I], Operands[1][I]);
+ break;
+ default:
+ llvm_unreachable("Unexpected index.");
+ }
+ }
+ }
+ DenseSet<unsigned> UniqueOpcodes;
+ constexpr unsigned NumAltInsts = 3; // main + alt + shuffle.
+ unsigned NonInstCnt = 0;
+ // Estimate number of instructions, required for the vectorized node and for
+ // the buildvector node.
+ unsigned UndefCnt = 0;
+ // Count the number of extra shuffles, required for vector nodes.
+ unsigned ExtraShuffleInsts = 0;
+ // Check that operands do not contain same values and create either perfect
+ // diamond match or shuffled match.
+ if (Operands.size() == 2) {
+ // Do not count same operands twice.
+ if (Operands.front() == Operands.back()) {
+ Operands.erase(Operands.begin());
+ } else if (!allConstant(Operands.front()) &&
+ all_of(Operands.front(), [&](Value *V) {
+ return is_contained(Operands.back(), V);
+ })) {
+ Operands.erase(Operands.begin());
+ ++ExtraShuffleInsts;
+ }
+ }
+ const Loop *L = LI->getLoopFor(S.MainOp->getParent());
+ // Vectorize node, if:
+ // 1. at least single operand is constant or splat.
+ // 2. Operands have many loop invariants (the instructions are not loop
+ // invariants).
+ // 3. At least single unique operands is supposed to vectorized.
+ return none_of(Operands,
+ [&](ArrayRef<Value *> Op) {
+ if (allConstant(Op) ||
+ (!isSplat(Op) && allSameBlock(Op) && allSameType(Op) &&
+ getSameOpcode(Op, *TLI).MainOp))
+ return false;
+ DenseMap<Value *, unsigned> Uniques;
+ for (Value *V : Op) {
+ if (isa<Constant, ExtractElementInst>(V) ||
+ getTreeEntry(V) || (L && L->isLoopInvariant(V))) {
+ if (isa<UndefValue>(V))
+ ++UndefCnt;
+ continue;
+ }
+ auto Res = Uniques.try_emplace(V, 0);
+ // Found first duplicate - need to add shuffle.
+ if (!Res.second && Res.first->second == 1)
+ ++ExtraShuffleInsts;
+ ++Res.first->getSecond();
+ if (auto *I = dyn_cast<Instruction>(V))
+ UniqueOpcodes.insert(I->getOpcode());
+ else if (Res.second)
+ ++NonInstCnt;
+ }
+ return none_of(Uniques, [&](const auto &P) {
+ return P.first->hasNUsesOrMore(P.second + 1) &&
+ none_of(P.first->users(), [&](User *U) {
+ return getTreeEntry(U) || Uniques.contains(U);
+ });
+ });
+ }) ||
+ // Do not vectorize node, if estimated number of vector instructions is
+ // more than estimated number of buildvector instructions. Number of
+ // vector operands is number of vector instructions + number of vector
+ // instructions for operands (buildvectors). Number of buildvector
+ // instructions is just number_of_operands * number_of_scalars.
+ (UndefCnt < (VL.size() - 1) * S.MainOp->getNumOperands() &&
+ (UniqueOpcodes.size() + NonInstCnt + ExtraShuffleInsts +
+ NumAltInsts) < S.MainOp->getNumOperands() * VL.size());
+}
+
BoUpSLP::TreeEntry::EntryState BoUpSLP::getScalarsVectorizationState(
InstructionsState &S, ArrayRef<Value *> VL, bool IsScatterVectorizeUserTE,
OrdersType &CurrentOrder, SmallVectorImpl<Value *> &PointerOps) const {
@@ -6076,6 +6194,14 @@ BoUpSLP::TreeEntry::EntryState BoUpSLP::getScalarsVectorizationState(
LLVM_DEBUG(dbgs() << "SLP: ShuffleVector are not vectorized.\n");
return TreeEntry::NeedToGather;
}
+ if (!areAltOperandsProfitable(S, VL)) {
+ LLVM_DEBUG(
+ dbgs()
+ << "SLP: ShuffleVector not vectorized, operands are buildvector and "
+ "the whole alt sequence is not profitable.\n");
+ return TreeEntry::NeedToGather;
+ }
+
return TreeEntry::Vectorize;
}
default:
@@ -10738,9 +10864,13 @@ Instruction &BoUpSLP::getLastInstructionInBundle(const TreeEntry *E) {
[](Value *V) {
return !isa<GetElementPtrInst>(V) && isa<Instruction>(V);
})) ||
- all_of(E->Scalars, [](Value *V) {
- return !isVectorLikeInstWithConstOps(V) && isUsedOutsideBlock(V);
- }))
+ all_of(E->Scalars,
+ [](Value *V) {
+ return !isVectorLikeInstWithConstOps(V) &&
+ isUsedOutsideBlock(V);
+ }) ||
+ (E->State == TreeEntry::NeedToGather && E->Idx == 0 &&
+ all_of(E->Scalars, IsaPred<ExtractElementInst, UndefValue>)))
Res.second = FindLastInst();
else
Res.second = FindFirstInst();
@@ -14126,20 +14256,17 @@ unsigned BoUpSLP::getVectorElementSize(Value *V) {
return Width;
}
-// Determine if a value V in a vectorizable expression Expr can be demoted to a
-// smaller type with a truncation. We collect the values that will be demoted
-// in ToDemote and additional roots that require investigating in Roots.
bool BoUpSLP::collectValuesToDemote(
- Value *V, bool IsProfitableToDemoteRoot, unsigned &BitWidth,
- SmallVectorImpl<Value *> &ToDemote,
- DenseMap<Instruction *, SmallVector<unsigned>> &DemotedConsts,
- DenseSet<Value *> &Visited, unsigned &MaxDepthLevel,
- bool &IsProfitableToDemote, bool IsTruncRoot) const {
+ const TreeEntry &E, bool IsProfitableToDemoteRoot, unsigned &BitWidth,
+ SmallVectorImpl<unsigned> &ToDemote, DenseSet<const TreeEntry *> &Visited,
+ unsigned &MaxDepthLevel, bool &IsProfitableToDemote,
+ bool IsTruncRoot) const {
// We can always demote constants.
- if (isa<Constant>(V))
+ if (all_of(E.Scalars, IsaPred<Constant>))
return true;
- if (DL->getTypeSizeInBits(V->getType()) == BitWidth) {
+ unsigned OrigBitWidth = DL->getTypeSizeInBits(E.Scalars.front()->getType());
+ if (OrigBitWidth == BitWidth) {
MaxDepthLevel = 1;
return true;
}
@@ -14150,7 +14277,6 @@ bool BoUpSLP::collectValuesToDemote(
auto IsPotentiallyTruncated = [&](Value *V, unsigned &BitWidth) -> bool {
if (MultiNodeScalars.contains(V))
return false;
- uint32_t OrigBitWidth = DL->getTypeSizeInBits(V->getType());
if (OrigBitWidth > BitWidth) {
APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
if (MaskedValueIsZero(V, Mask, SimplifyQuery(*DL)))
@@ -14168,47 +14294,50 @@ bool BoUpSLP::collectValuesToDemote(
BitWidth = std::max(BitWidth, BitWidth1);
return BitWidth > 0 && OrigBitWidth >= (BitWidth * 2);
};
- auto FinalAnalysis = [&](const TreeEntry *ITE = nullptr) {
+ using namespace std::placeholders;
+ auto FinalAnalysis = [&]() {
if (!IsProfitableToDemote)
return false;
- return (ITE && ITE->UserTreeIndices.size() > 1) ||
- IsPotentiallyTruncated(V, BitWidth);
+ bool Res = all_of(
+ E.Scalars, std::bind(IsPotentiallyTruncated, _1, std::ref(BitWidth)));
+ // Gather demoted constant operands.
+ if (Res && E.State == TreeEntry::NeedToGather &&
+ all_of(E.Scalars, IsaPred<Constant>))
+ ToDemote.push_back(E.Idx);
+ return Res;
};
// TODO: improve handling of gathered values and others.
- auto *I = dyn_cast<Instruction>(V);
- const TreeEntry *ITE = I ? getTreeEntry(I) : nullptr;
- if (!ITE || !Visited.insert(I).second || MultiNodeScalars.contains(I) ||
- all_of(I->users(), [&](User *U) {
- return isa<InsertElementInst>(U) && !getTreeEntry(U);
+ if (E.State == TreeEntry::NeedToGather || !Visited.insert(&E).second ||
+ any_of(E.Scalars, [&](Value *V) {
+ return all_of(V->users(), [&](User *U) {
+ return isa<InsertElementInst>(U) && !getTreeEntry(U);
+ });
}))
return FinalAnalysis();
- if (!all_of(I->users(),
- [=](User *U) {
- return getTreeEntry(U) ||
- (UserIgnoreList && UserIgnoreList->contains(U)) ||
- (U->getType()->isSized() &&
- !U->getType()->isScalableTy() &&
- DL->getTypeSizeInBits(U->getType()) <= BitWidth);
- }) &&
- !IsPotentiallyTruncated(I, BitWidth))
+ if (any_of(E.Scalars, [&](Value *V) {
+ return !all_of(V->users(), [=](User *U) {
+ return getTreeEntry(U) ||
+ (UserIgnoreList && UserIgnoreList->contains(U)) ||
+ (U->getType()->isSized() && !U->getType()->isScalableTy() &&
+ DL->getTypeSizeInBits(U->getType()) <= BitWidth);
+ }) && !IsPotentiallyTruncated(V, BitWidth);
+ }))
return false;
- unsigned Start = 0;
- unsigned End = I->getNumOperands();
-
- auto ProcessOperands = [&](ArrayRef<Value *> Operands, bool &NeedToExit) {
+ auto ProcessOperands = [&](ArrayRef<const TreeEntry *> Operands,
+ bool &NeedToExit) {
NeedToExit = false;
unsigned InitLevel = MaxDepthLevel;
- for (Value *IncValue : Operands) {
+ for (const TreeEntry *Op : Operands) {
unsigned Level = InitLevel;
- if (!collectValuesToDemote(IncValue, IsProfitableToDemoteRoot, BitWidth,
- ToDemote, DemotedConsts, Visited, Level,
- IsProfitableToDemote, IsTruncRoot)) {
+ if (!collectValuesToDemote(*Op, IsProfitableToDemoteRoot, BitWidth,
+ ToDemote, Visited, Level, IsProfitableToDemote,
+ IsTruncRoot)) {
if (!IsProfitableToDemote)
return false;
NeedToExit = true;
- if (!FinalAnalysis(ITE))
+ if (!FinalAnalysis())
return false;
continue;
}
@@ -14220,7 +14349,6 @@ bool BoUpSLP::collectValuesToDemote(
[&](function_ref<bool(unsigned, unsigned)> Checker, bool &NeedToExit) {
// Try all bitwidth < OrigBitWidth.
NeedToExit = false;
- uint32_t OrigBitWidth = DL->getTypeSizeInBits(I->getType());
unsigned BestFailBitwidth = 0;
for (; BitWidth < OrigBitWidth; BitWidth *= 2) {
if (Checker(BitWidth, OrigBitWidth))
@@ -14241,18 +14369,20 @@ bool BoUpSLP::collectValuesToDemote(
return false;
};
auto TryProcessInstruction =
- [&](Instruction *I, const TreeEntry &ITE, unsigned &BitWidth,
- ArrayRef<Value *> Operands = std::nullopt,
+ [&](unsigned &BitWidth,
+ ArrayRef<const TreeEntry *> Operands = std::nullopt,
function_ref<bool(unsigned, unsigned)> Checker = {}) {
if (Operands.empty()) {
if (!IsTruncRoot)
MaxDepthLevel = 1;
- (void)IsPotentiallyTruncated(V, BitWidth);
+ (void)for_each(E.Scalars, std::bind(IsPotentiallyTruncated, _1,
+ std::ref(BitWidth)));
} else {
// Several vectorized uses? Check if we can truncate it, otherwise -
// exit.
- if (ITE.UserTreeIndices.size() > 1 &&
- !IsPotentiallyTruncated(I, BitWidth))
+ if (E.UserTreeIndices.size() > 1 &&
+ !all_of(E.Scalars, std::bind(IsPotentiallyTruncated, _1,
+ std::ref(BitWidth))))
return false;
bool NeedToExit = false;
if (Checker && !AttemptCheckBitwidth(Checker, NeedToExit))
@@ -14266,26 +14396,22 @@ bool BoUpSLP::collectValuesToDemote(
}
++MaxDepthLevel;
- // Gather demoted constant operands.
- for (unsigned Idx : seq<unsigned>(Start, End))
- if (isa<Constant>(I->getOperand(Idx)))
- DemotedConsts.try_emplace(I).first->getSecond().push_back(Idx);
- // Record the value that we can demote.
- ToDemote.push_back(V);
+ // Record the entry that we can demote.
+ ToDemote.push_back(E.Idx);
return IsProfitableToDemote;
};
- switch (I->getOpcode()) {
+ switch (E.getOpcode()) {
// We can always demote truncations and extensions. Since truncations can
// seed additional demotion, we save the truncated value.
case Instruction::Trunc:
if (IsProfitableToDemoteRoot)
IsProfitableToDemote = true;
- return TryProcessInstruction(I, *ITE, BitWidth);
+ return TryProcessInstruction(BitWidth);
case Instruction::ZExt:
case Instruction::SExt:
IsProfitableToDemote = true;
- return TryProcessInstruction(I, *ITE, BitWidth);
+ return TryProcessInstruction(BitWidth);
// We can demote certain binary operations if we can demote both of their
// operands.
@@ -14295,112 +14421,128 @@ bool BoUpSLP::collectValuesToDemote(
case Instruction::And:
case Instruction::Or:
case Instruction::Xor: {
- return TryProcessInstruction(I, *ITE, BitWidth,
- {I->getOperand(0), I->getOperand(1)});
+ return TryProcessInstruction(
+ BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)});
}
case Instruction::Shl: {
// If we are truncating the result of this SHL, and if it's a shift of an
// inrange amount, we can always perform a SHL in a smaller type.
auto ShlChecker = [&](unsigned BitWidth, unsigned) {
- KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
- return AmtKnownBits.getMaxValue().ult(BitWidth);
+ return all_of(E.Scalars, [&](Value *V) {
+ auto *I = cast<Instruction>(V);
+ KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
+ return AmtKnownBits.getMaxValue().ult(BitWidth);
+ });
};
return TryProcessInstruction(
- I, *ITE, BitWidth, {I->getOperand(0), I->getOperand(1)}, ShlChecker);
+ BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)}, ShlChecker);
}
case Instruction::LShr: {
// If this is a truncate of a logical shr, we can truncate it to a smaller
// lshr iff we know that the bits we would otherwise be shifting in are
// already zeros.
auto LShrChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
- KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
- APInt ShiftedBits = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
- return AmtKnownBits.getMaxValue().ult(BitWidth) &&
- MaskedValueIsZero(I->getOperand(0), ShiftedBits,
- SimplifyQuery(*DL));
+ return all_of(E.Scalars, [&](Value *V) {
+ auto *I = cast<Instruction>(V);
+ KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
+ APInt ShiftedBits = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
+ return AmtKnownBits.getMaxValue().ult(BitWidth) &&
+ MaskedValueIsZero(I->getOperand(0), ShiftedBits,
+ SimplifyQuery(*DL));
+ });
};
return TryProcessInstruction(
- I, *ITE, BitWidth, {I->getOperand(0), I->getOperand(1)}, LShrChecker);
+ BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)},
+ LShrChecker);
}
case Instruction::AShr: {
// If this is a truncate of an arithmetic shr, we can truncate it to a
// smaller ashr iff we know that all the bits from the sign bit of the
// original type and the sign bit of the truncate type are similar.
auto AShrChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
- KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
- unsigned ShiftedBits = OrigBitWidth - BitWidth;
- return AmtKnownBits.getMaxValue().ult(BitWidth) &&
- ShiftedBits <
- ComputeNumSignBits(I->getOperand(0), *DL, 0, AC, nullptr, DT);
+ return all_of(E.Scalars, [&](Value *V) {
+ auto *I = cast<Instruction>(V);
+ KnownBits AmtKnownBits = computeKnownBits(I->getOperand(1), *DL);
+ unsigned ShiftedBits = OrigBitWidth - BitWidth;
+ return AmtKnownBits.getMaxValue().ult(BitWidth) &&
+ ShiftedBits < ComputeNumSignBits(I->getOperand(0), *DL, 0, AC,
+ nullptr, DT);
+ });
};
return TryProcessInstruction(
- I, *ITE, BitWidth, {I->getOperand(0), I->getOperand(1)}, AShrChecker);
+ BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)},
+ AShrChecker);
}
case Instruction::UDiv:
case Instruction::URem: {
// UDiv and URem can be truncated if all the truncated bits are zero.
auto Checker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
assert(BitWidth <= OrigBitWidth && "Unexpected bitwidths!");
- APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
- return MaskedValueIsZero(I->getOperand(0), Mask, SimplifyQuery(*DL)) &&
- MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL));
+ return all_of(E.Scalars, [&](Value *V) {
+ auto *I = cast<Instruction>(V);
+ APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
+ return MaskedValueIsZero(I->getOperand(0), Mask, SimplifyQuery(*DL)) &&
+ MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL));
+ });
};
- return TryProcessInstruction(I, *ITE, BitWidth,
- {I->getOperand(0), I->getOperand(1)}, Checker);
+ return TryProcessInstruction(
+ BitWidth, {getOperandEntry(&E, 0), getOperandEntry(&E, 1)}, Checker);
}
// We can demote selects if we can demote their true and false values.
case Instruction::Select: {
- Start = 1;
- auto *SI = cast<SelectInst>(I);
- return TryProcessInstruction(I, *ITE, BitWidth,
- {SI->getTrueValue(), SI->getFalseValue()});
+ return TryProcessInstruction(
+ BitWidth, {getOperandEntry(&E, 1), getOperandEntry(&E, 2)});
}
// We can demote phis if we can demote all their incoming operands. Note that
// we don't need to worry about cycles since we ensure single use above.
case Instruction::PHI: {
- PHINode *PN = cast<PHINode>(I);
- SmallVector<Value *> Ops(PN->incoming_values().begin(),
- PN->incoming_values().end());
- return TryProcessInstruction(I, *ITE, BitWidth, Ops);
+ const unsigned NumOps = E.getNumOperands();
+ SmallVector<const TreeEntry *> Ops(NumOps);
+ transform(seq<unsigned>(0, NumOps), Ops.begin(),
+ std::bind(&BoUpSLP::getOperandEntry, this, &E, _1));
+
+ return TryProcessInstruction(BitWidth, Ops);
}
case Instruction::Call: {
- auto *IC = dyn_cast<IntrinsicInst>(I);
+ auto *IC = dyn_cast<IntrinsicInst>(E.getMainOp());
if (!IC)
break;
Intrinsic::ID ID = getVectorIntrinsicIDForCall(IC, TLI);
if (ID != Intrinsic::abs && ID != Intrinsic::smin &&
ID != Intrinsic::smax && ID != Intrinsic::umin && ID != Intrinsic::umax)
break;
- SmallVector<Value *> Operands(1, I->getOperand(0));
+ SmallVector<const TreeEntry *, 2> Operands(1, getOperandEntry(&E, 0));
function_ref<bool(unsigned, unsigned)> CallChecker;
auto CompChecker = [&](unsigned BitWidth, unsigned OrigBitWidth) {
assert(BitWidth <= OrigBitWidth && "Unexpected bitwidths!");
- if (ID == Intrinsic::umin || ID == Intrinsic::umax) {
- APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
- return MaskedValueIsZero(I->getOperand(0), Mask, SimplifyQuery(*DL)) &&
- MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL));
- }
- assert((ID == Intrinsic::smin || ID == Intrinsic::smax) &&
- "Expected min/max intrinsics only.");
- unsigned SignBits = OrigBitWidth - BitWidth;
- return SignBits <= ComputeNumSignBits(I->getOperand(0), *DL, 0, AC,
- nullptr, DT) &&
- SignBits <=
- ComputeNumSignBits(I->getOperand(1), *DL, 0, AC, nullptr, DT);
+ return all_of(E.Scalars, [&](Value *V) {
+ auto *I = cast<Instruction>(V);
+ if (ID == Intrinsic::umin || ID == Intrinsic::umax) {
+ APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, BitWidth);
+ return MaskedValueIsZero(I->getOperand(0), Mask,
+ SimplifyQuery(*DL)) &&
+ MaskedValueIsZero(I->getOperand(1), Mask, SimplifyQuery(*DL));
+ }
+ assert((ID == Intrinsic::smin || ID == Intrinsic::smax) &&
+ "Expected min/max intrinsics only.");
+ unsigned SignBits = OrigBitWidth - BitWidth;
+ return SignBits <= ComputeNumSignBits(I->getOperand(0), *DL, 0, AC,
+ nullptr, DT) &&
+ SignBits <= ComputeNumSignBits(I->getOperand(1), *DL, 0, AC,
+ nullptr, DT);
+ });
};
- End = 1;
if (ID != Intrinsic::abs) {
- Operands.push_back(I->getOperand(1));
- End = 2;
+ Operands.push_back(getOperandEntry(&E, 1));
CallChecker = CompChecker;
}
InstructionCost BestCost =
std::numeric_limits<InstructionCost::CostType>::max();
unsigned BestBitWidth = BitWidth;
- unsigned VF = ITE->Scalars.size();
+ unsigned VF = E.Scalars.size();
// Choose the best bitwidth based on cost estimations.
auto Checker = [&](unsigned BitWidth, unsigned) {
unsigned MinBW = PowerOf2Ceil(BitWidth);
@@ -14419,7 +14561,7 @@ bool BoUpSLP::collectValuesToDemote(
[[maybe_unused]] bool NeedToExit;
(void)AttemptCheckBitwidth(Checker, NeedToExit);
BitWidth = BestBitWidth;
- return TryProcessInstruction(I, *ITE, BitWidth, Operands, CallChecker);
+ return TryProcessInstruction(BitWidth, Operands, CallChecker);
}
// Otherwise, conservatively give up.
@@ -14473,26 +14615,27 @@ void BoUpSLP::computeMinimumValueSizes() {
++NodeIdx;
}
- // Analyzed in reduction already and not profitable - exit.
+ // Analyzed the reduction already and not profitable - exit.
if (AnalyzedMinBWVals.contains(VectorizableTree[NodeIdx]->Scalars.front()))
return;
- SmallVector<Value *> ToDemote;
- DenseMap<Instruction *, SmallVector<unsigned>> DemotedConsts;
- auto ComputeMaxBitWidth = [&](ArrayRef<Value *> TreeRoot, unsigned VF,
- bool IsTopRoot, bool IsProfitableToDemoteRoot,
- unsigned Opcode, unsigned Limit,
- bool IsTruncRoot, bool IsSignedCmp) {
+ SmallVector<unsigned> ToDemote;
+ auto ComputeMaxBitWidth = [&](const TreeEntry &E, bool IsTopRoot,
+ bool IsProfitableToDemoteRoot, unsigned Opcode,
+ unsigned Limit, bool IsTruncRoot,
+ bool IsSignedCmp) {
ToDemote.clear();
- auto *TreeRootIT = dyn_cast<IntegerType>(TreeRoot[0]->getType());
+ unsigned VF = E.getVectorFactor();
+ auto *TreeRootIT = dyn_cast<IntegerType>(E.Scalars.front()->getType());
if (!TreeRootIT || !Opcode)
return 0u;
- if (AnalyzedMinBWVals.contains(TreeRoot.front()))
+ if (any_of(E.Scalars,
+ [&](Value *V) { return AnalyzedMinBWVals.contains(V); }))
return 0u;
- unsigned NumParts = TTI->getNumberOfParts(
- FixedVectorType::get(TreeRoot.front()->getType(), VF));
+ unsigned NumParts =
+ TTI->getNumberOfParts(FixedVectorType::get(TreeRootIT, VF));
// The maximum bit width required to represent all the values that can be
// demoted without loss of precision. It would be safe to truncate the roots
@@ -14505,14 +14648,14 @@ void BoUpSLP::computeMinimumValueSizes() {
// True.
// Determine if the sign bit of all the roots is known to be zero. If not,
// IsKnownPositive is set to False.
- bool IsKnownPositive = !IsSignedCmp && all_of(TreeRoot, [&](Value *R) {
+ bool IsKnownPositive = !IsSignedCmp && all_of(E.Scalars, [&](Value *R) {
KnownBits Known = computeKnownBits(R, *DL);
return Known.isNonNegative();
});
// We first check if all the bits of the roots are demanded. If they're not,
// we can truncate the roots to this narrower type.
- for (auto *Root : TreeRoot) {
+ for (Value *Root : E.Scalars) {
unsigned NumSignBits = ComputeNumSignBits(Root, *DL, 0, AC, nullptr, DT);
TypeSize NumTypeBits = DL->getTypeSizeInBits(Root->getType());
unsigned BitWidth1 = NumTypeBits - NumSignBits;
@@ -14557,23 +14700,22 @@ void BoUpSLP::computeMinimumValueSizes() {
// Conservatively determine if we can actually truncate the roots of the
// expression. Collect the values that can be demoted in ToDemote and
// additional roots that require investigating in Roots.
- for (auto *Root : TreeRoot) {
- DenseSet<Value *> Visited;
- unsigned MaxDepthLevel = IsTruncRoot ? Limit : 1;
- bool NeedToDemote = IsProfitableToDemote;
-
- if (!collectValuesToDemote(Root, IsProfitableToDemoteRoot, MaxBitWidth,
- ToDemote, DemotedConsts, Visited,
- MaxDepthLevel, NeedToDemote, IsTruncRoot) ||
- (MaxDepthLevel <= Limit &&
- !(((Opcode == Instruction::SExt || Opcode == Instruction::ZExt) &&
- (!IsTopRoot || !(IsStoreOrInsertElt || UserIgnoreList) ||
- DL->getTypeSizeInBits(Root->getType()) /
- DL->getTypeSizeInBits(
- cast<Instruction>(Root)->getOperand(0)->getType()) >
- 2)))))
- return 0u;
- }
+ DenseSet<const TreeEntry *> Visited;
+ unsigned MaxDepthLevel = IsTruncRoot ? Limit : 1;
+ bool NeedToDemote = IsProfitableToDemote;
+
+ if (!collectValuesToDemote(E, IsProfitableToDemoteRoot, MaxBitWidth,
+ ToDemote, Visited, MaxDepthLevel, NeedToDemote,
+ IsTruncRoot) ||
+ (MaxDepthLevel <= Limit &&
+ !(((Opcode == Instruction::SExt || Opcode == Instruction::ZExt) &&
+ (!IsTopRoot || !(IsStoreOrInsertElt || UserIgnoreList) ||
+ DL->getTypeSizeInBits(TreeRootIT) /
+ DL->getTypeSizeInBits(cast<Instruction>(E.Scalars.front())
+ ->getOperand(0)
+ ->getType()) >
+ 2)))))
+ return 0u;
// Round MaxBitWidth up to the next power-of-two.
MaxBitWidth = bit_ceil(MaxBitWidth);
@@ -14624,8 +14766,8 @@ void BoUpSLP::computeMinimumValueSizes() {
VectorizableTree.front()->Scalars.front()->getType()))
Limit = 3;
unsigned MaxBitWidth = ComputeMaxBitWidth(
- TreeRoot, VectorizableTree[NodeIdx]->getVectorFactor(), IsTopRoot,
- IsProfitableToDemoteRoot, Opcode, Limit, IsTruncRoot, IsSignedCmp);
+ *VectorizableTree[NodeIdx].get(), IsTopRoot, IsProfitableToDemoteRoot,
+ Opcode, Limit, IsTruncRoot, IsSignedCmp);
if (ReductionBitWidth != 0 && (IsTopRoot || !RootDemotes.empty())) {
if (MaxBitWidth != 0 && ReductionBitWidth < MaxBitWidth)
ReductionBitWidth = bit_ceil(MaxBitWidth);
@@ -14634,13 +14776,15 @@ void BoUpSLP::computeMinimumValueSizes() {
}
for (unsigned Idx : RootDemotes) {
- Value *V = VectorizableTree[Idx]->Scalars.front();
- uint32_t OrigBitWidth = DL->getTypeSizeInBits(V->getType());
- if (OrigBitWidth > MaxBitWidth) {
- APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, MaxBitWidth);
- if (MaskedValueIsZero(V, Mask, SimplifyQuery(*DL)))
- ToDemote.push_back(V);
- }
+ if (all_of(VectorizableTree[Idx]->Scalars, [&](Value *V) {
+ uint32_t OrigBitWidth = DL->getTypeSizeInBits(V->getType());
+ if (OrigBitWidth > MaxBitWidth) {
+ APInt Mask = APInt::getBitsSetFrom(OrigBitWidth, MaxBitWidth);
+ return MaskedValueIsZero(V, Mask, SimplifyQuery(*DL));
+ }
+ return false;
+ }))
+ ToDemote.push_back(Idx);
}
RootDemotes.clear();
IsTopRoot = false;
@@ -14687,9 +14831,8 @@ void BoUpSLP::computeMinimumValueSizes() {
// Finally, map the values we can demote to the maximum bit with we
// computed.
- for (Value *Scalar : ToDemote) {
- TreeEntry *TE = getTreeEntry(Scalar);
- assert(TE && "Expected vectorized scalar.");
+ for (unsigned Idx : ToDemote) {
+ TreeEntry *TE = VectorizableTree[Idx].get();
if (MinBWs.contains(TE))
continue;
bool IsSigned = TE->getOpcode() == Instruction::SExt ||
@@ -14697,22 +14840,6 @@ void BoUpSLP::computeMinimumValueSizes() {
return !isKnownNonNegative(R, SimplifyQuery(*DL));
});
MinBWs.try_emplace(TE, MaxBitWidth, IsSigned);
- const auto *I = cast<Instruction>(Scalar);
- auto DCIt = DemotedConsts.find(I);
- if (DCIt != DemotedConsts.end()) {
- for (unsigned Idx : DCIt->getSecond()) {
- // Check that all instructions operands are demoted.
- const TreeEntry *CTE = getOperandEntry(TE, Idx);
- if (all_of(TE->Scalars,
- [&](Value *V) {
- auto SIt = DemotedConsts.find(cast<Instruction>(V));
- return SIt != DemotedConsts.end() &&
- is_contained(SIt->getSecond(), Idx);
- }) ||
- all_of(CTE->Scalars, IsaPred<Constant>))
- MinBWs.try_emplace(CTE, MaxBitWidth, IsSigned);
- }
- }
}
}
}
diff --git a/llvm/test/Analysis/CostModel/RISCV/active_lane_mask.ll b/llvm/test/Analysis/CostModel/RISCV/active_lane_mask.ll
index ba62056f5851..7ebe14d98b21 100644
--- a/llvm/test/Analysis/CostModel/RISCV/active_lane_mask.ll
+++ b/llvm/test/Analysis/CostModel/RISCV/active_lane_mask.ll
@@ -3,28 +3,28 @@
define void @get_lane_mask() {
; CHECK-LABEL: 'get_lane_mask'
-; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %mask_nxv16i1_i64 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %mask_nxv8i1_i64 = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %mask_nxv4i1_i64 = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %mask_nxv2i1_i64 = call <vscale x 2 x i1> @llvm.get.active.lane.mask.nxv2i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_nxv1i1_i64 = call <vscale x 1 x i1> @llvm.get.active.lane.mask.nxv1i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %mask_nxv16i1_i32 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %mask_nxv8i1_i32 = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %mask_nxv4i1_i32 = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_nxv2i1_i32 = call <vscale x 2 x i1> @llvm.get.active.lane.mask.nxv2i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_nxv1i1_i32 = call <vscale x 1 x i1> @llvm.get.active.lane.mask.nxv1i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 44 for instruction: %mask_nxv32i1_i64 = call <vscale x 32 x i1> @llvm.get.active.lane.mask.nxv32i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %mask_nxv16i1_i16 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i16(i16 undef, i16 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 11 for instruction: %mask_v16i1_i64 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %mask_v8i1_i64 = call <8 x i1> @llvm.get.active.lane.mask.v8i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %mask_v4i1_i64 = call <4 x i1> @llvm.get.active.lane.mask.v4i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v2i1_i64 = call <2 x i1> @llvm.get.active.lane.mask.v2i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 7 for instruction: %mask_v16i1_i32 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %mask_v8i1_i32 = call <8 x i1> @llvm.get.active.lane.mask.v8i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v4i1_i32 = call <4 x i1> @llvm.get.active.lane.mask.v4i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v2i1_i32 = call <2 x i1> @llvm.get.active.lane.mask.v2i1.i32(i32 undef, i32 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 22 for instruction: %mask_v32i1_i64 = call <32 x i1> @llvm.get.active.lane.mask.v32i1.i64(i64 undef, i64 undef)
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %mask_v16i1_i16 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i16(i16 undef, i16 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 32 for instruction: %mask_nxv16i1_i64 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %mask_nxv8i1_i64 = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %mask_nxv4i1_i64 = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_nxv2i1_i64 = call <vscale x 2 x i1> @llvm.get.active.lane.mask.nxv2i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_nxv1i1_i64 = call <vscale x 1 x i1> @llvm.get.active.lane.mask.nxv1i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %mask_nxv16i1_i32 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %mask_nxv8i1_i32 = call <vscale x 8 x i1> @llvm.get.active.lane.mask.nxv8i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_nxv4i1_i32 = call <vscale x 4 x i1> @llvm.get.active.lane.mask.nxv4i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_nxv2i1_i32 = call <vscale x 2 x i1> @llvm.get.active.lane.mask.nxv2i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_nxv1i1_i32 = call <vscale x 1 x i1> @llvm.get.active.lane.mask.nxv1i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 64 for instruction: %mask_nxv32i1_i64 = call <vscale x 32 x i1> @llvm.get.active.lane.mask.nxv32i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %mask_nxv16i1_i16 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i16(i16 undef, i16 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %mask_v16i1_i64 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %mask_v8i1_i64 = call <8 x i1> @llvm.get.active.lane.mask.v8i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v4i1_i64 = call <4 x i1> @llvm.get.active.lane.mask.v4i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_v2i1_i64 = call <2 x i1> @llvm.get.active.lane.mask.v2i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %mask_v16i1_i32 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v8i1_i32 = call <8 x i1> @llvm.get.active.lane.mask.v8i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_v4i1_i32 = call <4 x i1> @llvm.get.active.lane.mask.v4i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %mask_v2i1_i32 = call <2 x i1> @llvm.get.active.lane.mask.v2i1.i32(i32 undef, i32 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 32 for instruction: %mask_v32i1_i64 = call <32 x i1> @llvm.get.active.lane.mask.v32i1.i64(i64 undef, i64 undef)
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %mask_v16i1_i16 = call <16 x i1> @llvm.get.active.lane.mask.v16i1.i16(i16 undef, i16 undef)
; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void
;
%mask_nxv16i1_i64 = call <vscale x 16 x i1> @llvm.get.active.lane.mask.nxv16i1.i64(i64 undef, i64 undef)
diff --git a/llvm/test/Analysis/CostModel/RISCV/rvv-select.ll b/llvm/test/Analysis/CostModel/RISCV/rvv-select.ll
index 264a74116449..6dcbc73674aa 100644
--- a/llvm/test/Analysis/CostModel/RISCV/rvv-select.ll
+++ b/llvm/test/Analysis/CostModel/RISCV/rvv-select.ll
@@ -22,14 +22,14 @@ define void @select() {
; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %15 = select i1 undef, <vscale x 2 x i1> undef, <vscale x 2 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %16 = select i1 undef, <vscale x 4 x i1> undef, <vscale x 4 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %17 = select i1 undef, <vscale x 8 x i1> undef, <vscale x 8 x i1> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %18 = select i1 undef, <vscale x 16 x i1> undef, <vscale x 16 x i1> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 5 for instruction: %19 = select i1 undef, <vscale x 32 x i1> undef, <vscale x 32 x i1> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 10 for instruction: %18 = select i1 undef, <vscale x 16 x i1> undef, <vscale x 16 x i1> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 20 for instruction: %19 = select i1 undef, <vscale x 32 x i1> undef, <vscale x 32 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %20 = select <vscale x 1 x i1> undef, <vscale x 1 x i1> undef, <vscale x 1 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %21 = select <vscale x 2 x i1> undef, <vscale x 2 x i1> undef, <vscale x 2 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %22 = select <vscale x 4 x i1> undef, <vscale x 4 x i1> undef, <vscale x 4 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %23 = select <vscale x 8 x i1> undef, <vscale x 8 x i1> undef, <vscale x 8 x i1> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %24 = select <vscale x 16 x i1> undef, <vscale x 16 x i1> undef, <vscale x 16 x i1> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %25 = select <vscale x 32 x i1> undef, <vscale x 32 x i1> undef, <vscale x 32 x i1> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %24 = select <vscale x 16 x i1> undef, <vscale x 16 x i1> undef, <vscale x 16 x i1> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %25 = select <vscale x 32 x i1> undef, <vscale x 32 x i1> undef, <vscale x 32 x i1> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %26 = select i1 undef, i8 undef, i8 undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %27 = select i1 undef, <1 x i8> undef, <1 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %28 = select i1 undef, <2 x i8> undef, <2 x i8> undef
@@ -47,14 +47,14 @@ define void @select() {
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %40 = select i1 undef, <vscale x 2 x i8> undef, <vscale x 2 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %41 = select i1 undef, <vscale x 4 x i8> undef, <vscale x 4 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %42 = select i1 undef, <vscale x 8 x i8> undef, <vscale x 8 x i8> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %43 = select i1 undef, <vscale x 16 x i8> undef, <vscale x 16 x i8> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %44 = select i1 undef, <vscale x 32 x i8> undef, <vscale x 32 x i8> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %43 = select i1 undef, <vscale x 16 x i8> undef, <vscale x 16 x i8> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %44 = select i1 undef, <vscale x 32 x i8> undef, <vscale x 32 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %45 = select <vscale x 1 x i1> undef, <vscale x 1 x i8> undef, <vscale x 1 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %46 = select <vscale x 2 x i1> undef, <vscale x 2 x i8> undef, <vscale x 2 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %47 = select <vscale x 4 x i1> undef, <vscale x 4 x i8> undef, <vscale x 4 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %48 = select <vscale x 8 x i1> undef, <vscale x 8 x i8> undef, <vscale x 8 x i8> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %49 = select <vscale x 16 x i1> undef, <vscale x 16 x i8> undef, <vscale x 16 x i8> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %50 = select <vscale x 32 x i1> undef, <vscale x 32 x i8> undef, <vscale x 32 x i8> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %49 = select <vscale x 16 x i1> undef, <vscale x 16 x i8> undef, <vscale x 16 x i8> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %50 = select <vscale x 32 x i1> undef, <vscale x 32 x i8> undef, <vscale x 32 x i8> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %51 = select i1 undef, i16 undef, i16 undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %52 = select i1 undef, <1 x i16> undef, <1 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %53 = select i1 undef, <2 x i16> undef, <2 x i16> undef
@@ -71,15 +71,15 @@ define void @select() {
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %64 = select i1 undef, <vscale x 1 x i16> undef, <vscale x 1 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %65 = select i1 undef, <vscale x 2 x i16> undef, <vscale x 2 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %66 = select i1 undef, <vscale x 4 x i16> undef, <vscale x 4 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %67 = select i1 undef, <vscale x 8 x i16> undef, <vscale x 8 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %68 = select i1 undef, <vscale x 16 x i16> undef, <vscale x 16 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %69 = select i1 undef, <vscale x 32 x i16> undef, <vscale x 32 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %67 = select i1 undef, <vscale x 8 x i16> undef, <vscale x 8 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %68 = select i1 undef, <vscale x 16 x i16> undef, <vscale x 16 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 24 for instruction: %69 = select i1 undef, <vscale x 32 x i16> undef, <vscale x 32 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %70 = select <vscale x 1 x i1> undef, <vscale x 1 x i16> undef, <vscale x 1 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %71 = select <vscale x 2 x i1> undef, <vscale x 2 x i16> undef, <vscale x 2 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %72 = select <vscale x 4 x i1> undef, <vscale x 4 x i16> undef, <vscale x 4 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %73 = select <vscale x 8 x i1> undef, <vscale x 8 x i16> undef, <vscale x 8 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %74 = select <vscale x 16 x i1> undef, <vscale x 16 x i16> undef, <vscale x 16 x i16> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %75 = select <vscale x 32 x i1> undef, <vscale x 32 x i16> undef, <vscale x 32 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %73 = select <vscale x 8 x i1> undef, <vscale x 8 x i16> undef, <vscale x 8 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %74 = select <vscale x 16 x i1> undef, <vscale x 16 x i16> undef, <vscale x 16 x i16> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %75 = select <vscale x 32 x i1> undef, <vscale x 32 x i16> undef, <vscale x 32 x i16> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %76 = select i1 undef, i32 undef, i32 undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %77 = select i1 undef, <1 x i32> undef, <1 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %78 = select i1 undef, <2 x i32> undef, <2 x i32> undef
@@ -95,16 +95,16 @@ define void @select() {
; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %88 = select <32 x i1> undef, <32 x i32> undef, <32 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %89 = select i1 undef, <vscale x 1 x i32> undef, <vscale x 1 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %90 = select i1 undef, <vscale x 2 x i32> undef, <vscale x 2 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %91 = select i1 undef, <vscale x 4 x i32> undef, <vscale x 4 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %92 = select i1 undef, <vscale x 8 x i32> undef, <vscale x 8 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %93 = select i1 undef, <vscale x 16 x i32> undef, <vscale x 16 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %94 = select i1 undef, <vscale x 32 x i32> undef, <vscale x 32 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %91 = select i1 undef, <vscale x 4 x i32> undef, <vscale x 4 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %92 = select i1 undef, <vscale x 8 x i32> undef, <vscale x 8 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 24 for instruction: %93 = select i1 undef, <vscale x 16 x i32> undef, <vscale x 16 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 48 for instruction: %94 = select i1 undef, <vscale x 32 x i32> undef, <vscale x 32 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %95 = select <vscale x 1 x i1> undef, <vscale x 1 x i32> undef, <vscale x 1 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %96 = select <vscale x 2 x i1> undef, <vscale x 2 x i32> undef, <vscale x 2 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %97 = select <vscale x 4 x i1> undef, <vscale x 4 x i32> undef, <vscale x 4 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %98 = select <vscale x 8 x i1> undef, <vscale x 8 x i32> undef, <vscale x 8 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %99 = select <vscale x 16 x i1> undef, <vscale x 16 x i32> undef, <vscale x 16 x i32> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %100 = select <vscale x 32 x i1> undef, <vscale x 32 x i32> undef, <vscale x 32 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %97 = select <vscale x 4 x i1> undef, <vscale x 4 x i32> undef, <vscale x 4 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %98 = select <vscale x 8 x i1> undef, <vscale x 8 x i32> undef, <vscale x 8 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %99 = select <vscale x 16 x i1> undef, <vscale x 16 x i32> undef, <vscale x 16 x i32> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %100 = select <vscale x 32 x i1> undef, <vscale x 32 x i32> undef, <vscale x 32 x i32> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %101 = select i1 undef, i64 undef, i64 undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %102 = select i1 undef, <1 x i64> undef, <1 x i64> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %103 = select i1 undef, <2 x i64> undef, <2 x i64> undef
@@ -119,17 +119,17 @@ define void @select() {
; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %112 = select <16 x i1> undef, <16 x i64> undef, <16 x i64> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %113 = select <32 x i1> undef, <32 x i64> undef, <32 x i64> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %114 = select i1 undef, <vscale x 1 x i64> undef, <vscale x 1 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %115 = select i1 undef, <vscale x 2 x i64> undef, <vscale x 2 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %116 = select i1 undef, <vscale x 4 x i64> undef, <vscale x 4 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 3 for instruction: %117 = select i1 undef, <vscale x 8 x i64> undef, <vscale x 8 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %118 = select i1 undef, <vscale x 16 x i64> undef, <vscale x 16 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %119 = select i1 undef, <vscale x 32 x i64> undef, <vscale x 32 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 6 for instruction: %115 = select i1 undef, <vscale x 2 x i64> undef, <vscale x 2 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 12 for instruction: %116 = select i1 undef, <vscale x 4 x i64> undef, <vscale x 4 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 24 for instruction: %117 = select i1 undef, <vscale x 8 x i64> undef, <vscale x 8 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 48 for instruction: %118 = select i1 undef, <vscale x 16 x i64> undef, <vscale x 16 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 96 for instruction: %119 = select i1 undef, <vscale x 32 x i64> undef, <vscale x 32 x i64> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %120 = select <vscale x 1 x i1> undef, <vscale x 1 x i64> undef, <vscale x 1 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %121 = select <vscale x 2 x i1> undef, <vscale x 2 x i64> undef, <vscale x 2 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %122 = select <vscale x 4 x i1> undef, <vscale x 4 x i64> undef, <vscale x 4 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 1 for instruction: %123 = select <vscale x 8 x i1> undef, <vscale x 8 x i64> undef, <vscale x 8 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %124 = select <vscale x 16 x i1> undef, <vscale x 16 x i64> undef, <vscale x 16 x i64> undef
-; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %125 = select <vscale x 32 x i1> undef, <vscale x 32 x i64> undef, <vscale x 32 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 2 for instruction: %121 = select <vscale x 2 x i1> undef, <vscale x 2 x i64> undef, <vscale x 2 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 4 for instruction: %122 = select <vscale x 4 x i1> undef, <vscale x 4 x i64> undef, <vscale x 4 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 8 for instruction: %123 = select <vscale x 8 x i1> undef, <vscale x 8 x i64> undef, <vscale x 8 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 16 for instruction: %124 = select <vscale x 16 x i1> undef, <vscale x 16 x i64> undef, <vscale x 16 x i64> undef
+; CHECK-NEXT: Cost Model: Found an estimated cost of 32 for instruction: %125 = select <vscale x 32 x i1> undef, <vscale x 32 x i64> undef, <vscale x 32 x i64> undef
; CHECK-NEXT: Cost Model: Found an estimated cost of 0 for instruction: ret void
;
select i1 undef, i1 undef, i1 undef
diff --git a/llvm/test/Analysis/ScalarEvolution/pr87798.ll b/llvm/test/Analysis/ScalarEvolution/pr87798.ll
new file mode 100644
index 000000000000..acd445993e47
--- /dev/null
+++ b/llvm/test/Analysis/ScalarEvolution/pr87798.ll
@@ -0,0 +1,68 @@
+; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -disable-output -passes='print<scalar-evolution>' -verify-scev < %s 2>&1 | FileCheck %s
+
+target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128-ni:1-p2:32:8:8:32-ni:2"
+target triple = "x86_64-unknown-linux-gnu"
+
+; print<scalar-evolution> is used to compute SCEVs for all values in the
+; function.
+; We should not crash on multiplicative inverse called within SCEV's binomial
+; coefficient function.
+
+define i32 @pr87798() {
+; CHECK-LABEL: 'pr87798'
+; CHECK-NEXT: Classifying expressions for: @pr87798
+; CHECK-NEXT: %phi = phi i32 [ 0, %bb ], [ %add4, %bb1 ]
+; CHECK-NEXT: --> {0,+,0,+,0,+,2,+,3}<%bb1> U: full-set S: full-set Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %phi2 = phi i32 [ 0, %bb ], [ %add, %bb1 ]
+; CHECK-NEXT: --> {0,+,0,+,1}<%bb1> U: full-set S: full-set Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %phi3 = phi i32 [ 0, %bb ], [ %add5, %bb1 ]
+; CHECK-NEXT: --> {0,+,1}<nuw><nsw><%bb1> U: [0,1) S: [0,1) Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %add = add i32 %phi2, %phi3
+; CHECK-NEXT: --> {0,+,1,+,1}<%bb1> U: full-set S: full-set Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %mul = mul i32 %phi2, %phi3
+; CHECK-NEXT: --> {0,+,0,+,2,+,3}<%bb1> U: full-set S: full-set Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %add4 = add i32 %mul, %phi
+; CHECK-NEXT: --> {0,+,0,+,2,+,5,+,3}<%bb1> U: full-set S: full-set Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %and = and i32 %phi, 1
+; CHECK-NEXT: --> (zext i1 {false,+,false,+,false,+,false,+,true}<%bb1> to i32) U: [0,2) S: [0,2) Exits: 0 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %add5 = add i32 %phi3, 1
+; CHECK-NEXT: --> {1,+,1}<nuw><nsw><%bb1> U: [1,2) S: [1,2) Exits: 1 LoopDispositions: { %bb1: Computable }
+; CHECK-NEXT: %phi9 = phi i32 [ %and, %bb1 ]
+; CHECK-NEXT: --> (zext i1 {false,+,false,+,false,+,false,+,true}<%bb1> to i32) U: [0,2) S: [0,2) --> 0 U: [0,1) S: [0,1)
+; CHECK-NEXT: %zext = zext i32 %phi9 to i64
+; CHECK-NEXT: --> poison U: full-set S: full-set
+; CHECK-NEXT: Determining loop execution counts for: @pr87798
+; CHECK-NEXT: Loop %loop: <multiple exits> Unpredictable backedge-taken count.
+; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count.
+; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count.
+; CHECK-NEXT: Loop %bb1: backedge-taken count is i1 false
+; CHECK-NEXT: Loop %bb1: constant max backedge-taken count is i1 false
+; CHECK-NEXT: Loop %bb1: symbolic max backedge-taken count is i1 false
+; CHECK-NEXT: Loop %bb1: Trip multiple is 1
+;
+bb:
+ br label %bb1
+
+bb1: ; preds = %bb1, %bb
+ %phi = phi i32 [ 0, %bb ], [ %add4, %bb1 ]
+ %phi2 = phi i32 [ 0, %bb ], [ %add, %bb1 ]
+ %phi3 = phi i32 [ 0, %bb ], [ %add5, %bb1 ]
+ %add = add i32 %phi2, %phi3
+ %mul = mul i32 %phi2, %phi3
+ %add4 = add i32 %mul, %phi
+ %and = and i32 %phi, 1
+ %add5 = add i32 %phi3, 1
+ br i1 true, label %preheader, label %bb1
+
+preheader: ; preds = %bb1
+ %phi9 = phi i32 [ %and, %bb1 ]
+ br label %loop
+
+loop: ; preds = %preheader, %loop
+ br label %loop
+
+bb7: ; No predecessors!
+ %zext = zext i32 %phi9 to i64
+ ret i32 0
+}
diff --git a/llvm/test/CodeGen/AArch64/lrint-conv.ll b/llvm/test/CodeGen/AArch64/lrint-conv.ll
index 80f1e8b8fc18..b61d6f04b400 100644
--- a/llvm/test/CodeGen/AArch64/lrint-conv.ll
+++ b/llvm/test/CodeGen/AArch64/lrint-conv.ll
@@ -1,64 +1,78 @@
-; RUN: llc < %s -mtriple=aarch64 -mattr=+neon | FileCheck %s
-; RUN: llc < %s -global-isel -global-isel-abort=2 -pass-remarks-missed=gisel* -mtriple=aarch64 | FileCheck %s --check-prefixes=FALLBACK,CHECK
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
+; RUN: llc < %s -mtriple=aarch64 | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64 -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+
+; CHECK-GI: warning: Instruction selection used fallback path for testmswl
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for testmsll
-; CHECK-LABEL: testmsws:
-; CHECK: frintx [[REG:s[0-9]]], s0
-; CHECK-NEXT: fcvtzs x0, [[REG]]
-; CHECK: ret
-; FALLBACK-NOT: remark{{.*}}testmsws
define i32 @testmsws(float %x) {
+; CHECK-LABEL: testmsws:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: frintx s0, s0
+; CHECK-NEXT: fcvtzs x0, s0
+; CHECK-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-NEXT: ret
entry:
%0 = tail call i64 @llvm.lrint.i64.f32(float %x)
%conv = trunc i64 %0 to i32
ret i32 %conv
}
-; CHECK-LABEL: testmsxs:
-; CHECK: frintx [[REG:s[0-9]]], s0
-; CHECK-NEXT: fcvtzs x0, [[REG]]
-; CHECK-NEXT: ret
-; FALLBACK-NOT: remark{{.*}}testmsxs
define i64 @testmsxs(float %x) {
+; CHECK-LABEL: testmsxs:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: frintx s0, s0
+; CHECK-NEXT: fcvtzs x0, s0
+; CHECK-NEXT: ret
entry:
%0 = tail call i64 @llvm.lrint.i64.f32(float %x)
ret i64 %0
}
-; CHECK-LABEL: testmswd:
-; CHECK: frintx [[REG:d[0-9]]], d0
-; CHECK-NEXT: fcvtzs x0, [[REG]]
-; CHECK: ret
-; FALLBACK-NOT: remark{{.*}}testmswd
define i32 @testmswd(double %x) {
+; CHECK-LABEL: testmswd:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: frintx d0, d0
+; CHECK-NEXT: fcvtzs x0, d0
+; CHECK-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-NEXT: ret
entry:
%0 = tail call i64 @llvm.lrint.i64.f64(double %x)
%conv = trunc i64 %0 to i32
ret i32 %conv
}
-; CHECK-LABEL: testmsxd:
-; CHECK: frintx [[REG:d[0-9]]], d0
-; CHECK-NEXT: fcvtzs x0, [[REG]]
-; CHECK-NEXT: ret
-; FALLBACK-NOT: remark{{.*}}testmsxd
define i64 @testmsxd(double %x) {
+; CHECK-LABEL: testmsxd:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: frintx d0, d0
+; CHECK-NEXT: fcvtzs x0, d0
+; CHECK-NEXT: ret
entry:
%0 = tail call i64 @llvm.lrint.i64.f64(double %x)
ret i64 %0
}
-; CHECK-LABEL: testmswl:
-; CHECK: bl lrintl
define dso_local i32 @testmswl(fp128 %x) {
+; CHECK-LABEL: testmswl:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: str x30, [sp, #-16]! // 8-byte Folded Spill
+; CHECK-NEXT: .cfi_def_cfa_offset 16
+; CHECK-NEXT: .cfi_offset w30, -16
+; CHECK-NEXT: bl lrintl
+; CHECK-NEXT: // kill: def $w0 killed $w0 killed $x0
+; CHECK-NEXT: ldr x30, [sp], #16 // 8-byte Folded Reload
+; CHECK-NEXT: ret
entry:
%0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x)
%conv = trunc i64 %0 to i32
ret i32 %conv
}
-; CHECK-LABEL: testmsll:
-; CHECK: b lrintl
define dso_local i64 @testmsll(fp128 %x) {
+; CHECK-LABEL: testmsll:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: b lrintl
entry:
%0 = tail call i64 @llvm.lrint.i64.f128(fp128 %x)
ret i64 %0
diff --git a/llvm/test/CodeGen/AArch64/sve2-bsl.ll b/llvm/test/CodeGen/AArch64/sve2-bsl.ll
new file mode 100644
index 000000000000..11f67634a3fb
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/sve2-bsl.ll
@@ -0,0 +1,28 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64-unknown-linux-gnu -mattr=+sve2 < %s | FileCheck %s --check-prefixes=CHECK
+
+define <vscale x 4 x i32> @bsl(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) {
+; CHECK-LABEL: bsl:
+; CHECK: // %bb.0:
+; CHECK-NEXT: mov z2.s, #0x7fffffff
+; CHECK-NEXT: bsl z0.d, z0.d, z1.d, z2.d
+; CHECK-NEXT: ret
+ %1 = and <vscale x 4 x i32> %a, splat(i32 2147483647)
+ %2 = and <vscale x 4 x i32> %b, splat(i32 -2147483648)
+ %c = or <vscale x 4 x i32> %1, %2
+ ret <vscale x 4 x i32> %c
+}
+
+; we are not expecting bsl instruction here. the constants do not match to fold to bsl.
+define <vscale x 4 x i32> @no_bsl_fold(<vscale x 4 x i32> %a, <vscale x 4 x i32> %b) {
+; CHECK-LABEL: no_bsl_fold:
+; CHECK: // %bb.0:
+; CHECK-NEXT: and z0.s, z0.s, #0x7fffffff
+; CHECK-NEXT: and z1.s, z1.s, #0x7ffffffe
+; CHECK-NEXT: orr z0.d, z0.d, z1.d
+; CHECK-NEXT: ret
+ %1 = and <vscale x 4 x i32> %a, splat(i32 2147483647)
+ %2 = and <vscale x 4 x i32> %b, splat(i32 2147483646)
+ %c = or <vscale x 4 x i32> %1, %2
+ ret <vscale x 4 x i32> %c
+}
diff --git a/llvm/test/CodeGen/AArch64/vector-lrint.ll b/llvm/test/CodeGen/AArch64/vector-lrint.ll
index 9c46cf69cb0b..b7fcd11ba8d1 100644
--- a/llvm/test/CodeGen/AArch64/vector-lrint.ll
+++ b/llvm/test/CodeGen/AArch64/vector-lrint.ll
@@ -1,6 +1,20 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
-; RUN: sed 's/iXLen/i32/g' %s | llc -mtriple=aarch64 -mattr=+neon | FileCheck %s
-; RUN: sed 's/iXLen/i64/g' %s | llc -mtriple=aarch64 -mattr=+neon | FileCheck %s
+; RUN: llc < %s -mtriple=aarch64 | FileCheck %s --check-prefixes=CHECK,CHECK-SD
+; RUN: llc < %s -mtriple=aarch64 -global-isel -global-isel-abort=2 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
+
+; CHECK-GI: warning: Instruction selection used fallback path for lrint_v1f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v2f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v4f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v8f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v16i64_v16f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v32i64_v32f16
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v2f32
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v4f32
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v8f32
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v16i64_v16f32
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v2f64
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v4f64
+; CHECK-GI-NEXT: warning: Instruction selection used fallback path for lrint_v8f64
define <1 x i64> @lrint_v1f16(<1 x half> %x) {
; CHECK-LABEL: lrint_v1f16:
@@ -372,13 +386,20 @@ define <32 x i64> @lrint_v32i64_v32f16(<32 x half> %x) {
declare <32 x i64> @llvm.lrint.v32i64.v32f16(<32 x half>)
define <1 x i64> @lrint_v1f32(<1 x float> %x) {
-; CHECK-LABEL: lrint_v1f32:
-; CHECK: // %bb.0:
-; CHECK-NEXT: // kill: def $d0 killed $d0 def $q0
-; CHECK-NEXT: frintx s0, s0
-; CHECK-NEXT: fcvtzs x8, s0
-; CHECK-NEXT: fmov d0, x8
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: lrint_v1f32:
+; CHECK-SD: // %bb.0:
+; CHECK-SD-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-SD-NEXT: frintx s0, s0
+; CHECK-SD-NEXT: fcvtzs x8, s0
+; CHECK-SD-NEXT: fmov d0, x8
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: lrint_v1f32:
+; CHECK-GI: // %bb.0:
+; CHECK-GI-NEXT: frintx s0, s0
+; CHECK-GI-NEXT: fcvtzs x8, s0
+; CHECK-GI-NEXT: fmov d0, x8
+; CHECK-GI-NEXT: ret
%a = call <1 x i64> @llvm.lrint.v1i64.v1f32(<1 x float> %x)
ret <1 x i64> %a
}
diff --git a/llvm/test/CodeGen/AMDGPU/insert_waitcnt_for_precise_memory.ll b/llvm/test/CodeGen/AMDGPU/insert_waitcnt_for_precise_memory.ll
new file mode 100644
index 000000000000..df03e8937037
--- /dev/null
+++ b/llvm/test/CodeGen/AMDGPU/insert_waitcnt_for_precise_memory.ll
@@ -0,0 +1,1658 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 -mattr=+precise-memory < %s | FileCheck %s -check-prefixes=GFX9
+; RUN: llc -mtriple=amdgcn -mcpu=gfx90a -mattr=+precise-memory < %s | FileCheck %s -check-prefixes=GFX90A
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1010 -mattr=+precise-memory < %s | FileCheck %s -check-prefixes=GFX10
+; RUN: llc -mtriple=amdgcn -mcpu=gfx900 -mattr=+enable-flat-scratch,+precise-memory < %s | FileCheck --check-prefixes=GFX9-FLATSCR %s
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1100 -mattr=+precise-memory < %s | FileCheck %s -check-prefixes=GFX11
+; RUN: llc -mtriple=amdgcn -mcpu=gfx1200 -mattr=+precise-memory < %s | FileCheck %s -check-prefixes=GFX12
+
+; from atomicrmw-expand.ll
+; covers flat_load, flat_atomic (atomic with return)
+;
+define void @syncscope_workgroup_nortn(ptr %addr, float %val) {
+; GFX9-LABEL: syncscope_workgroup_nortn:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: flat_load_dword v4, v[0:1]
+; GFX9-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-NEXT: s_mov_b64 s[4:5], 0
+; GFX9-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX9-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX9-NEXT: v_add_f32_e32 v3, v4, v2
+; GFX9-NEXT: flat_atomic_cmpswap v3, v[0:1], v[3:4] glc
+; GFX9-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-NEXT: v_cmp_eq_u32_e32 vcc, v3, v4
+; GFX9-NEXT: s_or_b64 s[4:5], vcc, s[4:5]
+; GFX9-NEXT: v_mov_b32_e32 v4, v3
+; GFX9-NEXT: s_andn2_b64 exec, exec, s[4:5]
+; GFX9-NEXT: s_cbranch_execnz .LBB0_1
+; GFX9-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX9-NEXT: s_or_b64 exec, exec, s[4:5]
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX90A-LABEL: syncscope_workgroup_nortn:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: flat_load_dword v5, v[0:1]
+; GFX90A-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: s_mov_b64 s[4:5], 0
+; GFX90A-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX90A-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX90A-NEXT: v_add_f32_e32 v4, v5, v2
+; GFX90A-NEXT: flat_atomic_cmpswap v3, v[0:1], v[4:5] glc
+; GFX90A-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: v_cmp_eq_u32_e32 vcc, v3, v5
+; GFX90A-NEXT: s_or_b64 s[4:5], vcc, s[4:5]
+; GFX90A-NEXT: v_mov_b32_e32 v5, v3
+; GFX90A-NEXT: s_andn2_b64 exec, exec, s[4:5]
+; GFX90A-NEXT: s_cbranch_execnz .LBB0_1
+; GFX90A-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX90A-NEXT: s_or_b64 exec, exec, s[4:5]
+; GFX90A-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: syncscope_workgroup_nortn:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: flat_load_dword v4, v[0:1]
+; GFX10-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX10-NEXT: s_mov_b32 s4, 0
+; GFX10-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX10-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX10-NEXT: v_add_f32_e32 v3, v4, v2
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: flat_atomic_cmpswap v3, v[0:1], v[3:4] glc
+; GFX10-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX10-NEXT: buffer_gl0_inv
+; GFX10-NEXT: v_cmp_eq_u32_e32 vcc_lo, v3, v4
+; GFX10-NEXT: v_mov_b32_e32 v4, v3
+; GFX10-NEXT: s_or_b32 s4, vcc_lo, s4
+; GFX10-NEXT: s_andn2_b32 exec_lo, exec_lo, s4
+; GFX10-NEXT: s_cbranch_execnz .LBB0_1
+; GFX10-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX10-NEXT: s_or_b32 exec_lo, exec_lo, s4
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX9-FLATSCR-LABEL: syncscope_workgroup_nortn:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: flat_load_dword v4, v[0:1]
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_mov_b64 s[0:1], 0
+; GFX9-FLATSCR-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX9-FLATSCR-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX9-FLATSCR-NEXT: v_add_f32_e32 v3, v4, v2
+; GFX9-FLATSCR-NEXT: flat_atomic_cmpswap v3, v[0:1], v[3:4] glc
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: v_cmp_eq_u32_e32 vcc, v3, v4
+; GFX9-FLATSCR-NEXT: s_or_b64 s[0:1], vcc, s[0:1]
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v4, v3
+; GFX9-FLATSCR-NEXT: s_andn2_b64 exec, exec, s[0:1]
+; GFX9-FLATSCR-NEXT: s_cbranch_execnz .LBB0_1
+; GFX9-FLATSCR-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX9-FLATSCR-NEXT: s_or_b64 exec, exec, s[0:1]
+; GFX9-FLATSCR-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: syncscope_workgroup_nortn:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: flat_load_b32 v4, v[0:1]
+; GFX11-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX11-NEXT: s_mov_b32 s0, 0
+; GFX11-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX11-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_add_f32_e32 v3, v4, v2
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: flat_atomic_cmpswap_b32 v3, v[0:1], v[3:4] glc
+; GFX11-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX11-NEXT: buffer_gl0_inv
+; GFX11-NEXT: v_cmp_eq_u32_e32 vcc_lo, v3, v4
+; GFX11-NEXT: v_mov_b32_e32 v4, v3
+; GFX11-NEXT: s_or_b32 s0, vcc_lo, s0
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT: s_and_not1_b32 exec_lo, exec_lo, s0
+; GFX11-NEXT: s_cbranch_execnz .LBB0_1
+; GFX11-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s0
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: syncscope_workgroup_nortn:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: flat_load_b32 v4, v[0:1]
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_mov_b32 s0, 0
+; GFX12-NEXT: .LBB0_1: ; %atomicrmw.start
+; GFX12-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_add_f32_e32 v3, v4, v2
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: flat_atomic_cmpswap_b32 v3, v[0:1], v[3:4] th:TH_ATOMIC_RETURN
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: global_inv scope:SCOPE_SE
+; GFX12-NEXT: v_cmp_eq_u32_e32 vcc_lo, v3, v4
+; GFX12-NEXT: v_mov_b32_e32 v4, v3
+; GFX12-NEXT: s_or_b32 s0, vcc_lo, s0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX12-NEXT: s_and_not1_b32 exec_lo, exec_lo, s0
+; GFX12-NEXT: s_cbranch_execnz .LBB0_1
+; GFX12-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX12-NEXT: s_or_b32 exec_lo, exec_lo, s0
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+ %res = atomicrmw fadd ptr %addr, float %val syncscope("workgroup") seq_cst
+ ret void
+}
+
+; from atomicrmw-nand.ll
+; covers global_atomic (atomic with return), global_load
+;
+define i32 @atomic_nand_i32_global(ptr addrspace(1) %ptr) nounwind {
+; GFX9-LABEL: atomic_nand_i32_global:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: global_load_dword v2, v[0:1], off
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_mov_b64 s[4:5], 0
+; GFX9-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX9-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX9-NEXT: v_mov_b32_e32 v3, v2
+; GFX9-NEXT: v_not_b32_e32 v2, v3
+; GFX9-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX9-NEXT: global_atomic_cmpswap v2, v[0:1], v[2:3], off glc
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: buffer_wbinvl1_vol
+; GFX9-NEXT: v_cmp_eq_u32_e32 vcc, v2, v3
+; GFX9-NEXT: s_or_b64 s[4:5], vcc, s[4:5]
+; GFX9-NEXT: s_andn2_b64 exec, exec, s[4:5]
+; GFX9-NEXT: s_cbranch_execnz .LBB1_1
+; GFX9-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX9-NEXT: s_or_b64 exec, exec, s[4:5]
+; GFX9-NEXT: v_mov_b32_e32 v0, v2
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX90A-LABEL: atomic_nand_i32_global:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: global_load_dword v2, v[0:1], off
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_mov_b64 s[4:5], 0
+; GFX90A-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX90A-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX90A-NEXT: v_mov_b32_e32 v3, v2
+; GFX90A-NEXT: v_not_b32_e32 v2, v3
+; GFX90A-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX90A-NEXT: buffer_wbl2
+; GFX90A-NEXT: global_atomic_cmpswap v2, v[0:1], v[2:3], off glc
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: buffer_invl2
+; GFX90A-NEXT: buffer_wbinvl1_vol
+; GFX90A-NEXT: v_cmp_eq_u32_e32 vcc, v2, v3
+; GFX90A-NEXT: s_or_b64 s[4:5], vcc, s[4:5]
+; GFX90A-NEXT: s_andn2_b64 exec, exec, s[4:5]
+; GFX90A-NEXT: s_cbranch_execnz .LBB1_1
+; GFX90A-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX90A-NEXT: s_or_b64 exec, exec, s[4:5]
+; GFX90A-NEXT: v_mov_b32_e32 v0, v2
+; GFX90A-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: atomic_nand_i32_global:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: global_load_dword v2, v[0:1], off
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: s_mov_b32 s4, 0
+; GFX10-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX10-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX10-NEXT: v_mov_b32_e32 v3, v2
+; GFX10-NEXT: v_not_b32_e32 v2, v3
+; GFX10-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: global_atomic_cmpswap v2, v[0:1], v[2:3], off glc
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: buffer_gl1_inv
+; GFX10-NEXT: buffer_gl0_inv
+; GFX10-NEXT: v_cmp_eq_u32_e32 vcc_lo, v2, v3
+; GFX10-NEXT: s_or_b32 s4, vcc_lo, s4
+; GFX10-NEXT: s_andn2_b32 exec_lo, exec_lo, s4
+; GFX10-NEXT: s_cbranch_execnz .LBB1_1
+; GFX10-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX10-NEXT: s_or_b32 exec_lo, exec_lo, s4
+; GFX10-NEXT: v_mov_b32_e32 v0, v2
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX9-FLATSCR-LABEL: atomic_nand_i32_global:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: global_load_dword v2, v[0:1], off
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_mov_b64 s[0:1], 0
+; GFX9-FLATSCR-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX9-FLATSCR-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v3, v2
+; GFX9-FLATSCR-NEXT: v_not_b32_e32 v2, v3
+; GFX9-FLATSCR-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX9-FLATSCR-NEXT: global_atomic_cmpswap v2, v[0:1], v[2:3], off glc
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: buffer_wbinvl1_vol
+; GFX9-FLATSCR-NEXT: v_cmp_eq_u32_e32 vcc, v2, v3
+; GFX9-FLATSCR-NEXT: s_or_b64 s[0:1], vcc, s[0:1]
+; GFX9-FLATSCR-NEXT: s_andn2_b64 exec, exec, s[0:1]
+; GFX9-FLATSCR-NEXT: s_cbranch_execnz .LBB1_1
+; GFX9-FLATSCR-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX9-FLATSCR-NEXT: s_or_b64 exec, exec, s[0:1]
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, v2
+; GFX9-FLATSCR-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: atomic_nand_i32_global:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: global_load_b32 v2, v[0:1], off
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: s_mov_b32 s0, 0
+; GFX11-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX11-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX11-NEXT: v_mov_b32_e32 v3, v2
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_not_b32_e32 v2, v3
+; GFX11-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: global_atomic_cmpswap_b32 v2, v[0:1], v[2:3], off glc
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: buffer_gl1_inv
+; GFX11-NEXT: buffer_gl0_inv
+; GFX11-NEXT: v_cmp_eq_u32_e32 vcc_lo, v2, v3
+; GFX11-NEXT: s_or_b32 s0, vcc_lo, s0
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT: s_and_not1_b32 exec_lo, exec_lo, s0
+; GFX11-NEXT: s_cbranch_execnz .LBB1_1
+; GFX11-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s0
+; GFX11-NEXT: v_mov_b32_e32 v0, v2
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: atomic_nand_i32_global:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: global_load_b32 v2, v[0:1], off
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: s_mov_b32 s0, 0
+; GFX12-NEXT: .LBB1_1: ; %atomicrmw.start
+; GFX12-NEXT: ; =>This Inner Loop Header: Depth=1
+; GFX12-NEXT: v_mov_b32_e32 v3, v2
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(VALU_DEP_1)
+; GFX12-NEXT: v_not_b32_e32 v2, v3
+; GFX12-NEXT: v_or_b32_e32 v2, -5, v2
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: global_atomic_cmpswap_b32 v2, v[0:1], v[2:3], off th:TH_ATOMIC_RETURN
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: global_inv scope:SCOPE_SYS
+; GFX12-NEXT: v_cmp_eq_u32_e32 vcc_lo, v2, v3
+; GFX12-NEXT: s_or_b32 s0, vcc_lo, s0
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX12-NEXT: s_and_not1_b32 exec_lo, exec_lo, s0
+; GFX12-NEXT: s_cbranch_execnz .LBB1_1
+; GFX12-NEXT: ; %bb.2: ; %atomicrmw.end
+; GFX12-NEXT: s_or_b32 exec_lo, exec_lo, s0
+; GFX12-NEXT: v_mov_b32_e32 v0, v2
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+ %result = atomicrmw nand ptr addrspace(1) %ptr, i32 4 seq_cst
+ ret i32 %result
+}
+
+; from call-argument-types.ll
+; covers scratch_load, scratch_store, buffer_load, buffer_store
+;
+declare hidden void @byval_align16_f64_arg(<32 x i32>, ptr addrspace(5) byval(double) align 16)
+define void @tail_call_byval_align16(<32 x i32> %val, double %tmp) {
+; GFX9-LABEL: tail_call_byval_align16:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: buffer_load_dword v32, off, s[0:3], s32 offset:28
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: buffer_load_dword v33, off, s[0:3], s32
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_getpc_b64 s[16:17]
+; GFX9-NEXT: s_add_u32 s16, s16, byval_align16_f64_arg@rel32@lo+4
+; GFX9-NEXT: s_addc_u32 s17, s17, byval_align16_f64_arg@rel32@hi+12
+; GFX9-NEXT: buffer_store_dword v32, off, s[0:3], s32 offset:20
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: buffer_load_dword v32, off, s[0:3], s32 offset:24
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: buffer_store_dword v32, off, s[0:3], s32 offset:16
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: buffer_store_dword v33, off, s[0:3], s32
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_setpc_b64 s[16:17]
+;
+; GFX90A-LABEL: tail_call_byval_align16:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: buffer_load_dword v32, off, s[0:3], s32 offset:28
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: buffer_load_dword v33, off, s[0:3], s32 offset:24
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: buffer_load_dword v34, off, s[0:3], s32
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_getpc_b64 s[16:17]
+; GFX90A-NEXT: s_add_u32 s16, s16, byval_align16_f64_arg@rel32@lo+4
+; GFX90A-NEXT: s_addc_u32 s17, s17, byval_align16_f64_arg@rel32@hi+12
+; GFX90A-NEXT: buffer_store_dword v32, off, s[0:3], s32 offset:20
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: buffer_store_dword v33, off, s[0:3], s32 offset:16
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: buffer_store_dword v34, off, s[0:3], s32
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_setpc_b64 s[16:17]
+;
+; GFX10-LABEL: tail_call_byval_align16:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: buffer_load_dword v32, off, s[0:3], s32 offset:28
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: buffer_load_dword v33, off, s[0:3], s32 offset:24
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: buffer_load_dword v34, off, s[0:3], s32
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: s_getpc_b64 s[16:17]
+; GFX10-NEXT: s_add_u32 s16, s16, byval_align16_f64_arg@rel32@lo+4
+; GFX10-NEXT: s_addc_u32 s17, s17, byval_align16_f64_arg@rel32@hi+12
+; GFX10-NEXT: buffer_store_dword v32, off, s[0:3], s32 offset:20
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: buffer_store_dword v33, off, s[0:3], s32 offset:16
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: buffer_store_dword v34, off, s[0:3], s32
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: s_setpc_b64 s[16:17]
+;
+; GFX9-FLATSCR-LABEL: tail_call_byval_align16:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: scratch_load_dword v32, off, s32
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_getpc_b64 s[0:1]
+; GFX9-FLATSCR-NEXT: s_add_u32 s0, s0, byval_align16_f64_arg@rel32@lo+4
+; GFX9-FLATSCR-NEXT: s_addc_u32 s1, s1, byval_align16_f64_arg@rel32@hi+12
+; GFX9-FLATSCR-NEXT: scratch_store_dword off, v32, s32
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: scratch_load_dwordx2 v[32:33], off, s32 offset:24
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: scratch_store_dwordx2 off, v[32:33], s32 offset:16
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_setpc_b64 s[0:1]
+;
+; GFX11-LABEL: tail_call_byval_align16:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: scratch_load_b32 v32, off, s32
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: s_getpc_b64 s[0:1]
+; GFX11-NEXT: s_add_u32 s0, s0, byval_align16_f64_arg@rel32@lo+4
+; GFX11-NEXT: s_addc_u32 s1, s1, byval_align16_f64_arg@rel32@hi+12
+; GFX11-NEXT: scratch_store_b32 off, v32, s32
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: scratch_load_b64 v[32:33], off, s32 offset:24
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: scratch_store_b64 off, v[32:33], s32 offset:16
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: s_setpc_b64 s[0:1]
+;
+; GFX12-LABEL: tail_call_byval_align16:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: scratch_load_b32 v32, off, s32
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: s_getpc_b64 s[0:1]
+; GFX12-NEXT: s_sext_i32_i16 s1, s1
+; GFX12-NEXT: s_add_co_u32 s0, s0, byval_align16_f64_arg@rel32@lo+8
+; GFX12-NEXT: s_add_co_ci_u32 s1, s1, byval_align16_f64_arg@rel32@hi+16
+; GFX12-NEXT: scratch_store_b32 off, v32, s32
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: scratch_load_b64 v[32:33], off, s32 offset:24
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: scratch_store_b64 off, v[32:33], s32 offset:16
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: s_setpc_b64 s[0:1]
+entry:
+ %alloca = alloca double, align 8, addrspace(5)
+ tail call void @byval_align16_f64_arg(<32 x i32> %val, ptr addrspace(5) byval(double) align 16 %alloca)
+ ret void
+}
+
+; from udiv.ll
+; covers s_load
+;
+define amdgpu_kernel void @udiv_i32(ptr addrspace(1) %out, i32 %x, i32 %y) {
+; GFX9-LABEL: udiv_i32:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_load_dwordx4 s[0:3], s[0:1], 0x24
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: v_mov_b32_e32 v1, 0
+; GFX9-NEXT: v_cvt_f32_u32_e32 v0, s3
+; GFX9-NEXT: s_sub_i32 s4, 0, s3
+; GFX9-NEXT: v_rcp_iflag_f32_e32 v0, v0
+; GFX9-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0
+; GFX9-NEXT: v_cvt_u32_f32_e32 v0, v0
+; GFX9-NEXT: v_readfirstlane_b32 s5, v0
+; GFX9-NEXT: s_mul_i32 s4, s4, s5
+; GFX9-NEXT: s_mul_hi_u32 s4, s5, s4
+; GFX9-NEXT: s_add_i32 s5, s5, s4
+; GFX9-NEXT: s_mul_hi_u32 s4, s2, s5
+; GFX9-NEXT: s_mul_i32 s5, s4, s3
+; GFX9-NEXT: s_sub_i32 s2, s2, s5
+; GFX9-NEXT: s_add_i32 s6, s4, 1
+; GFX9-NEXT: s_sub_i32 s5, s2, s3
+; GFX9-NEXT: s_cmp_ge_u32 s2, s3
+; GFX9-NEXT: s_cselect_b32 s4, s6, s4
+; GFX9-NEXT: s_cselect_b32 s2, s5, s2
+; GFX9-NEXT: s_add_i32 s5, s4, 1
+; GFX9-NEXT: s_cmp_ge_u32 s2, s3
+; GFX9-NEXT: s_cselect_b32 s2, s5, s4
+; GFX9-NEXT: v_mov_b32_e32 v0, s2
+; GFX9-NEXT: global_store_dword v1, v0, s[0:1]
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: udiv_i32:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_load_dwordx4 s[0:3], s[0:1], 0x24
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: v_mov_b32_e32 v1, 0
+; GFX90A-NEXT: v_cvt_f32_u32_e32 v0, s3
+; GFX90A-NEXT: s_sub_i32 s4, 0, s3
+; GFX90A-NEXT: v_rcp_iflag_f32_e32 v0, v0
+; GFX90A-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0
+; GFX90A-NEXT: v_cvt_u32_f32_e32 v0, v0
+; GFX90A-NEXT: v_readfirstlane_b32 s5, v0
+; GFX90A-NEXT: s_mul_i32 s4, s4, s5
+; GFX90A-NEXT: s_mul_hi_u32 s4, s5, s4
+; GFX90A-NEXT: s_add_i32 s5, s5, s4
+; GFX90A-NEXT: s_mul_hi_u32 s4, s2, s5
+; GFX90A-NEXT: s_mul_i32 s5, s4, s3
+; GFX90A-NEXT: s_sub_i32 s2, s2, s5
+; GFX90A-NEXT: s_add_i32 s6, s4, 1
+; GFX90A-NEXT: s_sub_i32 s5, s2, s3
+; GFX90A-NEXT: s_cmp_ge_u32 s2, s3
+; GFX90A-NEXT: s_cselect_b32 s4, s6, s4
+; GFX90A-NEXT: s_cselect_b32 s2, s5, s2
+; GFX90A-NEXT: s_add_i32 s5, s4, 1
+; GFX90A-NEXT: s_cmp_ge_u32 s2, s3
+; GFX90A-NEXT: s_cselect_b32 s2, s5, s4
+; GFX90A-NEXT: v_mov_b32_e32 v0, s2
+; GFX90A-NEXT: global_store_dword v1, v0, s[0:1]
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: udiv_i32:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_load_dwordx4 s[0:3], s[0:1], 0x24
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: v_cvt_f32_u32_e32 v0, s3
+; GFX10-NEXT: s_sub_i32 s5, 0, s3
+; GFX10-NEXT: v_rcp_iflag_f32_e32 v0, v0
+; GFX10-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0
+; GFX10-NEXT: v_cvt_u32_f32_e32 v0, v0
+; GFX10-NEXT: v_readfirstlane_b32 s4, v0
+; GFX10-NEXT: v_mov_b32_e32 v0, 0
+; GFX10-NEXT: s_mul_i32 s5, s5, s4
+; GFX10-NEXT: s_mul_hi_u32 s5, s4, s5
+; GFX10-NEXT: s_add_i32 s4, s4, s5
+; GFX10-NEXT: s_mul_hi_u32 s4, s2, s4
+; GFX10-NEXT: s_mul_i32 s5, s4, s3
+; GFX10-NEXT: s_sub_i32 s2, s2, s5
+; GFX10-NEXT: s_add_i32 s5, s4, 1
+; GFX10-NEXT: s_sub_i32 s6, s2, s3
+; GFX10-NEXT: s_cmp_ge_u32 s2, s3
+; GFX10-NEXT: s_cselect_b32 s4, s5, s4
+; GFX10-NEXT: s_cselect_b32 s2, s6, s2
+; GFX10-NEXT: s_add_i32 s5, s4, 1
+; GFX10-NEXT: s_cmp_ge_u32 s2, s3
+; GFX10-NEXT: s_cselect_b32 s2, s5, s4
+; GFX10-NEXT: v_mov_b32_e32 v1, s2
+; GFX10-NEXT: global_store_dword v0, v1, s[0:1]
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: udiv_i32:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_load_dwordx4 s[0:3], s[0:1], 0x24
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, 0
+; GFX9-FLATSCR-NEXT: v_cvt_f32_u32_e32 v0, s3
+; GFX9-FLATSCR-NEXT: s_sub_i32 s4, 0, s3
+; GFX9-FLATSCR-NEXT: v_rcp_iflag_f32_e32 v0, v0
+; GFX9-FLATSCR-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0
+; GFX9-FLATSCR-NEXT: v_cvt_u32_f32_e32 v0, v0
+; GFX9-FLATSCR-NEXT: v_readfirstlane_b32 s5, v0
+; GFX9-FLATSCR-NEXT: s_mul_i32 s4, s4, s5
+; GFX9-FLATSCR-NEXT: s_mul_hi_u32 s4, s5, s4
+; GFX9-FLATSCR-NEXT: s_add_i32 s5, s5, s4
+; GFX9-FLATSCR-NEXT: s_mul_hi_u32 s4, s2, s5
+; GFX9-FLATSCR-NEXT: s_mul_i32 s5, s4, s3
+; GFX9-FLATSCR-NEXT: s_sub_i32 s2, s2, s5
+; GFX9-FLATSCR-NEXT: s_add_i32 s6, s4, 1
+; GFX9-FLATSCR-NEXT: s_sub_i32 s5, s2, s3
+; GFX9-FLATSCR-NEXT: s_cmp_ge_u32 s2, s3
+; GFX9-FLATSCR-NEXT: s_cselect_b32 s4, s6, s4
+; GFX9-FLATSCR-NEXT: s_cselect_b32 s2, s5, s2
+; GFX9-FLATSCR-NEXT: s_add_i32 s5, s4, 1
+; GFX9-FLATSCR-NEXT: s_cmp_ge_u32 s2, s3
+; GFX9-FLATSCR-NEXT: s_cselect_b32 s2, s5, s4
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, s2
+; GFX9-FLATSCR-NEXT: global_store_dword v1, v0, s[0:1]
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: udiv_i32:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_load_b128 s[0:3], s[0:1], 0x24
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: v_cvt_f32_u32_e32 v0, s3
+; GFX11-NEXT: s_sub_i32 s5, 0, s3
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_2) | instid1(VALU_DEP_1)
+; GFX11-NEXT: v_rcp_iflag_f32_e32 v0, v0
+; GFX11-NEXT: s_waitcnt_depctr 0xfff
+; GFX11-NEXT: v_mul_f32_e32 v0, 0x4f7ffffe, v0
+; GFX11-NEXT: v_cvt_u32_f32_e32 v0, v0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(SKIP_1) | instid1(VALU_DEP_2)
+; GFX11-NEXT: v_readfirstlane_b32 s4, v0
+; GFX11-NEXT: v_mov_b32_e32 v0, 0
+; GFX11-NEXT: s_mul_i32 s5, s5, s4
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT: s_mul_hi_u32 s5, s4, s5
+; GFX11-NEXT: s_add_i32 s4, s4, s5
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT: s_mul_hi_u32 s4, s2, s4
+; GFX11-NEXT: s_mul_i32 s5, s4, s3
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT: s_sub_i32 s2, s2, s5
+; GFX11-NEXT: s_add_i32 s5, s4, 1
+; GFX11-NEXT: s_sub_i32 s6, s2, s3
+; GFX11-NEXT: s_cmp_ge_u32 s2, s3
+; GFX11-NEXT: s_cselect_b32 s4, s5, s4
+; GFX11-NEXT: s_cselect_b32 s2, s6, s2
+; GFX11-NEXT: s_add_i32 s5, s4, 1
+; GFX11-NEXT: s_cmp_ge_u32 s2, s3
+; GFX11-NEXT: s_cselect_b32 s2, s5, s4
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX11-NEXT: v_mov_b32_e32 v1, s2
+; GFX11-NEXT: global_store_b32 v0, v1, s[0:1]
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: udiv_i32:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_load_b128 s[0:3], s[0:1], 0x24
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: s_cvt_f32_u32 s4, s3
+; GFX12-NEXT: s_sub_co_i32 s5, 0, s3
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_2) | instskip(NEXT) | instid1(TRANS32_DEP_1)
+; GFX12-NEXT: v_rcp_iflag_f32_e32 v0, s4
+; GFX12-NEXT: v_readfirstlane_b32 s4, v0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1) | instskip(NEXT) | instid1(SALU_CYCLE_3)
+; GFX12-NEXT: s_mul_f32 s4, s4, 0x4f7ffffe
+; GFX12-NEXT: s_cvt_u32_f32 s4, s4
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_3) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_mul_i32 s5, s5, s4
+; GFX12-NEXT: s_mul_hi_u32 s5, s4, s5
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_add_co_i32 s4, s4, s5
+; GFX12-NEXT: s_mul_hi_u32 s4, s2, s4
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_mul_i32 s5, s4, s3
+; GFX12-NEXT: s_sub_co_i32 s2, s2, s5
+; GFX12-NEXT: s_add_co_i32 s5, s4, 1
+; GFX12-NEXT: s_sub_co_i32 s6, s2, s3
+; GFX12-NEXT: s_cmp_ge_u32 s2, s3
+; GFX12-NEXT: s_cselect_b32 s4, s5, s4
+; GFX12-NEXT: s_cselect_b32 s2, s6, s2
+; GFX12-NEXT: s_add_co_i32 s5, s4, 1
+; GFX12-NEXT: s_cmp_ge_u32 s2, s3
+; GFX12-NEXT: s_cselect_b32 s2, s5, s4
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1)
+; GFX12-NEXT: v_dual_mov_b32 v0, 0 :: v_dual_mov_b32 v1, s2
+; GFX12-NEXT: global_store_b32 v0, v1, s[0:1]
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: s_endpgm
+ %r = udiv i32 %x, %y
+ store i32 %r, ptr addrspace(1) %out
+ ret void
+}
+
+declare float @llvm.amdgcn.s.buffer.load.f32(<4 x i32>, i32, i32)
+
+; from smrd.ll
+; covers s_buffer_load
+;
+define amdgpu_ps float @smrd_sgpr_offset(<4 x i32> inreg %desc, i32 inreg %offset) #0 {
+; GFX9-LABEL: smrd_sgpr_offset:
+; GFX9: ; %bb.0: ; %main_body
+; GFX9-NEXT: s_buffer_load_dword s0, s[0:3], s4 offset:0x0
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: v_mov_b32_e32 v0, s0
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX90A-LABEL: smrd_sgpr_offset:
+; GFX90A: ; %bb.0: ; %main_body
+; GFX90A-NEXT: s_buffer_load_dword s0, s[0:3], s4 offset:0x0
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: v_mov_b32_e32 v0, s0
+; GFX90A-NEXT: ; return to shader part epilog
+;
+; GFX10-LABEL: smrd_sgpr_offset:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: s_buffer_load_dword s0, s[0:3], s4 offset:0x0
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: v_mov_b32_e32 v0, s0
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX9-FLATSCR-LABEL: smrd_sgpr_offset:
+; GFX9-FLATSCR: ; %bb.0: ; %main_body
+; GFX9-FLATSCR-NEXT: s_mov_b32 s11, s5
+; GFX9-FLATSCR-NEXT: s_mov_b32 s10, s4
+; GFX9-FLATSCR-NEXT: s_mov_b32 s9, s3
+; GFX9-FLATSCR-NEXT: s_mov_b32 s8, s2
+; GFX9-FLATSCR-NEXT: s_buffer_load_dword s0, s[8:11], s6 offset:0x0
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, s0
+; GFX9-FLATSCR-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: smrd_sgpr_offset:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: s_buffer_load_b32 s0, s[0:3], s4 offset:0x0
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: v_mov_b32_e32 v0, s0
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: smrd_sgpr_offset:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: s_buffer_load_b32 s0, s[0:3], s4 offset:0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_mov_b32_e32 v0, s0
+; GFX12-NEXT: ; return to shader part epilog
+main_body:
+ %r = call float @llvm.amdgcn.s.buffer.load.f32(<4 x i32> %desc, i32 %offset, i32 0)
+ ret float %r
+}
+
+; from atomic_load_add.ll
+; covers s_load, ds_add (atomic without return)
+;
+define amdgpu_kernel void @atomic_add_local(ptr addrspace(3) %local) {
+; GFX9-LABEL: atomic_add_local:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_mov_b64 s[2:3], exec
+; GFX9-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX9-NEXT: v_mbcnt_hi_u32_b32 v0, s3, v0
+; GFX9-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-NEXT: s_and_saveexec_b64 s[4:5], vcc
+; GFX9-NEXT: s_cbranch_execz .LBB5_2
+; GFX9-NEXT: ; %bb.1:
+; GFX9-NEXT: s_load_dword s0, s[0:1], 0x24
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: s_bcnt1_i32_b64 s1, s[2:3]
+; GFX9-NEXT: s_mul_i32 s1, s1, 5
+; GFX9-NEXT: v_mov_b32_e32 v1, s1
+; GFX9-NEXT: v_mov_b32_e32 v0, s0
+; GFX9-NEXT: ds_add_u32 v0, v1
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: .LBB5_2:
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: atomic_add_local:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_mov_b64 s[2:3], exec
+; GFX90A-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX90A-NEXT: v_mbcnt_hi_u32_b32 v0, s3, v0
+; GFX90A-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX90A-NEXT: s_and_saveexec_b64 s[4:5], vcc
+; GFX90A-NEXT: s_cbranch_execz .LBB5_2
+; GFX90A-NEXT: ; %bb.1:
+; GFX90A-NEXT: s_load_dword s0, s[0:1], 0x24
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: s_bcnt1_i32_b64 s1, s[2:3]
+; GFX90A-NEXT: s_mul_i32 s1, s1, 5
+; GFX90A-NEXT: v_mov_b32_e32 v1, s1
+; GFX90A-NEXT: v_mov_b32_e32 v0, s0
+; GFX90A-NEXT: ds_add_u32 v0, v1
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: .LBB5_2:
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_add_local:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_mov_b32 s2, exec_lo
+; GFX10-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX10-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v0
+; GFX10-NEXT: s_and_saveexec_b32 s3, vcc_lo
+; GFX10-NEXT: s_cbranch_execz .LBB5_2
+; GFX10-NEXT: ; %bb.1:
+; GFX10-NEXT: s_load_dword s0, s[0:1], 0x24
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_bcnt1_i32_b32 s1, s2
+; GFX10-NEXT: s_mul_i32 s1, s1, 5
+; GFX10-NEXT: v_mov_b32_e32 v1, s1
+; GFX10-NEXT: v_mov_b32_e32 v0, s0
+; GFX10-NEXT: ds_add_u32 v0, v1
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: buffer_gl0_inv
+; GFX10-NEXT: .LBB5_2:
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: atomic_add_local:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_mov_b64 s[2:3], exec
+; GFX9-FLATSCR-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX9-FLATSCR-NEXT: v_mbcnt_hi_u32_b32 v0, s3, v0
+; GFX9-FLATSCR-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-FLATSCR-NEXT: s_and_saveexec_b64 s[4:5], vcc
+; GFX9-FLATSCR-NEXT: s_cbranch_execz .LBB5_2
+; GFX9-FLATSCR-NEXT: ; %bb.1:
+; GFX9-FLATSCR-NEXT: s_load_dword s0, s[0:1], 0x24
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_bcnt1_i32_b64 s1, s[2:3]
+; GFX9-FLATSCR-NEXT: s_mul_i32 s1, s1, 5
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, s1
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, s0
+; GFX9-FLATSCR-NEXT: ds_add_u32 v0, v1
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: .LBB5_2:
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_add_local:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_mov_b32 s2, exec_lo
+; GFX11-NEXT: s_mov_b32 s3, exec_lo
+; GFX11-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX11-NEXT: s_cbranch_execz .LBB5_2
+; GFX11-NEXT: ; %bb.1:
+; GFX11-NEXT: s_load_b32 s0, s[0:1], 0x24
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_bcnt1_i32_b32 s1, s2
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT: s_mul_i32 s1, s1, 5
+; GFX11-NEXT: v_dual_mov_b32 v1, s1 :: v_dual_mov_b32 v0, s0
+; GFX11-NEXT: ds_add_u32 v0, v1
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: buffer_gl0_inv
+; GFX11-NEXT: .LBB5_2:
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_add_local:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_mov_b32 s2, exec_lo
+; GFX12-NEXT: s_mov_b32 s3, exec_lo
+; GFX12-NEXT: v_mbcnt_lo_u32_b32 v0, s2, 0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX12-NEXT: s_cbranch_execz .LBB5_2
+; GFX12-NEXT: ; %bb.1:
+; GFX12-NEXT: s_load_b32 s0, s[0:1], 0x24
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: s_bcnt1_i32_b32 s1, s2
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_mul_i32 s1, s1, 5
+; GFX12-NEXT: v_dual_mov_b32 v1, s1 :: v_dual_mov_b32 v0, s0
+; GFX12-NEXT: ds_add_u32 v0, v1
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: global_inv scope:SCOPE_SE
+; GFX12-NEXT: .LBB5_2:
+; GFX12-NEXT: s_endpgm
+ %unused = atomicrmw volatile add ptr addrspace(3) %local, i32 5 seq_cst
+ ret void
+}
+
+; from flat_atomics_i32_system.ll
+; covers flat_atomic_swap (atomic without return)
+;
+define void @flat_atomic_xchg_i32_noret(ptr %ptr, i32 %in) {
+; GFX9-LABEL: flat_atomic_xchg_i32_noret:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-NEXT: flat_atomic_swap v[0:1], v2
+; GFX9-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-NEXT: buffer_wbinvl1_vol
+; GFX9-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX90A-LABEL: flat_atomic_xchg_i32_noret:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: buffer_wbl2
+; GFX90A-NEXT: flat_atomic_swap v[0:1], v2
+; GFX90A-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX90A-NEXT: buffer_invl2
+; GFX90A-NEXT: buffer_wbinvl1_vol
+; GFX90A-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX10-LABEL: flat_atomic_xchg_i32_noret:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: flat_atomic_swap v[0:1], v2
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: buffer_gl1_inv
+; GFX10-NEXT: buffer_gl0_inv
+; GFX10-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX9-FLATSCR-LABEL: flat_atomic_xchg_i32_noret:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: flat_atomic_swap v[0:1], v2
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0) lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: buffer_wbinvl1_vol
+; GFX9-FLATSCR-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX11-LABEL: flat_atomic_xchg_i32_noret:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_waitcnt vmcnt(0) expcnt(0) lgkmcnt(0)
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: flat_atomic_swap_b32 v[0:1], v2
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: buffer_gl1_inv
+; GFX11-NEXT: buffer_gl0_inv
+; GFX11-NEXT: s_setpc_b64 s[30:31]
+;
+; GFX12-LABEL: flat_atomic_xchg_i32_noret:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_wait_loadcnt_dscnt 0x0
+; GFX12-NEXT: s_wait_expcnt 0x0
+; GFX12-NEXT: s_wait_samplecnt 0x0
+; GFX12-NEXT: s_wait_bvhcnt 0x0
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: flat_atomic_swap_b32 v[0:1], v2
+; GFX12-NEXT: s_wait_storecnt_dscnt 0x0
+; GFX12-NEXT: global_inv scope:SCOPE_SYS
+; GFX12-NEXT: s_setpc_b64 s[30:31]
+ %tmp0 = atomicrmw xchg ptr %ptr, i32 %in seq_cst
+ ret void
+}
+
+; from atomic_load_add.ll
+; covers s_load, ds_add_rtn (atomic with return)
+;
+define amdgpu_kernel void @atomic_add_ret_local(ptr addrspace(1) %out, ptr addrspace(3) %local) {
+; GFX9-LABEL: atomic_add_ret_local:
+; GFX9: ; %bb.0:
+; GFX9-NEXT: s_mov_b64 s[4:5], exec
+; GFX9-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX9-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX9-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-NEXT: ; implicit-def: $vgpr1
+; GFX9-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX9-NEXT: s_cbranch_execz .LBB7_2
+; GFX9-NEXT: ; %bb.1:
+; GFX9-NEXT: s_load_dword s6, s[0:1], 0x2c
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX9-NEXT: s_mul_i32 s4, s4, 5
+; GFX9-NEXT: v_mov_b32_e32 v2, s4
+; GFX9-NEXT: v_mov_b32_e32 v1, s6
+; GFX9-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: .LBB7_2:
+; GFX9-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX9-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: v_readfirstlane_b32 s2, v1
+; GFX9-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX9-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: atomic_add_ret_local:
+; GFX90A: ; %bb.0:
+; GFX90A-NEXT: s_mov_b64 s[4:5], exec
+; GFX90A-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX90A-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX90A-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX90A-NEXT: ; implicit-def: $vgpr1
+; GFX90A-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX90A-NEXT: s_cbranch_execz .LBB7_2
+; GFX90A-NEXT: ; %bb.1:
+; GFX90A-NEXT: s_load_dword s6, s[0:1], 0x2c
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX90A-NEXT: s_mul_i32 s4, s4, 5
+; GFX90A-NEXT: v_mov_b32_e32 v2, s4
+; GFX90A-NEXT: v_mov_b32_e32 v1, s6
+; GFX90A-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: .LBB7_2:
+; GFX90A-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX90A-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: v_readfirstlane_b32 s2, v1
+; GFX90A-NEXT: v_mov_b32_e32 v2, 0
+; GFX90A-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX90A-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: atomic_add_ret_local:
+; GFX10: ; %bb.0:
+; GFX10-NEXT: s_mov_b32 s3, exec_lo
+; GFX10-NEXT: ; implicit-def: $vgpr1
+; GFX10-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX10-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v0
+; GFX10-NEXT: s_and_saveexec_b32 s2, vcc_lo
+; GFX10-NEXT: s_cbranch_execz .LBB7_2
+; GFX10-NEXT: ; %bb.1:
+; GFX10-NEXT: s_load_dword s4, s[0:1], 0x2c
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX10-NEXT: s_mul_i32 s3, s3, 5
+; GFX10-NEXT: v_mov_b32_e32 v2, s3
+; GFX10-NEXT: v_mov_b32_e32 v1, s4
+; GFX10-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: buffer_gl0_inv
+; GFX10-NEXT: .LBB7_2:
+; GFX10-NEXT: s_waitcnt_depctr 0xffe3
+; GFX10-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX10-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: v_readfirstlane_b32 s2, v1
+; GFX10-NEXT: v_mov_b32_e32 v1, 0
+; GFX10-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX10-NEXT: global_store_dword v1, v0, s[0:1]
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: atomic_add_ret_local:
+; GFX9-FLATSCR: ; %bb.0:
+; GFX9-FLATSCR-NEXT: s_mov_b64 s[4:5], exec
+; GFX9-FLATSCR-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX9-FLATSCR-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX9-FLATSCR-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-FLATSCR-NEXT: ; implicit-def: $vgpr1
+; GFX9-FLATSCR-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX9-FLATSCR-NEXT: s_cbranch_execz .LBB7_2
+; GFX9-FLATSCR-NEXT: ; %bb.1:
+; GFX9-FLATSCR-NEXT: s_load_dword s6, s[0:1], 0x2c
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX9-FLATSCR-NEXT: s_mul_i32 s4, s4, 5
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v2, s4
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, s6
+; GFX9-FLATSCR-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: .LBB7_2:
+; GFX9-FLATSCR-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX9-FLATSCR-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: v_readfirstlane_b32 s2, v1
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-FLATSCR-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX9-FLATSCR-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: atomic_add_ret_local:
+; GFX11: ; %bb.0:
+; GFX11-NEXT: s_mov_b32 s3, exec_lo
+; GFX11-NEXT: s_mov_b32 s2, exec_lo
+; GFX11-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX11-NEXT: ; implicit-def: $vgpr1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX11-NEXT: s_cbranch_execz .LBB7_2
+; GFX11-NEXT: ; %bb.1:
+; GFX11-NEXT: s_load_b32 s4, s[0:1], 0x2c
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT: s_mul_i32 s3, s3, 5
+; GFX11-NEXT: v_dual_mov_b32 v2, s3 :: v_dual_mov_b32 v1, s4
+; GFX11-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: buffer_gl0_inv
+; GFX11-NEXT: .LBB7_2:
+; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX11-NEXT: s_load_b64 s[0:1], s[0:1], 0x24
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: v_readfirstlane_b32 s2, v1
+; GFX11-NEXT: v_mov_b32_e32 v1, 0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; GFX11-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX11-NEXT: global_store_b32 v1, v0, s[0:1]
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: atomic_add_ret_local:
+; GFX12: ; %bb.0:
+; GFX12-NEXT: s_mov_b32 s3, exec_lo
+; GFX12-NEXT: s_mov_b32 s2, exec_lo
+; GFX12-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX12-NEXT: ; implicit-def: $vgpr1
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX12-NEXT: s_cbranch_execz .LBB7_2
+; GFX12-NEXT: ; %bb.1:
+; GFX12-NEXT: s_load_b32 s4, s[0:1], 0x2c
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_mul_i32 s3, s3, 5
+; GFX12-NEXT: v_dual_mov_b32 v2, s3 :: v_dual_mov_b32 v1, s4
+; GFX12-NEXT: ds_add_rtn_u32 v1, v1, v2
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: global_inv scope:SCOPE_SE
+; GFX12-NEXT: .LBB7_2:
+; GFX12-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX12-NEXT: s_load_b64 s[0:1], s[0:1], 0x24
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_readfirstlane_b32 s2, v1
+; GFX12-NEXT: v_mov_b32_e32 v1, 0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; GFX12-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX12-NEXT: global_store_b32 v1, v0, s[0:1]
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: s_endpgm
+ %val = atomicrmw volatile add ptr addrspace(3) %local, i32 5 seq_cst
+ store i32 %val, ptr addrspace(1) %out
+ ret void
+}
+
+declare i32 @llvm.amdgcn.raw.ptr.buffer.atomic.add(i32, ptr addrspace(8), i32, i32, i32 immarg)
+
+; from atomic_optimizations_buffer.ll
+; covers buffer_atomic (atomic with return)
+;
+define amdgpu_kernel void @add_i32_constant(ptr addrspace(1) %out, ptr addrspace(8) %inout) {
+; GFX9-LABEL: add_i32_constant:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: s_mov_b64 s[4:5], exec
+; GFX9-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX9-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX9-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-NEXT: ; implicit-def: $vgpr1
+; GFX9-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX9-NEXT: s_cbranch_execz .LBB8_2
+; GFX9-NEXT: ; %bb.1:
+; GFX9-NEXT: s_load_dwordx4 s[8:11], s[0:1], 0x34
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX9-NEXT: s_mul_i32 s4, s4, 5
+; GFX9-NEXT: v_mov_b32_e32 v1, s4
+; GFX9-NEXT: buffer_atomic_add v1, off, s[8:11], 0 glc
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: .LBB8_2:
+; GFX9-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX9-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: v_readfirstlane_b32 s2, v1
+; GFX9-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX9-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: add_i32_constant:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: s_mov_b64 s[4:5], exec
+; GFX90A-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX90A-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX90A-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX90A-NEXT: ; implicit-def: $vgpr1
+; GFX90A-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX90A-NEXT: s_cbranch_execz .LBB8_2
+; GFX90A-NEXT: ; %bb.1:
+; GFX90A-NEXT: s_load_dwordx4 s[8:11], s[0:1], 0x34
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX90A-NEXT: s_mul_i32 s4, s4, 5
+; GFX90A-NEXT: v_mov_b32_e32 v1, s4
+; GFX90A-NEXT: buffer_atomic_add v1, off, s[8:11], 0 glc
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: .LBB8_2:
+; GFX90A-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX90A-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: v_readfirstlane_b32 s2, v1
+; GFX90A-NEXT: v_mov_b32_e32 v2, 0
+; GFX90A-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX90A-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: add_i32_constant:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: s_mov_b32 s3, exec_lo
+; GFX10-NEXT: ; implicit-def: $vgpr1
+; GFX10-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX10-NEXT: v_cmp_eq_u32_e32 vcc_lo, 0, v0
+; GFX10-NEXT: s_and_saveexec_b32 s2, vcc_lo
+; GFX10-NEXT: s_cbranch_execz .LBB8_2
+; GFX10-NEXT: ; %bb.1:
+; GFX10-NEXT: s_load_dwordx4 s[4:7], s[0:1], 0x34
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX10-NEXT: s_mul_i32 s3, s3, 5
+; GFX10-NEXT: v_mov_b32_e32 v1, s3
+; GFX10-NEXT: buffer_atomic_add v1, off, s[4:7], 0 glc
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: .LBB8_2:
+; GFX10-NEXT: s_waitcnt_depctr 0xffe3
+; GFX10-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX10-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: v_readfirstlane_b32 s2, v1
+; GFX10-NEXT: v_mov_b32_e32 v1, 0
+; GFX10-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX10-NEXT: global_store_dword v1, v0, s[0:1]
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: add_i32_constant:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: s_mov_b64 s[4:5], exec
+; GFX9-FLATSCR-NEXT: v_mbcnt_lo_u32_b32 v0, s4, 0
+; GFX9-FLATSCR-NEXT: v_mbcnt_hi_u32_b32 v0, s5, v0
+; GFX9-FLATSCR-NEXT: v_cmp_eq_u32_e32 vcc, 0, v0
+; GFX9-FLATSCR-NEXT: ; implicit-def: $vgpr1
+; GFX9-FLATSCR-NEXT: s_and_saveexec_b64 s[2:3], vcc
+; GFX9-FLATSCR-NEXT: s_cbranch_execz .LBB8_2
+; GFX9-FLATSCR-NEXT: ; %bb.1:
+; GFX9-FLATSCR-NEXT: s_load_dwordx4 s[8:11], s[0:1], 0x34
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_bcnt1_i32_b64 s4, s[4:5]
+; GFX9-FLATSCR-NEXT: s_mul_i32 s4, s4, 5
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, s4
+; GFX9-FLATSCR-NEXT: buffer_atomic_add v1, off, s[8:11], 0 glc
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: .LBB8_2:
+; GFX9-FLATSCR-NEXT: s_or_b64 exec, exec, s[2:3]
+; GFX9-FLATSCR-NEXT: s_load_dwordx2 s[0:1], s[0:1], 0x24
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: v_readfirstlane_b32 s2, v1
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v2, 0
+; GFX9-FLATSCR-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX9-FLATSCR-NEXT: global_store_dword v2, v0, s[0:1]
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: add_i32_constant:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: s_mov_b32 s3, exec_lo
+; GFX11-NEXT: s_mov_b32 s2, exec_lo
+; GFX11-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX11-NEXT: ; implicit-def: $vgpr1
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX11-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX11-NEXT: s_cbranch_execz .LBB8_2
+; GFX11-NEXT: ; %bb.1:
+; GFX11-NEXT: s_load_b128 s[4:7], s[0:1], 0x34
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX11-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX11-NEXT: s_mul_i32 s3, s3, 5
+; GFX11-NEXT: v_mov_b32_e32 v1, s3
+; GFX11-NEXT: buffer_atomic_add_u32 v1, off, s[4:7], 0 glc
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: .LBB8_2:
+; GFX11-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX11-NEXT: s_load_b64 s[0:1], s[0:1], 0x24
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: v_readfirstlane_b32 s2, v1
+; GFX11-NEXT: v_mov_b32_e32 v1, 0
+; GFX11-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; GFX11-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX11-NEXT: global_store_b32 v1, v0, s[0:1]
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: add_i32_constant:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: s_mov_b32 s3, exec_lo
+; GFX12-NEXT: s_mov_b32 s2, exec_lo
+; GFX12-NEXT: v_mbcnt_lo_u32_b32 v0, s3, 0
+; GFX12-NEXT: ; implicit-def: $vgpr1
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_1)
+; GFX12-NEXT: v_cmpx_eq_u32_e32 0, v0
+; GFX12-NEXT: s_cbranch_execz .LBB8_2
+; GFX12-NEXT: ; %bb.1:
+; GFX12-NEXT: s_load_b128 s[4:7], s[0:1], 0x34
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: s_bcnt1_i32_b32 s3, s3
+; GFX12-NEXT: s_delay_alu instid0(SALU_CYCLE_1) | instskip(NEXT) | instid1(SALU_CYCLE_1)
+; GFX12-NEXT: s_mul_i32 s3, s3, 5
+; GFX12-NEXT: v_mov_b32_e32 v1, s3
+; GFX12-NEXT: buffer_atomic_add_u32 v1, off, s[4:7], null th:TH_ATOMIC_RETURN
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: .LBB8_2:
+; GFX12-NEXT: s_or_b32 exec_lo, exec_lo, s2
+; GFX12-NEXT: s_load_b64 s[0:1], s[0:1], 0x24
+; GFX12-NEXT: s_wait_kmcnt 0x0
+; GFX12-NEXT: v_readfirstlane_b32 s2, v1
+; GFX12-NEXT: v_mov_b32_e32 v1, 0
+; GFX12-NEXT: s_delay_alu instid0(VALU_DEP_2)
+; GFX12-NEXT: v_mad_u32_u24 v0, v0, 5, s2
+; GFX12-NEXT: global_store_b32 v1, v0, s[0:1]
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: s_endpgm
+entry:
+ %old = call i32 @llvm.amdgcn.raw.ptr.buffer.atomic.add(i32 5, ptr addrspace(8) %inout, i32 0, i32 0, i32 0)
+ store i32 %old, ptr addrspace(1) %out
+ ret void
+}
+
+declare <4 x float> @llvm.amdgcn.image.load.1d.v4f32.i16(i32, i16, <8 x i32>, i32, i32)
+
+; from llvm.amdgcn.image.load.a16.ll
+; covers image_load
+;
+define amdgpu_ps <4 x float> @load.f32.1d(<8 x i32> inreg %rsrc, <2 x i16> %coords) {
+; GFX9-LABEL: load.f32.1d:
+; GFX9: ; %bb.0: ; %main_body
+; GFX9-NEXT: image_load v0, v0, s[0:7] dmask:0x1 unorm a16
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX90A-LABEL: load.f32.1d:
+; GFX90A: ; %bb.0: ; %main_body
+; GFX90A-NEXT: image_load v0, v0, s[0:7] dmask:0x1 unorm a16
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: ; return to shader part epilog
+;
+; GFX10-LABEL: load.f32.1d:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: image_load v0, v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm a16
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX9-FLATSCR-LABEL: load.f32.1d:
+; GFX9-FLATSCR: ; %bb.0: ; %main_body
+; GFX9-FLATSCR-NEXT: s_mov_b32 s11, s9
+; GFX9-FLATSCR-NEXT: s_mov_b32 s10, s8
+; GFX9-FLATSCR-NEXT: s_mov_b32 s9, s7
+; GFX9-FLATSCR-NEXT: s_mov_b32 s8, s6
+; GFX9-FLATSCR-NEXT: s_mov_b32 s7, s5
+; GFX9-FLATSCR-NEXT: s_mov_b32 s6, s4
+; GFX9-FLATSCR-NEXT: s_mov_b32 s5, s3
+; GFX9-FLATSCR-NEXT: s_mov_b32 s4, s2
+; GFX9-FLATSCR-NEXT: image_load v0, v0, s[4:11] dmask:0x1 unorm a16
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: load.f32.1d:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: image_load v0, v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm a16
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: load.f32.1d:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: image_load v0, v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D a16
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+main_body:
+ %x = extractelement <2 x i16> %coords, i32 0
+ %v = call <4 x float> @llvm.amdgcn.image.load.1d.v4f32.i16(i32 1, i16 %x, <8 x i32> %rsrc, i32 0, i32 0)
+ ret <4 x float> %v
+}
+
+declare void @llvm.amdgcn.image.store.1d.v4f32.i16(<4 x float>, i32, i16, <8 x i32>, i32, i32)
+
+; from llvm.amdgcn.image.store.a16.ll
+; covers image_store
+;
+define amdgpu_ps void @store_f32_1d(<8 x i32> inreg %rsrc, <2 x i16> %coords, <4 x float> %val) {
+; GFX9-LABEL: store_f32_1d:
+; GFX9: ; %bb.0: ; %main_body
+; GFX9-NEXT: image_store v[1:4], v0, s[0:7] dmask:0x1 unorm a16
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: store_f32_1d:
+; GFX90A: ; %bb.0: ; %main_body
+; GFX90A-NEXT: v_mov_b32_e32 v5, v4
+; GFX90A-NEXT: v_mov_b32_e32 v4, v3
+; GFX90A-NEXT: v_mov_b32_e32 v3, v2
+; GFX90A-NEXT: v_mov_b32_e32 v2, v1
+; GFX90A-NEXT: image_store v[2:5], v0, s[0:7] dmask:0x1 unorm a16
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: store_f32_1d:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: image_store v[1:4], v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm a16
+; GFX10-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: store_f32_1d:
+; GFX9-FLATSCR: ; %bb.0: ; %main_body
+; GFX9-FLATSCR-NEXT: s_mov_b32 s11, s9
+; GFX9-FLATSCR-NEXT: s_mov_b32 s10, s8
+; GFX9-FLATSCR-NEXT: s_mov_b32 s9, s7
+; GFX9-FLATSCR-NEXT: s_mov_b32 s8, s6
+; GFX9-FLATSCR-NEXT: s_mov_b32 s7, s5
+; GFX9-FLATSCR-NEXT: s_mov_b32 s6, s4
+; GFX9-FLATSCR-NEXT: s_mov_b32 s5, s3
+; GFX9-FLATSCR-NEXT: s_mov_b32 s4, s2
+; GFX9-FLATSCR-NEXT: image_store v[1:4], v0, s[4:11] dmask:0x1 unorm a16
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: store_f32_1d:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: image_store v[1:4], v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm a16
+; GFX11-NEXT: s_waitcnt_vscnt null, 0x0
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: store_f32_1d:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: image_store v[1:4], v0, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D a16
+; GFX12-NEXT: s_wait_storecnt 0x0
+; GFX12-NEXT: s_endpgm
+
+main_body:
+ %x = extractelement <2 x i16> %coords, i32 0
+ call void @llvm.amdgcn.image.store.1d.v4f32.i16(<4 x float> %val, i32 1, i16 %x, <8 x i32> %rsrc, i32 0, i32 0)
+ ret void
+}
+
+declare i32 @llvm.amdgcn.image.atomic.swap.1d.i32.i32(i32, i32, <8 x i32>, i32, i32)
+
+; from llvm.amdgcn.image.atomic.dim.ll
+; covers image_atomic (atomic with return)
+;
+define amdgpu_ps float @atomic_swap_1d(<8 x i32> inreg %rsrc, i32 %data, i32 %s) {
+; GFX9-LABEL: atomic_swap_1d:
+; GFX9: ; %bb.0: ; %main_body
+; GFX9-NEXT: image_atomic_swap v0, v1, s[0:7] dmask:0x1 unorm glc
+; GFX9-NEXT: s_waitcnt vmcnt(0)
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX90A-LABEL: atomic_swap_1d:
+; GFX90A: ; %bb.0: ; %main_body
+; GFX90A-NEXT: v_mov_b32_e32 v2, v1
+; GFX90A-NEXT: image_atomic_swap v0, v2, s[0:7] dmask:0x1 unorm glc
+; GFX90A-NEXT: s_waitcnt vmcnt(0)
+; GFX90A-NEXT: ; return to shader part epilog
+;
+; GFX10-LABEL: atomic_swap_1d:
+; GFX10: ; %bb.0: ; %main_body
+; GFX10-NEXT: image_atomic_swap v0, v1, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm glc
+; GFX10-NEXT: s_waitcnt vmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX9-FLATSCR-LABEL: atomic_swap_1d:
+; GFX9-FLATSCR: ; %bb.0: ; %main_body
+; GFX9-FLATSCR-NEXT: s_mov_b32 s11, s9
+; GFX9-FLATSCR-NEXT: s_mov_b32 s10, s8
+; GFX9-FLATSCR-NEXT: s_mov_b32 s9, s7
+; GFX9-FLATSCR-NEXT: s_mov_b32 s8, s6
+; GFX9-FLATSCR-NEXT: s_mov_b32 s7, s5
+; GFX9-FLATSCR-NEXT: s_mov_b32 s6, s4
+; GFX9-FLATSCR-NEXT: s_mov_b32 s5, s3
+; GFX9-FLATSCR-NEXT: s_mov_b32 s4, s2
+; GFX9-FLATSCR-NEXT: image_atomic_swap v0, v1, s[4:11] dmask:0x1 unorm glc
+; GFX9-FLATSCR-NEXT: s_waitcnt vmcnt(0)
+; GFX9-FLATSCR-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: atomic_swap_1d:
+; GFX11: ; %bb.0: ; %main_body
+; GFX11-NEXT: image_atomic_swap v0, v1, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D unorm glc
+; GFX11-NEXT: s_waitcnt vmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: atomic_swap_1d:
+; GFX12: ; %bb.0: ; %main_body
+; GFX12-NEXT: image_atomic_swap v0, v1, s[0:7] dmask:0x1 dim:SQ_RSRC_IMG_1D th:TH_ATOMIC_RETURN
+; GFX12-NEXT: s_wait_loadcnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+main_body:
+ %v = call i32 @llvm.amdgcn.image.atomic.swap.1d.i32.i32(i32 %data, i32 %s, <8 x i32> %rsrc, i32 0, i32 0)
+ %out = bitcast i32 %v to float
+ ret float %out
+}
+
+; from lds-bounds.ll
+; covers ds_write_b64 (atomic without return)
+@compute_lds = external addrspace(3) global [512 x i32], align 16
+;
+define amdgpu_cs void @store_aligned(ptr addrspace(3) %ptr) #0 {
+; GFX9-LABEL: store_aligned:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: v_mov_b32_e32 v1, 42
+; GFX9-NEXT: v_mov_b32_e32 v2, 43
+; GFX9-NEXT: ds_write_b64 v0, v[1:2]
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: store_aligned:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: v_mov_b32_e32 v2, 42
+; GFX90A-NEXT: v_mov_b32_e32 v3, 43
+; GFX90A-NEXT: ds_write_b64 v0, v[2:3]
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: store_aligned:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: v_mov_b32_e32 v1, 42
+; GFX10-NEXT: v_mov_b32_e32 v2, 43
+; GFX10-NEXT: ds_write_b64 v0, v[1:2]
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: store_aligned:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, 42
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v2, 43
+; GFX9-FLATSCR-NEXT: ds_write_b64 v0, v[1:2]
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: store_aligned:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: v_dual_mov_b32 v1, 42 :: v_dual_mov_b32 v2, 43
+; GFX11-NEXT: ds_store_b64 v0, v[1:2]
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: store_aligned:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: v_dual_mov_b32 v1, 42 :: v_dual_mov_b32 v2, 43
+; GFX12-NEXT: ds_store_b64 v0, v[1:2]
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: s_endpgm
+entry:
+ %ptr.gep.1 = getelementptr i32, ptr addrspace(3) %ptr, i32 1
+
+ store i32 42, ptr addrspace(3) %ptr, align 8
+ store i32 43, ptr addrspace(3) %ptr.gep.1
+ ret void
+}
+
+
+; from lds-bounds.ll
+; covers ds_read_b64
+;
+define amdgpu_cs <2 x float> @load_aligned(ptr addrspace(3) %ptr) #0 {
+; GFX9-LABEL: load_aligned:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: ds_read_b64 v[0:1], v0
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX90A-LABEL: load_aligned:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: ds_read_b64 v[0:1], v0
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: ; return to shader part epilog
+;
+; GFX10-LABEL: load_aligned:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: ds_read_b64 v[0:1], v0
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX9-FLATSCR-LABEL: load_aligned:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: ds_read_b64 v[0:1], v0
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: load_aligned:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: ds_load_b64 v[0:1], v0
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: load_aligned:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: ds_load_b64 v[0:1], v0
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+entry:
+ %ptr.gep.1 = getelementptr i32, ptr addrspace(3) %ptr, i32 1
+
+ %v.0 = load i32, ptr addrspace(3) %ptr, align 8
+ %v.1 = load i32, ptr addrspace(3) %ptr.gep.1
+
+ %r.0 = insertelement <2 x i32> poison, i32 %v.0, i32 0
+ %r.1 = insertelement <2 x i32> %r.0, i32 %v.1, i32 1
+ %bc = bitcast <2 x i32> %r.1 to <2 x float>
+ ret <2 x float> %bc
+}
+
+; from lds-bounds.ll
+; covers ds_write2_b32
+;
+define amdgpu_cs void @store_global_const_idx() #0 {
+; GFX9-LABEL: store_global_const_idx:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX9-NEXT: v_mov_b32_e32 v1, 42
+; GFX9-NEXT: v_mov_b32_e32 v2, 43
+; GFX9-NEXT: ds_write2_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: s_endpgm
+;
+; GFX90A-LABEL: store_global_const_idx:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX90A-NEXT: v_mov_b32_e32 v1, 42
+; GFX90A-NEXT: v_mov_b32_e32 v2, 43
+; GFX90A-NEXT: ds_write2_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: s_endpgm
+;
+; GFX10-LABEL: store_global_const_idx:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX10-NEXT: v_mov_b32_e32 v1, 42
+; GFX10-NEXT: v_mov_b32_e32 v2, 43
+; GFX10-NEXT: ds_write2_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: s_endpgm
+;
+; GFX9-FLATSCR-LABEL: store_global_const_idx:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v1, 42
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v2, 43
+; GFX9-FLATSCR-NEXT: ds_write2_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: s_endpgm
+;
+; GFX11-LABEL: store_global_const_idx:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: v_dual_mov_b32 v0, compute_lds@abs32@lo :: v_dual_mov_b32 v1, 42
+; GFX11-NEXT: v_mov_b32_e32 v2, 43
+; GFX11-NEXT: ds_store_2addr_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: s_endpgm
+;
+; GFX12-LABEL: store_global_const_idx:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: v_dual_mov_b32 v0, compute_lds@abs32@lo :: v_dual_mov_b32 v1, 42
+; GFX12-NEXT: v_mov_b32_e32 v2, 43
+; GFX12-NEXT: ds_store_2addr_b32 v0, v1, v2 offset0:3 offset1:4
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: s_endpgm
+entry:
+ %ptr.a = getelementptr [512 x i32], ptr addrspace(3) @compute_lds, i32 0, i32 3
+ %ptr.b = getelementptr [512 x i32], ptr addrspace(3) @compute_lds, i32 0, i32 4
+
+ store i32 42, ptr addrspace(3) %ptr.a
+ store i32 43, ptr addrspace(3) %ptr.b
+ ret void
+}
+
+; from lds-bounds.ll
+; covers ds_read2_b32
+;
+define amdgpu_cs <2 x float> @load_global_const_idx() #0 {
+; GFX9-LABEL: load_global_const_idx:
+; GFX9: ; %bb.0: ; %entry
+; GFX9-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX9-NEXT: ds_read2_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX9-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-NEXT: ; return to shader part epilog
+;
+; GFX90A-LABEL: load_global_const_idx:
+; GFX90A: ; %bb.0: ; %entry
+; GFX90A-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX90A-NEXT: ds_read2_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX90A-NEXT: s_waitcnt lgkmcnt(0)
+; GFX90A-NEXT: ; return to shader part epilog
+;
+; GFX10-LABEL: load_global_const_idx:
+; GFX10: ; %bb.0: ; %entry
+; GFX10-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX10-NEXT: ds_read2_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX10-NEXT: s_waitcnt lgkmcnt(0)
+; GFX10-NEXT: ; return to shader part epilog
+;
+; GFX9-FLATSCR-LABEL: load_global_const_idx:
+; GFX9-FLATSCR: ; %bb.0: ; %entry
+; GFX9-FLATSCR-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX9-FLATSCR-NEXT: ds_read2_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX9-FLATSCR-NEXT: s_waitcnt lgkmcnt(0)
+; GFX9-FLATSCR-NEXT: ; return to shader part epilog
+;
+; GFX11-LABEL: load_global_const_idx:
+; GFX11: ; %bb.0: ; %entry
+; GFX11-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX11-NEXT: ds_load_2addr_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX11-NEXT: s_waitcnt lgkmcnt(0)
+; GFX11-NEXT: ; return to shader part epilog
+;
+; GFX12-LABEL: load_global_const_idx:
+; GFX12: ; %bb.0: ; %entry
+; GFX12-NEXT: v_mov_b32_e32 v0, compute_lds@abs32@lo
+; GFX12-NEXT: ds_load_2addr_b32 v[0:1], v0 offset0:3 offset1:4
+; GFX12-NEXT: s_wait_dscnt 0x0
+; GFX12-NEXT: ; return to shader part epilog
+entry:
+ %ptr.a = getelementptr [512 x i32], ptr addrspace(3) @compute_lds, i32 0, i32 3
+ %ptr.b = getelementptr [512 x i32], ptr addrspace(3) @compute_lds, i32 0, i32 4
+
+ %v.0 = load i32, ptr addrspace(3) %ptr.a
+ %v.1 = load i32, ptr addrspace(3) %ptr.b
+
+ %r.0 = insertelement <2 x i32> poison, i32 %v.0, i32 0
+ %r.1 = insertelement <2 x i32> %r.0, i32 %v.1, i32 1
+ %bc = bitcast <2 x i32> %r.1 to <2 x float>
+ ret <2 x float> %bc
+}
+
diff --git a/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll b/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
index 08426b07bf74..4565c63f08d9 100644
--- a/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
+++ b/llvm/test/CodeGen/LoongArch/emergency-spill-slot.ll
@@ -6,9 +6,9 @@
define void @func() {
; CHECK-LABEL: func:
; CHECK: # %bb.0:
-; CHECK-NEXT: addi.d $sp, $sp, -2048
-; CHECK-NEXT: addi.d $sp, $sp, -2048
-; CHECK-NEXT: addi.d $sp, $sp, -16
+; CHECK-NEXT: lu12i.w $a0, 1
+; CHECK-NEXT: ori $a0, $a0, 16
+; CHECK-NEXT: sub.d $sp, $sp, $a0
; CHECK-NEXT: .cfi_def_cfa_offset 4112
; CHECK-NEXT: pcalau12i $a0, %got_pc_hi20(var)
; CHECK-NEXT: ld.d $a1, $a0, %got_pc_lo12(var)
diff --git a/llvm/test/CodeGen/RISCV/interrupt-attr-nocall.ll b/llvm/test/CodeGen/RISCV/interrupt-attr-nocall.ll
index 263743d39a8e..fa6ac96b57b1 100644
--- a/llvm/test/CodeGen/RISCV/interrupt-attr-nocall.ll
+++ b/llvm/test/CodeGen/RISCV/interrupt-attr-nocall.ll
@@ -412,51 +412,39 @@ define void @foo_double() nounwind #0 {
;
; CHECK-RV32IF-LABEL: foo_double:
; CHECK-RV32IF: # %bb.0:
-; CHECK-RV32IF-NEXT: addi sp, sp, -192
-; CHECK-RV32IF-NEXT: sw ra, 188(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t0, 184(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t1, 180(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t2, 176(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a0, 172(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a1, 168(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a2, 164(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a3, 160(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a4, 156(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a5, 152(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a6, 148(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a7, 144(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t3, 140(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t4, 136(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t5, 132(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t6, 128(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft0, 124(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft1, 120(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft2, 116(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft3, 112(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft4, 108(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft5, 104(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft6, 100(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft7, 96(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs0, 92(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs1, 88(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa0, 84(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa1, 80(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa2, 76(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa3, 72(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa4, 68(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa5, 64(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa6, 60(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa7, 56(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs2, 52(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs3, 48(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs4, 44(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs5, 40(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs6, 36(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs7, 32(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs8, 28(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs9, 24(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs10, 20(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs11, 16(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: addi sp, sp, -144
+; CHECK-RV32IF-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t0, 136(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t1, 132(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t2, 128(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a0, 124(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a1, 120(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a2, 116(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a3, 112(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a4, 108(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a5, 104(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a6, 100(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a7, 96(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t3, 92(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t4, 88(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t5, 84(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t6, 80(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft0, 76(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft1, 72(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft2, 68(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft3, 64(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft4, 60(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft5, 56(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft6, 52(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft7, 48(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa0, 44(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa1, 40(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa2, 36(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa3, 32(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa4, 28(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa5, 24(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa6, 20(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa7, 16(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft8, 12(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft9, 8(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft10, 4(sp) # 4-byte Folded Spill
@@ -471,55 +459,43 @@ define void @foo_double() nounwind #0 {
; CHECK-RV32IF-NEXT: lui a2, %hi(g)
; CHECK-RV32IF-NEXT: sw a1, %lo(g+4)(a2)
; CHECK-RV32IF-NEXT: sw a0, %lo(g)(a2)
-; CHECK-RV32IF-NEXT: lw ra, 188(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t0, 184(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t1, 180(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t2, 176(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a0, 172(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a1, 168(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a2, 164(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a3, 160(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a4, 156(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a5, 152(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a6, 148(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a7, 144(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t3, 140(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t4, 136(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t5, 132(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t6, 128(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft0, 124(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft1, 120(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft2, 116(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft3, 112(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft4, 108(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft5, 104(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft6, 100(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft7, 96(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs0, 92(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs1, 88(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa0, 84(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa1, 80(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa2, 76(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa3, 72(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa4, 68(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa5, 64(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa6, 60(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa7, 56(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs2, 52(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs3, 48(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs4, 44(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs5, 40(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs6, 36(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs7, 32(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs8, 28(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs9, 24(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs10, 20(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs11, 16(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t0, 136(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t1, 132(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t2, 128(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a0, 124(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a1, 120(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a2, 116(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a3, 112(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a4, 108(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a5, 104(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a6, 100(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a7, 96(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t3, 92(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t4, 88(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t5, 84(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t6, 80(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft0, 76(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft1, 72(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft2, 68(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft3, 64(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft4, 60(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft5, 56(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft6, 52(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft7, 48(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa0, 44(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa1, 40(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa2, 36(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa3, 32(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa4, 28(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa5, 24(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa6, 20(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa7, 16(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft8, 12(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft9, 8(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft10, 4(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft11, 0(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: addi sp, sp, 192
+; CHECK-RV32IF-NEXT: addi sp, sp, 144
; CHECK-RV32IF-NEXT: mret
;
; CHECK-RV32IFD-LABEL: foo_double:
@@ -604,57 +580,45 @@ define void @foo_fp_double() nounwind #1 {
;
; CHECK-RV32IF-LABEL: foo_fp_double:
; CHECK-RV32IF: # %bb.0:
-; CHECK-RV32IF-NEXT: addi sp, sp, -208
-; CHECK-RV32IF-NEXT: sw ra, 204(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t0, 200(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t1, 196(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t2, 192(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw s0, 188(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a0, 184(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a1, 180(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a2, 176(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a3, 172(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a4, 168(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a5, 164(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a6, 160(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw a7, 156(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t3, 152(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t4, 148(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t5, 144(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: sw t6, 140(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft0, 136(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft1, 132(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft2, 128(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft3, 124(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft4, 120(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft5, 116(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft6, 112(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw ft7, 108(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs0, 104(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs1, 100(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa0, 96(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa1, 92(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa2, 88(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa3, 84(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa4, 80(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa5, 76(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa6, 72(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fa7, 68(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs2, 64(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs3, 60(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs4, 56(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs5, 52(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs6, 48(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs7, 44(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs8, 40(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs9, 36(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs10, 32(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: fsw fs11, 28(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: addi sp, sp, -160
+; CHECK-RV32IF-NEXT: sw ra, 156(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t0, 152(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t1, 148(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t2, 144(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw s0, 140(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a0, 136(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a1, 132(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a2, 128(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a3, 124(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a4, 120(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a5, 116(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a6, 112(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw a7, 108(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t3, 104(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t4, 100(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t5, 96(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: sw t6, 92(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft0, 88(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft1, 84(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft2, 80(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft3, 76(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft4, 72(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft5, 68(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft6, 64(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw ft7, 60(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa0, 56(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa1, 52(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa2, 48(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa3, 44(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa4, 40(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa5, 36(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa6, 32(sp) # 4-byte Folded Spill
+; CHECK-RV32IF-NEXT: fsw fa7, 28(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft8, 24(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft9, 20(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft10, 16(sp) # 4-byte Folded Spill
; CHECK-RV32IF-NEXT: fsw ft11, 12(sp) # 4-byte Folded Spill
-; CHECK-RV32IF-NEXT: addi s0, sp, 208
+; CHECK-RV32IF-NEXT: addi s0, sp, 160
; CHECK-RV32IF-NEXT: lui a1, %hi(h)
; CHECK-RV32IF-NEXT: lw a0, %lo(h)(a1)
; CHECK-RV32IF-NEXT: lw a1, %lo(h+4)(a1)
@@ -665,56 +629,44 @@ define void @foo_fp_double() nounwind #1 {
; CHECK-RV32IF-NEXT: lui a2, %hi(g)
; CHECK-RV32IF-NEXT: sw a1, %lo(g+4)(a2)
; CHECK-RV32IF-NEXT: sw a0, %lo(g)(a2)
-; CHECK-RV32IF-NEXT: lw ra, 204(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t0, 200(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t1, 196(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t2, 192(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw s0, 188(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a0, 184(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a1, 180(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a2, 176(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a3, 172(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a4, 168(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a5, 164(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a6, 160(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw a7, 156(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t3, 152(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t4, 148(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t5, 144(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: lw t6, 140(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft0, 136(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft1, 132(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft2, 128(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft3, 124(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft4, 120(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft5, 116(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft6, 112(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw ft7, 108(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs0, 104(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs1, 100(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa0, 96(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa1, 92(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa2, 88(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa3, 84(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa4, 80(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa5, 76(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa6, 72(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fa7, 68(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs2, 64(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs3, 60(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs4, 56(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs5, 52(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs6, 48(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs7, 44(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs8, 40(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs9, 36(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs10, 32(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: flw fs11, 28(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw ra, 156(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t0, 152(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t1, 148(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t2, 144(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw s0, 140(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a0, 136(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a1, 132(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a2, 128(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a3, 124(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a4, 120(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a5, 116(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a6, 112(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw a7, 108(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t3, 104(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t4, 100(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t5, 96(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: lw t6, 92(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft0, 88(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft1, 84(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft2, 80(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft3, 76(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft4, 72(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft5, 68(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft6, 64(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw ft7, 60(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa0, 56(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa1, 52(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa2, 48(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa3, 44(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa4, 40(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa5, 36(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa6, 32(sp) # 4-byte Folded Reload
+; CHECK-RV32IF-NEXT: flw fa7, 28(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft8, 24(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft9, 20(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft10, 16(sp) # 4-byte Folded Reload
; CHECK-RV32IF-NEXT: flw ft11, 12(sp) # 4-byte Folded Reload
-; CHECK-RV32IF-NEXT: addi sp, sp, 208
+; CHECK-RV32IF-NEXT: addi sp, sp, 160
; CHECK-RV32IF-NEXT: mret
;
; CHECK-RV32IFD-LABEL: foo_fp_double:
diff --git a/llvm/test/CodeGen/RISCV/interrupt-attr.ll b/llvm/test/CodeGen/RISCV/interrupt-attr.ll
index 50c789f8f86d..739c9d8d0b0a 100644
--- a/llvm/test/CodeGen/RISCV/interrupt-attr.ll
+++ b/llvm/test/CodeGen/RISCV/interrupt-attr.ll
@@ -115,208 +115,160 @@ define void @foo_with_call() #1 {
;
; CHECK-RV32-F-LABEL: foo_with_call:
; CHECK-RV32-F: # %bb.0:
-; CHECK-RV32-F-NEXT: addi sp, sp, -192
-; CHECK-RV32-F-NEXT: sw ra, 188(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t0, 184(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t1, 180(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t2, 176(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a0, 172(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a1, 168(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a2, 164(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a3, 160(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a4, 156(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a5, 152(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a6, 148(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a7, 144(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t3, 140(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t4, 136(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t5, 132(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t6, 128(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft0, 124(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft1, 120(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft2, 116(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft3, 112(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft4, 108(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft5, 104(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft6, 100(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft7, 96(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs0, 92(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs1, 88(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa0, 84(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa1, 80(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa2, 76(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa3, 72(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa4, 68(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa5, 64(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa6, 60(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa7, 56(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs2, 52(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs3, 48(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs4, 44(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs5, 40(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs6, 36(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs7, 32(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs8, 28(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs9, 24(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs10, 20(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs11, 16(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: addi sp, sp, -144
+; CHECK-RV32-F-NEXT: sw ra, 140(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t0, 136(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t1, 132(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t2, 128(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a0, 124(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a1, 120(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a2, 116(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a3, 112(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a4, 108(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a5, 104(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a6, 100(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a7, 96(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t3, 92(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t4, 88(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t5, 84(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t6, 80(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft0, 76(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft1, 72(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft2, 68(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft3, 64(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft4, 60(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft5, 56(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft6, 52(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft7, 48(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa0, 44(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa1, 40(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa2, 36(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa3, 32(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa4, 28(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa5, 24(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa6, 20(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa7, 16(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft8, 12(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft9, 8(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft10, 4(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft11, 0(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: call otherfoo
-; CHECK-RV32-F-NEXT: lw ra, 188(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t0, 184(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t1, 180(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t2, 176(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a0, 172(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a1, 168(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a2, 164(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a3, 160(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a4, 156(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a5, 152(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a6, 148(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a7, 144(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t3, 140(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t4, 136(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t5, 132(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t6, 128(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft0, 124(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft1, 120(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft2, 116(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft3, 112(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft4, 108(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft5, 104(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft6, 100(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft7, 96(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs0, 92(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs1, 88(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa0, 84(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa1, 80(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa2, 76(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa3, 72(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa4, 68(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa5, 64(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa6, 60(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa7, 56(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs2, 52(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs3, 48(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs4, 44(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs5, 40(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs6, 36(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs7, 32(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs8, 28(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs9, 24(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs10, 20(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs11, 16(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw ra, 140(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t0, 136(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t1, 132(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t2, 128(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a0, 124(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a1, 120(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a2, 116(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a3, 112(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a4, 108(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a5, 104(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a6, 100(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a7, 96(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t3, 92(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t4, 88(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t5, 84(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t6, 80(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft0, 76(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft1, 72(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft2, 68(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft3, 64(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft4, 60(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft5, 56(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft6, 52(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft7, 48(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa0, 44(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa1, 40(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa2, 36(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa3, 32(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa4, 28(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa5, 24(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa6, 20(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa7, 16(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft8, 12(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft9, 8(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft10, 4(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft11, 0(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: addi sp, sp, 192
+; CHECK-RV32-F-NEXT: addi sp, sp, 144
; CHECK-RV32-F-NEXT: mret
;
; CHECK-RV32-FD-LABEL: foo_with_call:
; CHECK-RV32-FD: # %bb.0:
-; CHECK-RV32-FD-NEXT: addi sp, sp, -320
-; CHECK-RV32-FD-NEXT: sw ra, 316(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t0, 312(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t1, 308(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t2, 304(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a0, 300(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a1, 296(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a2, 292(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a3, 288(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a4, 284(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a5, 280(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a6, 276(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a7, 272(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t3, 268(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t4, 264(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t5, 260(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t6, 256(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft0, 248(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft1, 240(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft2, 232(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft3, 224(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft4, 216(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft5, 208(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft6, 200(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft7, 192(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs0, 184(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs1, 176(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa0, 168(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa1, 160(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa2, 152(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa3, 144(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa4, 136(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa5, 128(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa6, 120(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa7, 112(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs2, 104(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs3, 96(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs4, 88(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs5, 80(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs6, 72(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs7, 64(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs8, 56(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs9, 48(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs10, 40(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs11, 32(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: addi sp, sp, -224
+; CHECK-RV32-FD-NEXT: sw ra, 220(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t0, 216(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t1, 212(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t2, 208(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a0, 204(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a1, 200(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a2, 196(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a3, 192(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a4, 188(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a5, 184(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a6, 180(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a7, 176(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t3, 172(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t4, 168(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t5, 164(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t6, 160(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft0, 152(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft1, 144(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft2, 136(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft3, 128(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft4, 120(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft5, 112(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft6, 104(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft7, 96(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa0, 88(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa1, 80(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa2, 72(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa3, 64(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa4, 56(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa5, 48(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa6, 40(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa7, 32(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft8, 24(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft9, 16(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft10, 8(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft11, 0(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: call otherfoo
-; CHECK-RV32-FD-NEXT: lw ra, 316(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t0, 312(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t1, 308(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t2, 304(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a0, 300(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a1, 296(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a2, 292(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a3, 288(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a4, 284(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a5, 280(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a6, 276(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a7, 272(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t3, 268(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t4, 264(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t5, 260(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t6, 256(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft0, 248(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft1, 240(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft2, 232(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft3, 224(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft4, 216(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft5, 208(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft6, 200(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft7, 192(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs0, 184(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs1, 176(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa0, 168(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa1, 160(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa2, 152(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa3, 144(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa4, 136(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa5, 128(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa6, 120(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa7, 112(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs2, 104(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs3, 96(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs4, 88(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs5, 80(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs6, 72(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs7, 64(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs8, 56(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs9, 48(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs10, 40(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs11, 32(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw ra, 220(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t0, 216(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t1, 212(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t2, 208(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a0, 204(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a1, 200(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a2, 196(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a3, 192(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a4, 188(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a5, 184(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a6, 180(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a7, 176(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t3, 172(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t4, 168(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t5, 164(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t6, 160(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft0, 152(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft1, 144(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft2, 136(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft3, 128(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft4, 120(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft5, 112(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft6, 104(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft7, 96(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa0, 88(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa1, 80(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa2, 72(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa3, 64(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa4, 56(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa5, 48(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa6, 40(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa7, 32(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft8, 24(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft9, 16(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft10, 8(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft11, 0(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: addi sp, sp, 320
+; CHECK-RV32-FD-NEXT: addi sp, sp, 224
; CHECK-RV32-FD-NEXT: mret
;
; CHECK-RV32-F-ILP3-LABEL: foo_with_call:
@@ -846,208 +798,160 @@ define void @foo_with_call() #1 {
;
; CHECK-RV64-F-LABEL: foo_with_call:
; CHECK-RV64-F: # %bb.0:
-; CHECK-RV64-F-NEXT: addi sp, sp, -256
-; CHECK-RV64-F-NEXT: sd ra, 248(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t0, 240(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t1, 232(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t2, 224(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a0, 216(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a1, 208(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a2, 200(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a3, 192(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a4, 184(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a5, 176(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a6, 168(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a7, 160(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t3, 152(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t4, 144(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t5, 136(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t6, 128(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft0, 124(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft1, 120(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft2, 116(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft3, 112(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft4, 108(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft5, 104(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft6, 100(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft7, 96(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs0, 92(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs1, 88(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa0, 84(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa1, 80(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa2, 76(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa3, 72(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa4, 68(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa5, 64(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa6, 60(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa7, 56(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs2, 52(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs3, 48(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs4, 44(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs5, 40(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs6, 36(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs7, 32(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs8, 28(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs9, 24(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs10, 20(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs11, 16(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: addi sp, sp, -208
+; CHECK-RV64-F-NEXT: sd ra, 200(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t0, 192(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t1, 184(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t2, 176(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a0, 168(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a1, 160(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a2, 152(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a3, 144(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a4, 136(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a5, 128(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a6, 120(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a7, 112(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t3, 104(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t4, 96(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t5, 88(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t6, 80(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft0, 76(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft1, 72(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft2, 68(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft3, 64(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft4, 60(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft5, 56(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft6, 52(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft7, 48(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa0, 44(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa1, 40(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa2, 36(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa3, 32(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa4, 28(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa5, 24(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa6, 20(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa7, 16(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft8, 12(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft9, 8(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft10, 4(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft11, 0(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: call otherfoo
-; CHECK-RV64-F-NEXT: ld ra, 248(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t0, 240(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t1, 232(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t2, 224(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a0, 216(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a1, 208(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a2, 200(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a3, 192(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a4, 184(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a5, 176(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a6, 168(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a7, 160(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t3, 152(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t4, 144(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t5, 136(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t6, 128(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft0, 124(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft1, 120(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft2, 116(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft3, 112(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft4, 108(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft5, 104(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft6, 100(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft7, 96(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs0, 92(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs1, 88(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa0, 84(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa1, 80(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa2, 76(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa3, 72(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa4, 68(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa5, 64(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa6, 60(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa7, 56(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs2, 52(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs3, 48(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs4, 44(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs5, 40(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs6, 36(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs7, 32(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs8, 28(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs9, 24(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs10, 20(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs11, 16(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld ra, 200(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t0, 192(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t1, 184(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t2, 176(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a0, 168(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a1, 160(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a2, 152(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a3, 144(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a4, 136(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a5, 128(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a6, 120(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a7, 112(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t3, 104(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t4, 96(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t5, 88(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t6, 80(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft0, 76(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft1, 72(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft2, 68(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft3, 64(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft4, 60(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft5, 56(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft6, 52(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft7, 48(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa0, 44(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa1, 40(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa2, 36(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa3, 32(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa4, 28(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa5, 24(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa6, 20(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa7, 16(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft8, 12(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft9, 8(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft10, 4(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft11, 0(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: addi sp, sp, 256
+; CHECK-RV64-F-NEXT: addi sp, sp, 208
; CHECK-RV64-F-NEXT: mret
;
; CHECK-RV64-FD-LABEL: foo_with_call:
; CHECK-RV64-FD: # %bb.0:
-; CHECK-RV64-FD-NEXT: addi sp, sp, -384
-; CHECK-RV64-FD-NEXT: sd ra, 376(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t0, 368(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t1, 360(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t2, 352(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a0, 344(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a1, 336(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a2, 328(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a3, 320(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a4, 312(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a5, 304(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a6, 296(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a7, 288(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t3, 280(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t4, 272(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t5, 264(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t6, 256(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft0, 248(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft1, 240(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft2, 232(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft3, 224(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft4, 216(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft5, 208(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft6, 200(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft7, 192(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs0, 184(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs1, 176(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa0, 168(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa1, 160(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa2, 152(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa3, 144(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa4, 136(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa5, 128(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa6, 120(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa7, 112(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs2, 104(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs3, 96(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs4, 88(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs5, 80(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs6, 72(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs7, 64(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs8, 56(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs9, 48(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs10, 40(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs11, 32(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: addi sp, sp, -288
+; CHECK-RV64-FD-NEXT: sd ra, 280(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t0, 272(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t1, 264(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t2, 256(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a0, 248(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a1, 240(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a2, 232(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a3, 224(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a4, 216(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a5, 208(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a6, 200(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a7, 192(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t3, 184(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t4, 176(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t5, 168(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t6, 160(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft0, 152(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft1, 144(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft2, 136(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft3, 128(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft4, 120(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft5, 112(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft6, 104(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft7, 96(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa0, 88(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa1, 80(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa2, 72(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa3, 64(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa4, 56(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa5, 48(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa6, 40(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa7, 32(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft8, 24(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft9, 16(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft10, 8(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft11, 0(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: call otherfoo
-; CHECK-RV64-FD-NEXT: ld ra, 376(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t0, 368(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t1, 360(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t2, 352(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a0, 344(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a1, 336(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a2, 328(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a3, 320(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a4, 312(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a5, 304(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a6, 296(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a7, 288(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t3, 280(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t4, 272(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t5, 264(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t6, 256(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft0, 248(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft1, 240(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft2, 232(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft3, 224(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft4, 216(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft5, 208(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft6, 200(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft7, 192(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs0, 184(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs1, 176(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa0, 168(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa1, 160(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa2, 152(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa3, 144(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa4, 136(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa5, 128(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa6, 120(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa7, 112(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs2, 104(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs3, 96(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs4, 88(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs5, 80(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs6, 72(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs7, 64(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs8, 56(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs9, 48(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs10, 40(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs11, 32(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld ra, 280(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t0, 272(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t1, 264(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t2, 256(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a0, 248(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a1, 240(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a2, 232(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a3, 224(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a4, 216(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a5, 208(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a6, 200(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a7, 192(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t3, 184(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t4, 176(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t5, 168(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t6, 160(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft0, 152(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft1, 144(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft2, 136(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft3, 128(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft4, 120(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft5, 112(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft6, 104(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft7, 96(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa0, 88(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa1, 80(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa2, 72(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa3, 64(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa4, 56(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa5, 48(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa6, 40(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa7, 32(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft8, 24(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft9, 16(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft10, 8(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft11, 0(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: addi sp, sp, 384
+; CHECK-RV64-FD-NEXT: addi sp, sp, 288
; CHECK-RV64-FD-NEXT: mret
;
; CHECK-RV64-F-LP64-LABEL: foo_with_call:
@@ -1711,214 +1615,166 @@ define void @foo_fp_with_call() #2 {
;
; CHECK-RV32-F-LABEL: foo_fp_with_call:
; CHECK-RV32-F: # %bb.0:
-; CHECK-RV32-F-NEXT: addi sp, sp, -208
-; CHECK-RV32-F-NEXT: sw ra, 204(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t0, 200(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t1, 196(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t2, 192(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw s0, 188(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a0, 184(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a1, 180(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a2, 176(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a3, 172(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a4, 168(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a5, 164(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a6, 160(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw a7, 156(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t3, 152(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t4, 148(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t5, 144(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: sw t6, 140(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft0, 136(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft1, 132(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft2, 128(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft3, 124(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft4, 120(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft5, 116(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft6, 112(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw ft7, 108(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs0, 104(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs1, 100(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa0, 96(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa1, 92(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa2, 88(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa3, 84(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa4, 80(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa5, 76(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa6, 72(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fa7, 68(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs2, 64(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs3, 60(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs4, 56(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs5, 52(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs6, 48(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs7, 44(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs8, 40(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs9, 36(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs10, 32(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: fsw fs11, 28(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: addi sp, sp, -160
+; CHECK-RV32-F-NEXT: sw ra, 156(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t0, 152(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t1, 148(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t2, 144(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw s0, 140(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a0, 136(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a1, 132(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a2, 128(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a3, 124(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a4, 120(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a5, 116(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a6, 112(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw a7, 108(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t3, 104(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t4, 100(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t5, 96(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: sw t6, 92(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft0, 88(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft1, 84(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft2, 80(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft3, 76(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft4, 72(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft5, 68(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft6, 64(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw ft7, 60(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa0, 56(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa1, 52(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa2, 48(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa3, 44(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa4, 40(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa5, 36(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa6, 32(sp) # 4-byte Folded Spill
+; CHECK-RV32-F-NEXT: fsw fa7, 28(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft8, 24(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft9, 20(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft10, 16(sp) # 4-byte Folded Spill
; CHECK-RV32-F-NEXT: fsw ft11, 12(sp) # 4-byte Folded Spill
-; CHECK-RV32-F-NEXT: addi s0, sp, 208
+; CHECK-RV32-F-NEXT: addi s0, sp, 160
; CHECK-RV32-F-NEXT: call otherfoo
-; CHECK-RV32-F-NEXT: lw ra, 204(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t0, 200(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t1, 196(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t2, 192(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw s0, 188(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a0, 184(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a1, 180(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a2, 176(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a3, 172(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a4, 168(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a5, 164(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a6, 160(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw a7, 156(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t3, 152(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t4, 148(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t5, 144(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: lw t6, 140(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft0, 136(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft1, 132(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft2, 128(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft3, 124(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft4, 120(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft5, 116(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft6, 112(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw ft7, 108(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs0, 104(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs1, 100(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa0, 96(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa1, 92(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa2, 88(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa3, 84(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa4, 80(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa5, 76(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa6, 72(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fa7, 68(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs2, 64(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs3, 60(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs4, 56(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs5, 52(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs6, 48(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs7, 44(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs8, 40(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs9, 36(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs10, 32(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: flw fs11, 28(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw ra, 156(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t0, 152(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t1, 148(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t2, 144(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw s0, 140(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a0, 136(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a1, 132(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a2, 128(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a3, 124(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a4, 120(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a5, 116(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a6, 112(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw a7, 108(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t3, 104(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t4, 100(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t5, 96(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: lw t6, 92(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft0, 88(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft1, 84(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft2, 80(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft3, 76(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft4, 72(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft5, 68(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft6, 64(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw ft7, 60(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa0, 56(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa1, 52(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa2, 48(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa3, 44(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa4, 40(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa5, 36(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa6, 32(sp) # 4-byte Folded Reload
+; CHECK-RV32-F-NEXT: flw fa7, 28(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft8, 24(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft9, 20(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft10, 16(sp) # 4-byte Folded Reload
; CHECK-RV32-F-NEXT: flw ft11, 12(sp) # 4-byte Folded Reload
-; CHECK-RV32-F-NEXT: addi sp, sp, 208
+; CHECK-RV32-F-NEXT: addi sp, sp, 160
; CHECK-RV32-F-NEXT: mret
;
; CHECK-RV32-FD-LABEL: foo_fp_with_call:
; CHECK-RV32-FD: # %bb.0:
-; CHECK-RV32-FD-NEXT: addi sp, sp, -336
-; CHECK-RV32-FD-NEXT: sw ra, 332(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t0, 328(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t1, 324(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t2, 320(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw s0, 316(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a0, 312(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a1, 308(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a2, 304(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a3, 300(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a4, 296(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a5, 292(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a6, 288(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw a7, 284(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t3, 280(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t4, 276(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t5, 272(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: sw t6, 268(sp) # 4-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft0, 256(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft1, 248(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft2, 240(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft3, 232(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft4, 224(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft5, 216(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft6, 208(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd ft7, 200(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs0, 192(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs1, 184(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa0, 176(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa1, 168(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa2, 160(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa3, 152(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa4, 144(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa5, 136(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa6, 128(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fa7, 120(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs2, 112(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs3, 104(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs4, 96(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs5, 88(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs6, 80(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs7, 72(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs8, 64(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs9, 56(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs10, 48(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: fsd fs11, 40(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: addi sp, sp, -240
+; CHECK-RV32-FD-NEXT: sw ra, 236(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t0, 232(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t1, 228(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t2, 224(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw s0, 220(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a0, 216(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a1, 212(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a2, 208(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a3, 204(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a4, 200(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a5, 196(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a6, 192(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw a7, 188(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t3, 184(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t4, 180(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t5, 176(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: sw t6, 172(sp) # 4-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft0, 160(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft1, 152(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft2, 144(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft3, 136(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft4, 128(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft5, 120(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft6, 112(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd ft7, 104(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa0, 96(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa1, 88(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa2, 80(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa3, 72(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa4, 64(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa5, 56(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa6, 48(sp) # 8-byte Folded Spill
+; CHECK-RV32-FD-NEXT: fsd fa7, 40(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft8, 32(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft9, 24(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft10, 16(sp) # 8-byte Folded Spill
; CHECK-RV32-FD-NEXT: fsd ft11, 8(sp) # 8-byte Folded Spill
-; CHECK-RV32-FD-NEXT: addi s0, sp, 336
+; CHECK-RV32-FD-NEXT: addi s0, sp, 240
; CHECK-RV32-FD-NEXT: call otherfoo
-; CHECK-RV32-FD-NEXT: lw ra, 332(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t0, 328(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t1, 324(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t2, 320(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw s0, 316(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a0, 312(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a1, 308(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a2, 304(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a3, 300(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a4, 296(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a5, 292(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a6, 288(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw a7, 284(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t3, 280(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t4, 276(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t5, 272(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: lw t6, 268(sp) # 4-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft0, 256(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft1, 248(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft2, 240(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft3, 232(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft4, 224(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft5, 216(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft6, 208(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld ft7, 200(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs0, 192(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs1, 184(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa0, 176(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa1, 168(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa2, 160(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa3, 152(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa4, 144(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa5, 136(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa6, 128(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fa7, 120(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs2, 112(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs3, 104(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs4, 96(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs5, 88(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs6, 80(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs7, 72(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs8, 64(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs9, 56(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs10, 48(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: fld fs11, 40(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw ra, 236(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t0, 232(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t1, 228(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t2, 224(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw s0, 220(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a0, 216(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a1, 212(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a2, 208(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a3, 204(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a4, 200(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a5, 196(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a6, 192(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw a7, 188(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t3, 184(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t4, 180(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t5, 176(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: lw t6, 172(sp) # 4-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft0, 160(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft1, 152(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft2, 144(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft3, 136(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft4, 128(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft5, 120(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft6, 112(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld ft7, 104(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa0, 96(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa1, 88(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa2, 80(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa3, 72(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa4, 64(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa5, 56(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa6, 48(sp) # 8-byte Folded Reload
+; CHECK-RV32-FD-NEXT: fld fa7, 40(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft8, 32(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft9, 24(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft10, 16(sp) # 8-byte Folded Reload
; CHECK-RV32-FD-NEXT: fld ft11, 8(sp) # 8-byte Folded Reload
-; CHECK-RV32-FD-NEXT: addi sp, sp, 336
+; CHECK-RV32-FD-NEXT: addi sp, sp, 240
; CHECK-RV32-FD-NEXT: mret
;
; CHECK-RV32-F-ILP3-LABEL: foo_fp_with_call:
@@ -2469,214 +2325,166 @@ define void @foo_fp_with_call() #2 {
;
; CHECK-RV64-F-LABEL: foo_fp_with_call:
; CHECK-RV64-F: # %bb.0:
-; CHECK-RV64-F-NEXT: addi sp, sp, -272
-; CHECK-RV64-F-NEXT: sd ra, 264(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t0, 256(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t1, 248(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t2, 240(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd s0, 232(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a0, 224(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a1, 216(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a2, 208(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a3, 200(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a4, 192(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a5, 184(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a6, 176(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd a7, 168(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t3, 160(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t4, 152(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t5, 144(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: sd t6, 136(sp) # 8-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft0, 132(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft1, 128(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft2, 124(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft3, 120(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft4, 116(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft5, 112(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft6, 108(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw ft7, 104(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs0, 100(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs1, 96(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa0, 92(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa1, 88(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa2, 84(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa3, 80(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa4, 76(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa5, 72(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa6, 68(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fa7, 64(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs2, 60(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs3, 56(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs4, 52(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs5, 48(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs6, 44(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs7, 40(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs8, 36(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs9, 32(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs10, 28(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: fsw fs11, 24(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: addi sp, sp, -224
+; CHECK-RV64-F-NEXT: sd ra, 216(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t0, 208(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t1, 200(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t2, 192(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd s0, 184(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a0, 176(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a1, 168(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a2, 160(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a3, 152(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a4, 144(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a5, 136(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a6, 128(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd a7, 120(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t3, 112(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t4, 104(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t5, 96(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: sd t6, 88(sp) # 8-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft0, 84(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft1, 80(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft2, 76(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft3, 72(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft4, 68(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft5, 64(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft6, 60(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw ft7, 56(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa0, 52(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa1, 48(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa2, 44(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa3, 40(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa4, 36(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa5, 32(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa6, 28(sp) # 4-byte Folded Spill
+; CHECK-RV64-F-NEXT: fsw fa7, 24(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft8, 20(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft9, 16(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft10, 12(sp) # 4-byte Folded Spill
; CHECK-RV64-F-NEXT: fsw ft11, 8(sp) # 4-byte Folded Spill
-; CHECK-RV64-F-NEXT: addi s0, sp, 272
+; CHECK-RV64-F-NEXT: addi s0, sp, 224
; CHECK-RV64-F-NEXT: call otherfoo
-; CHECK-RV64-F-NEXT: ld ra, 264(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t0, 256(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t1, 248(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t2, 240(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld s0, 232(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a0, 224(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a1, 216(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a2, 208(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a3, 200(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a4, 192(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a5, 184(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a6, 176(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld a7, 168(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t3, 160(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t4, 152(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t5, 144(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: ld t6, 136(sp) # 8-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft0, 132(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft1, 128(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft2, 124(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft3, 120(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft4, 116(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft5, 112(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft6, 108(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw ft7, 104(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs0, 100(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs1, 96(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa0, 92(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa1, 88(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa2, 84(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa3, 80(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa4, 76(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa5, 72(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa6, 68(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fa7, 64(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs2, 60(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs3, 56(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs4, 52(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs5, 48(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs6, 44(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs7, 40(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs8, 36(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs9, 32(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs10, 28(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: flw fs11, 24(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld ra, 216(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t0, 208(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t1, 200(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t2, 192(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld s0, 184(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a0, 176(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a1, 168(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a2, 160(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a3, 152(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a4, 144(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a5, 136(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a6, 128(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld a7, 120(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t3, 112(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t4, 104(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t5, 96(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: ld t6, 88(sp) # 8-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft0, 84(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft1, 80(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft2, 76(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft3, 72(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft4, 68(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft5, 64(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft6, 60(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw ft7, 56(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa0, 52(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa1, 48(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa2, 44(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa3, 40(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa4, 36(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa5, 32(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa6, 28(sp) # 4-byte Folded Reload
+; CHECK-RV64-F-NEXT: flw fa7, 24(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft8, 20(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft9, 16(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft10, 12(sp) # 4-byte Folded Reload
; CHECK-RV64-F-NEXT: flw ft11, 8(sp) # 4-byte Folded Reload
-; CHECK-RV64-F-NEXT: addi sp, sp, 272
+; CHECK-RV64-F-NEXT: addi sp, sp, 224
; CHECK-RV64-F-NEXT: mret
;
; CHECK-RV64-FD-LABEL: foo_fp_with_call:
; CHECK-RV64-FD: # %bb.0:
-; CHECK-RV64-FD-NEXT: addi sp, sp, -400
-; CHECK-RV64-FD-NEXT: sd ra, 392(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t0, 384(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t1, 376(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t2, 368(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd s0, 360(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a0, 352(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a1, 344(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a2, 336(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a3, 328(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a4, 320(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a5, 312(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a6, 304(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd a7, 296(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t3, 288(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t4, 280(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t5, 272(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: sd t6, 264(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft0, 256(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft1, 248(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft2, 240(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft3, 232(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft4, 224(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft5, 216(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft6, 208(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd ft7, 200(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs0, 192(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs1, 184(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa0, 176(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa1, 168(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa2, 160(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa3, 152(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa4, 144(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa5, 136(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa6, 128(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fa7, 120(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs2, 112(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs3, 104(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs4, 96(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs5, 88(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs6, 80(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs7, 72(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs8, 64(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs9, 56(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs10, 48(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: fsd fs11, 40(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: addi sp, sp, -304
+; CHECK-RV64-FD-NEXT: sd ra, 296(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t0, 288(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t1, 280(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t2, 272(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd s0, 264(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a0, 256(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a1, 248(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a2, 240(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a3, 232(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a4, 224(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a5, 216(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a6, 208(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd a7, 200(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t3, 192(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t4, 184(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t5, 176(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: sd t6, 168(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft0, 160(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft1, 152(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft2, 144(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft3, 136(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft4, 128(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft5, 120(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft6, 112(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd ft7, 104(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa0, 96(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa1, 88(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa2, 80(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa3, 72(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa4, 64(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa5, 56(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa6, 48(sp) # 8-byte Folded Spill
+; CHECK-RV64-FD-NEXT: fsd fa7, 40(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft8, 32(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft9, 24(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft10, 16(sp) # 8-byte Folded Spill
; CHECK-RV64-FD-NEXT: fsd ft11, 8(sp) # 8-byte Folded Spill
-; CHECK-RV64-FD-NEXT: addi s0, sp, 400
+; CHECK-RV64-FD-NEXT: addi s0, sp, 304
; CHECK-RV64-FD-NEXT: call otherfoo
-; CHECK-RV64-FD-NEXT: ld ra, 392(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t0, 384(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t1, 376(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t2, 368(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld s0, 360(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a0, 352(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a1, 344(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a2, 336(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a3, 328(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a4, 320(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a5, 312(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a6, 304(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld a7, 296(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t3, 288(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t4, 280(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t5, 272(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: ld t6, 264(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft0, 256(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft1, 248(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft2, 240(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft3, 232(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft4, 224(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft5, 216(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft6, 208(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld ft7, 200(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs0, 192(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs1, 184(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa0, 176(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa1, 168(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa2, 160(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa3, 152(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa4, 144(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa5, 136(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa6, 128(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fa7, 120(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs2, 112(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs3, 104(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs4, 96(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs5, 88(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs6, 80(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs7, 72(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs8, 64(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs9, 56(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs10, 48(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: fld fs11, 40(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld ra, 296(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t0, 288(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t1, 280(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t2, 272(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld s0, 264(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a0, 256(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a1, 248(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a2, 240(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a3, 232(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a4, 224(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a5, 216(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a6, 208(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld a7, 200(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t3, 192(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t4, 184(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t5, 176(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: ld t6, 168(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft0, 160(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft1, 152(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft2, 144(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft3, 136(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft4, 128(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft5, 120(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft6, 112(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld ft7, 104(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa0, 96(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa1, 88(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa2, 80(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa3, 72(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa4, 64(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa5, 56(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa6, 48(sp) # 8-byte Folded Reload
+; CHECK-RV64-FD-NEXT: fld fa7, 40(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft8, 32(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft9, 24(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft10, 16(sp) # 8-byte Folded Reload
; CHECK-RV64-FD-NEXT: fld ft11, 8(sp) # 8-byte Folded Reload
-; CHECK-RV64-FD-NEXT: addi sp, sp, 400
+; CHECK-RV64-FD-NEXT: addi sp, sp, 304
; CHECK-RV64-FD-NEXT: mret
;
; CHECK-RV64-F-LP64-LABEL: foo_fp_with_call:
diff --git a/llvm/test/CodeGen/RISCV/rv64zba.ll b/llvm/test/CodeGen/RISCV/rv64zba.ll
index 7e32253c8653..067addc819f7 100644
--- a/llvm/test/CodeGen/RISCV/rv64zba.ll
+++ b/llvm/test/CodeGen/RISCV/rv64zba.ll
@@ -1404,9 +1404,8 @@ define i64 @sh6_sh3_add2(i64 noundef %x, i64 noundef %y, i64 noundef %z) {
;
; RV64ZBA-LABEL: sh6_sh3_add2:
; RV64ZBA: # %bb.0: # %entry
-; RV64ZBA-NEXT: slli a1, a1, 6
-; RV64ZBA-NEXT: add a0, a1, a0
-; RV64ZBA-NEXT: sh3add a0, a2, a0
+; RV64ZBA-NEXT: sh3add a1, a1, a2
+; RV64ZBA-NEXT: sh3add a0, a1, a0
; RV64ZBA-NEXT: ret
entry:
%shl = shl i64 %z, 3
@@ -2111,9 +2110,8 @@ define i64 @array_index_sh1_sh3(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh1_sh3:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 4
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh3add a0, a2, a0
+; RV64ZBA-NEXT: sh1add a1, a1, a2
+; RV64ZBA-NEXT: sh3add a0, a1, a0
; RV64ZBA-NEXT: ld a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [2 x i64], ptr %p, i64 %idx1, i64 %idx2
@@ -2174,9 +2172,8 @@ define i32 @array_index_sh2_sh2(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh2_sh2:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 4
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh2add a0, a2, a0
+; RV64ZBA-NEXT: sh2add a1, a1, a2
+; RV64ZBA-NEXT: sh2add a0, a1, a0
; RV64ZBA-NEXT: lw a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [4 x i32], ptr %p, i64 %idx1, i64 %idx2
@@ -2196,9 +2193,8 @@ define i64 @array_index_sh2_sh3(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh2_sh3:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 5
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh3add a0, a2, a0
+; RV64ZBA-NEXT: sh2add a1, a1, a2
+; RV64ZBA-NEXT: sh3add a0, a1, a0
; RV64ZBA-NEXT: ld a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [4 x i64], ptr %p, i64 %idx1, i64 %idx2
@@ -2238,9 +2234,8 @@ define i16 @array_index_sh3_sh1(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh3_sh1:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 4
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh1add a0, a2, a0
+; RV64ZBA-NEXT: sh3add a1, a1, a2
+; RV64ZBA-NEXT: sh1add a0, a1, a0
; RV64ZBA-NEXT: lh a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [8 x i16], ptr %p, i64 %idx1, i64 %idx2
@@ -2260,9 +2255,8 @@ define i32 @array_index_sh3_sh2(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh3_sh2:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 5
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh2add a0, a2, a0
+; RV64ZBA-NEXT: sh3add a1, a1, a2
+; RV64ZBA-NEXT: sh2add a0, a1, a0
; RV64ZBA-NEXT: lw a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [8 x i32], ptr %p, i64 %idx1, i64 %idx2
@@ -2282,9 +2276,8 @@ define i64 @array_index_sh3_sh3(ptr %p, i64 %idx1, i64 %idx2) {
;
; RV64ZBA-LABEL: array_index_sh3_sh3:
; RV64ZBA: # %bb.0:
-; RV64ZBA-NEXT: slli a1, a1, 6
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh3add a0, a2, a0
+; RV64ZBA-NEXT: sh3add a1, a1, a2
+; RV64ZBA-NEXT: sh3add a0, a1, a0
; RV64ZBA-NEXT: ld a0, 0(a0)
; RV64ZBA-NEXT: ret
%a = getelementptr inbounds [8 x i64], ptr %p, i64 %idx1, i64 %idx2
@@ -2308,9 +2301,8 @@ define i64 @array_index_lshr_sh3_sh3(ptr %p, i64 %idx1, i64 %idx2) {
; RV64ZBA-LABEL: array_index_lshr_sh3_sh3:
; RV64ZBA: # %bb.0:
; RV64ZBA-NEXT: srli a1, a1, 58
-; RV64ZBA-NEXT: slli a1, a1, 6
-; RV64ZBA-NEXT: add a0, a0, a1
-; RV64ZBA-NEXT: sh3add a0, a2, a0
+; RV64ZBA-NEXT: sh3add a1, a1, a2
+; RV64ZBA-NEXT: sh3add a0, a1, a0
; RV64ZBA-NEXT: ld a0, 0(a0)
; RV64ZBA-NEXT: ret
%shr = lshr i64 %idx1, 58
diff --git a/llvm/test/CodeGen/RISCV/rvv/ctlz-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/ctlz-sdnode.ll
index fc94f8c2a527..d756cfcf7077 100644
--- a/llvm/test/CodeGen/RISCV/rvv/ctlz-sdnode.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/ctlz-sdnode.ll
@@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=riscv32 -mattr=+zve64x -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZVE64X,RV32,RV32I
; RUN: llc -mtriple=riscv64 -mattr=+zve64x -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-ZVE64X,RV64,RV64I
-; RUN: llc -mtriple=riscv32 -mattr=+zve64f,+f -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-F,RV32
-; RUN: llc -mtriple=riscv64 -mattr=+zve64f,+f -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-F,RV64
+; RUN: llc -mtriple=riscv32 -mattr=+zve64f,+f -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-F,RV32F
+; RUN: llc -mtriple=riscv64 -mattr=+zve64f,+f -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-F,RV64F
; RUN: llc -mtriple=riscv32 -mattr=+v,+d -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-D,RV32
; RUN: llc -mtriple=riscv64 -mattr=+v,+d -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK,CHECK-D,RV64
; RUN: llc -mtriple=riscv32 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB
@@ -1229,21 +1229,36 @@ define <vscale x 1 x i64> @ctlz_nxv1i64(<vscale x 1 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_nxv1i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m1, ta, ma
-; CHECK-F-NEXT: vmv.v.x v9, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v10, v8
-; CHECK-F-NEXT: vsrl.vi v8, v10, 23
-; CHECK-F-NEXT: vwsubu.wv v9, v9, v8
-; CHECK-F-NEXT: li a1, 64
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
-; CHECK-F-NEXT: vminu.vx v8, v9, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_nxv1i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m1, ta, ma
+; RV32F-NEXT: vmv.v.x v9, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v10, v8
+; RV32F-NEXT: vsrl.vi v8, v10, 23
+; RV32F-NEXT: vwsubu.wv v9, v9, v8
+; RV32F-NEXT: li a1, 64
+; RV32F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
+; RV32F-NEXT: vminu.vx v8, v9, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_nxv1i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, mf2, ta, ma
+; RV64F-NEXT: vmv.v.x v9, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v10, v8
+; RV64F-NEXT: vsrl.vi v8, v10, 23
+; RV64F-NEXT: vwsubu.vv v10, v9, v8
+; RV64F-NEXT: li a1, 64
+; RV64F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
+; RV64F-NEXT: vminu.vx v8, v10, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_nxv1i64:
; CHECK-D: # %bb.0:
@@ -1370,21 +1385,36 @@ define <vscale x 2 x i64> @ctlz_nxv2i64(<vscale x 2 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_nxv2i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m2, ta, ma
-; CHECK-F-NEXT: vmv.v.x v10, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v12, v8
-; CHECK-F-NEXT: vsrl.vi v8, v12, 23
-; CHECK-F-NEXT: vwsubu.wv v10, v10, v8
-; CHECK-F-NEXT: li a1, 64
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
-; CHECK-F-NEXT: vminu.vx v8, v10, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_nxv2i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m2, ta, ma
+; RV32F-NEXT: vmv.v.x v10, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v12, v8
+; RV32F-NEXT: vsrl.vi v8, v12, 23
+; RV32F-NEXT: vwsubu.wv v10, v10, v8
+; RV32F-NEXT: li a1, 64
+; RV32F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
+; RV32F-NEXT: vminu.vx v8, v10, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_nxv2i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m1, ta, ma
+; RV64F-NEXT: vmv.v.x v10, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v11, v8
+; RV64F-NEXT: vsrl.vi v8, v11, 23
+; RV64F-NEXT: vwsubu.vv v12, v10, v8
+; RV64F-NEXT: li a1, 64
+; RV64F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
+; RV64F-NEXT: vminu.vx v8, v12, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_nxv2i64:
; CHECK-D: # %bb.0:
@@ -1511,21 +1541,36 @@ define <vscale x 4 x i64> @ctlz_nxv4i64(<vscale x 4 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_nxv4i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m4, ta, ma
-; CHECK-F-NEXT: vmv.v.x v12, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v16, v8
-; CHECK-F-NEXT: vsrl.vi v8, v16, 23
-; CHECK-F-NEXT: vwsubu.wv v12, v12, v8
-; CHECK-F-NEXT: li a1, 64
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
-; CHECK-F-NEXT: vminu.vx v8, v12, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_nxv4i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m4, ta, ma
+; RV32F-NEXT: vmv.v.x v12, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v16, v8
+; RV32F-NEXT: vsrl.vi v8, v16, 23
+; RV32F-NEXT: vwsubu.wv v12, v12, v8
+; RV32F-NEXT: li a1, 64
+; RV32F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
+; RV32F-NEXT: vminu.vx v8, v12, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_nxv4i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m2, ta, ma
+; RV64F-NEXT: vmv.v.x v12, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v14, v8
+; RV64F-NEXT: vsrl.vi v8, v14, 23
+; RV64F-NEXT: vwsubu.vv v16, v12, v8
+; RV64F-NEXT: li a1, 64
+; RV64F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
+; RV64F-NEXT: vminu.vx v8, v16, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_nxv4i64:
; CHECK-D: # %bb.0:
@@ -1652,21 +1697,36 @@ define <vscale x 8 x i64> @ctlz_nxv8i64(<vscale x 8 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_nxv8i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m8, ta, ma
-; CHECK-F-NEXT: vmv.v.x v16, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v24, v8
-; CHECK-F-NEXT: vsrl.vi v8, v24, 23
-; CHECK-F-NEXT: vwsubu.wv v16, v16, v8
-; CHECK-F-NEXT: li a1, 64
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
-; CHECK-F-NEXT: vminu.vx v8, v16, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_nxv8i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV32F-NEXT: vmv.v.x v16, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v24, v8
+; RV32F-NEXT: vsrl.vi v8, v24, 23
+; RV32F-NEXT: vwsubu.wv v16, v16, v8
+; RV32F-NEXT: li a1, 64
+; RV32F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
+; RV32F-NEXT: vminu.vx v8, v16, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_nxv8i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m4, ta, ma
+; RV64F-NEXT: vmv.v.x v16, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v20, v8
+; RV64F-NEXT: vsrl.vi v8, v20, 23
+; RV64F-NEXT: vwsubu.vv v24, v16, v8
+; RV64F-NEXT: li a1, 64
+; RV64F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
+; RV64F-NEXT: vminu.vx v8, v24, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_nxv8i64:
; CHECK-D: # %bb.0:
@@ -2835,19 +2895,31 @@ define <vscale x 1 x i64> @ctlz_zero_undef_nxv1i64(<vscale x 1 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_zero_undef_nxv1i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m1, ta, ma
-; CHECK-F-NEXT: vmv.v.x v9, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v10, v8
-; CHECK-F-NEXT: vsrl.vi v8, v10, 23
-; CHECK-F-NEXT: vwsubu.wv v9, v9, v8
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: vmv1r.v v8, v9
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_zero_undef_nxv1i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m1, ta, ma
+; RV32F-NEXT: vmv.v.x v9, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v10, v8
+; RV32F-NEXT: vsrl.vi v8, v10, 23
+; RV32F-NEXT: vwsubu.wv v9, v9, v8
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: vmv1r.v v8, v9
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_zero_undef_nxv1i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, mf2, ta, ma
+; RV64F-NEXT: vmv.v.x v9, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v10, v8
+; RV64F-NEXT: vsrl.vi v10, v10, 23
+; RV64F-NEXT: vwsubu.vv v8, v9, v10
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_zero_undef_nxv1i64:
; CHECK-D: # %bb.0:
@@ -2971,19 +3043,31 @@ define <vscale x 2 x i64> @ctlz_zero_undef_nxv2i64(<vscale x 2 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_zero_undef_nxv2i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m2, ta, ma
-; CHECK-F-NEXT: vmv.v.x v10, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v12, v8
-; CHECK-F-NEXT: vsrl.vi v8, v12, 23
-; CHECK-F-NEXT: vwsubu.wv v10, v10, v8
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: vmv2r.v v8, v10
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_zero_undef_nxv2i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m2, ta, ma
+; RV32F-NEXT: vmv.v.x v10, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v12, v8
+; RV32F-NEXT: vsrl.vi v8, v12, 23
+; RV32F-NEXT: vwsubu.wv v10, v10, v8
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: vmv2r.v v8, v10
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_zero_undef_nxv2i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m1, ta, ma
+; RV64F-NEXT: vmv.v.x v10, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v11, v8
+; RV64F-NEXT: vsrl.vi v11, v11, 23
+; RV64F-NEXT: vwsubu.vv v8, v10, v11
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_zero_undef_nxv2i64:
; CHECK-D: # %bb.0:
@@ -3107,19 +3191,31 @@ define <vscale x 4 x i64> @ctlz_zero_undef_nxv4i64(<vscale x 4 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_zero_undef_nxv4i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m4, ta, ma
-; CHECK-F-NEXT: vmv.v.x v12, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v16, v8
-; CHECK-F-NEXT: vsrl.vi v8, v16, 23
-; CHECK-F-NEXT: vwsubu.wv v12, v12, v8
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: vmv4r.v v8, v12
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_zero_undef_nxv4i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m4, ta, ma
+; RV32F-NEXT: vmv.v.x v12, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v16, v8
+; RV32F-NEXT: vsrl.vi v8, v16, 23
+; RV32F-NEXT: vwsubu.wv v12, v12, v8
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: vmv4r.v v8, v12
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_zero_undef_nxv4i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m2, ta, ma
+; RV64F-NEXT: vmv.v.x v12, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v14, v8
+; RV64F-NEXT: vsrl.vi v14, v14, 23
+; RV64F-NEXT: vwsubu.vv v8, v12, v14
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_zero_undef_nxv4i64:
; CHECK-D: # %bb.0:
@@ -3243,19 +3339,31 @@ define <vscale x 8 x i64> @ctlz_zero_undef_nxv8i64(<vscale x 8 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: ctlz_zero_undef_nxv8i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: vmv8r.v v16, v8
-; CHECK-F-NEXT: li a0, 190
-; CHECK-F-NEXT: vsetvli a1, zero, e64, m8, ta, ma
-; CHECK-F-NEXT: vmv.v.x v8, a0
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v24, v16
-; CHECK-F-NEXT: vsrl.vi v16, v24, 23
-; CHECK-F-NEXT: vwsubu.wv v8, v8, v16
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: ctlz_zero_undef_nxv8i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: vmv8r.v v16, v8
+; RV32F-NEXT: li a0, 190
+; RV32F-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV32F-NEXT: vmv.v.x v8, a0
+; RV32F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v24, v16
+; RV32F-NEXT: vsrl.vi v16, v24, 23
+; RV32F-NEXT: vwsubu.wv v8, v8, v16
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: ctlz_zero_undef_nxv8i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: li a0, 190
+; RV64F-NEXT: vsetvli a1, zero, e32, m4, ta, ma
+; RV64F-NEXT: vmv.v.x v16, a0
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v20, v8
+; RV64F-NEXT: vsrl.vi v20, v20, 23
+; RV64F-NEXT: vwsubu.vv v8, v16, v20
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: ctlz_zero_undef_nxv8i64:
; CHECK-D: # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/rvv/cttz-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/cttz-sdnode.ll
index b14cde25aa85..d13f4d2dca1f 100644
--- a/llvm/test/CodeGen/RISCV/rvv/cttz-sdnode.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/cttz-sdnode.ll
@@ -1241,13 +1241,12 @@ define <vscale x 1 x i64> @cttz_nxv1i64(<vscale x 1 x i64> %va) {
; RV64F-NEXT: fsrmi a0, 1
; RV64F-NEXT: vfncvt.f.xu.w v10, v9
; RV64F-NEXT: vsrl.vi v9, v10, 23
-; RV64F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
-; RV64F-NEXT: vzext.vf2 v10, v9
; RV64F-NEXT: li a1, 127
-; RV64F-NEXT: vsub.vx v9, v10, a1
+; RV64F-NEXT: vwsubu.vx v10, v9, a1
+; RV64F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
; RV64F-NEXT: vmseq.vi v0, v8, 0
; RV64F-NEXT: li a1, 64
-; RV64F-NEXT: vmerge.vxm v8, v9, a1, v0
+; RV64F-NEXT: vmerge.vxm v8, v10, a1, v0
; RV64F-NEXT: fsrm a0
; RV64F-NEXT: ret
;
@@ -1404,13 +1403,12 @@ define <vscale x 2 x i64> @cttz_nxv2i64(<vscale x 2 x i64> %va) {
; RV64F-NEXT: fsrmi a0, 1
; RV64F-NEXT: vfncvt.f.xu.w v12, v10
; RV64F-NEXT: vsrl.vi v10, v12, 23
-; RV64F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
-; RV64F-NEXT: vzext.vf2 v12, v10
; RV64F-NEXT: li a1, 127
-; RV64F-NEXT: vsub.vx v10, v12, a1
+; RV64F-NEXT: vwsubu.vx v12, v10, a1
+; RV64F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
; RV64F-NEXT: vmseq.vi v0, v8, 0
; RV64F-NEXT: li a1, 64
-; RV64F-NEXT: vmerge.vxm v8, v10, a1, v0
+; RV64F-NEXT: vmerge.vxm v8, v12, a1, v0
; RV64F-NEXT: fsrm a0
; RV64F-NEXT: ret
;
@@ -1567,13 +1565,12 @@ define <vscale x 4 x i64> @cttz_nxv4i64(<vscale x 4 x i64> %va) {
; RV64F-NEXT: fsrmi a0, 1
; RV64F-NEXT: vfncvt.f.xu.w v16, v12
; RV64F-NEXT: vsrl.vi v12, v16, 23
-; RV64F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
-; RV64F-NEXT: vzext.vf2 v16, v12
; RV64F-NEXT: li a1, 127
-; RV64F-NEXT: vsub.vx v12, v16, a1
+; RV64F-NEXT: vwsubu.vx v16, v12, a1
+; RV64F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
; RV64F-NEXT: vmseq.vi v0, v8, 0
; RV64F-NEXT: li a1, 64
-; RV64F-NEXT: vmerge.vxm v8, v12, a1, v0
+; RV64F-NEXT: vmerge.vxm v8, v16, a1, v0
; RV64F-NEXT: fsrm a0
; RV64F-NEXT: ret
;
@@ -1730,13 +1727,12 @@ define <vscale x 8 x i64> @cttz_nxv8i64(<vscale x 8 x i64> %va) {
; RV64F-NEXT: fsrmi a0, 1
; RV64F-NEXT: vfncvt.f.xu.w v24, v16
; RV64F-NEXT: vsrl.vi v16, v24, 23
-; RV64F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
-; RV64F-NEXT: vzext.vf2 v24, v16
; RV64F-NEXT: li a1, 127
-; RV64F-NEXT: vsub.vx v16, v24, a1
+; RV64F-NEXT: vwsubu.vx v24, v16, a1
+; RV64F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
; RV64F-NEXT: vmseq.vi v0, v8, 0
; RV64F-NEXT: li a1, 64
-; RV64F-NEXT: vmerge.vxm v8, v16, a1, v0
+; RV64F-NEXT: vmerge.vxm v8, v24, a1, v0
; RV64F-NEXT: fsrm a0
; RV64F-NEXT: ret
;
@@ -2891,21 +2887,35 @@ define <vscale x 1 x i64> @cttz_zero_undef_nxv1i64(<vscale x 1 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: cttz_zero_undef_nxv1i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: vsetvli a0, zero, e64, m1, ta, ma
-; CHECK-F-NEXT: vrsub.vi v9, v8, 0
-; CHECK-F-NEXT: vand.vv v8, v8, v9
-; CHECK-F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v9, v8
-; CHECK-F-NEXT: vsrl.vi v8, v9, 23
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
-; CHECK-F-NEXT: vzext.vf2 v9, v8
-; CHECK-F-NEXT: li a1, 127
-; CHECK-F-NEXT: vsub.vx v8, v9, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: cttz_zero_undef_nxv1i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: vsetvli a0, zero, e64, m1, ta, ma
+; RV32F-NEXT: vrsub.vi v9, v8, 0
+; RV32F-NEXT: vand.vv v8, v8, v9
+; RV32F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v9, v8
+; RV32F-NEXT: vsrl.vi v8, v9, 23
+; RV32F-NEXT: vsetvli zero, zero, e64, m1, ta, ma
+; RV32F-NEXT: vzext.vf2 v9, v8
+; RV32F-NEXT: li a1, 127
+; RV32F-NEXT: vsub.vx v8, v9, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: cttz_zero_undef_nxv1i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: vsetvli a0, zero, e64, m1, ta, ma
+; RV64F-NEXT: vrsub.vi v9, v8, 0
+; RV64F-NEXT: vand.vv v8, v8, v9
+; RV64F-NEXT: vsetvli zero, zero, e32, mf2, ta, ma
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v9, v8
+; RV64F-NEXT: vsrl.vi v9, v9, 23
+; RV64F-NEXT: li a1, 127
+; RV64F-NEXT: vwsubu.vx v8, v9, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: cttz_zero_undef_nxv1i64:
; CHECK-D: # %bb.0:
@@ -3011,21 +3021,35 @@ define <vscale x 2 x i64> @cttz_zero_undef_nxv2i64(<vscale x 2 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: cttz_zero_undef_nxv2i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: vsetvli a0, zero, e64, m2, ta, ma
-; CHECK-F-NEXT: vrsub.vi v10, v8, 0
-; CHECK-F-NEXT: vand.vv v8, v8, v10
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v10, v8
-; CHECK-F-NEXT: vsrl.vi v8, v10, 23
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
-; CHECK-F-NEXT: vzext.vf2 v10, v8
-; CHECK-F-NEXT: li a1, 127
-; CHECK-F-NEXT: vsub.vx v8, v10, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: cttz_zero_undef_nxv2i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: vsetvli a0, zero, e64, m2, ta, ma
+; RV32F-NEXT: vrsub.vi v10, v8, 0
+; RV32F-NEXT: vand.vv v8, v8, v10
+; RV32F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v10, v8
+; RV32F-NEXT: vsrl.vi v8, v10, 23
+; RV32F-NEXT: vsetvli zero, zero, e64, m2, ta, ma
+; RV32F-NEXT: vzext.vf2 v10, v8
+; RV32F-NEXT: li a1, 127
+; RV32F-NEXT: vsub.vx v8, v10, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: cttz_zero_undef_nxv2i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: vsetvli a0, zero, e64, m2, ta, ma
+; RV64F-NEXT: vrsub.vi v10, v8, 0
+; RV64F-NEXT: vand.vv v8, v8, v10
+; RV64F-NEXT: vsetvli zero, zero, e32, m1, ta, ma
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v10, v8
+; RV64F-NEXT: vsrl.vi v10, v10, 23
+; RV64F-NEXT: li a1, 127
+; RV64F-NEXT: vwsubu.vx v8, v10, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: cttz_zero_undef_nxv2i64:
; CHECK-D: # %bb.0:
@@ -3131,21 +3155,35 @@ define <vscale x 4 x i64> @cttz_zero_undef_nxv4i64(<vscale x 4 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: cttz_zero_undef_nxv4i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: vsetvli a0, zero, e64, m4, ta, ma
-; CHECK-F-NEXT: vrsub.vi v12, v8, 0
-; CHECK-F-NEXT: vand.vv v8, v8, v12
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v12, v8
-; CHECK-F-NEXT: vsrl.vi v8, v12, 23
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
-; CHECK-F-NEXT: vzext.vf2 v12, v8
-; CHECK-F-NEXT: li a1, 127
-; CHECK-F-NEXT: vsub.vx v8, v12, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: cttz_zero_undef_nxv4i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: vsetvli a0, zero, e64, m4, ta, ma
+; RV32F-NEXT: vrsub.vi v12, v8, 0
+; RV32F-NEXT: vand.vv v8, v8, v12
+; RV32F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v12, v8
+; RV32F-NEXT: vsrl.vi v8, v12, 23
+; RV32F-NEXT: vsetvli zero, zero, e64, m4, ta, ma
+; RV32F-NEXT: vzext.vf2 v12, v8
+; RV32F-NEXT: li a1, 127
+; RV32F-NEXT: vsub.vx v8, v12, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: cttz_zero_undef_nxv4i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: vsetvli a0, zero, e64, m4, ta, ma
+; RV64F-NEXT: vrsub.vi v12, v8, 0
+; RV64F-NEXT: vand.vv v8, v8, v12
+; RV64F-NEXT: vsetvli zero, zero, e32, m2, ta, ma
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v12, v8
+; RV64F-NEXT: vsrl.vi v12, v12, 23
+; RV64F-NEXT: li a1, 127
+; RV64F-NEXT: vwsubu.vx v8, v12, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: cttz_zero_undef_nxv4i64:
; CHECK-D: # %bb.0:
@@ -3251,21 +3289,35 @@ define <vscale x 8 x i64> @cttz_zero_undef_nxv8i64(<vscale x 8 x i64> %va) {
; RV64I-NEXT: vsrl.vx v8, v8, a0
; RV64I-NEXT: ret
;
-; CHECK-F-LABEL: cttz_zero_undef_nxv8i64:
-; CHECK-F: # %bb.0:
-; CHECK-F-NEXT: vsetvli a0, zero, e64, m8, ta, ma
-; CHECK-F-NEXT: vrsub.vi v16, v8, 0
-; CHECK-F-NEXT: vand.vv v8, v8, v16
-; CHECK-F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
-; CHECK-F-NEXT: fsrmi a0, 1
-; CHECK-F-NEXT: vfncvt.f.xu.w v16, v8
-; CHECK-F-NEXT: vsrl.vi v8, v16, 23
-; CHECK-F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
-; CHECK-F-NEXT: vzext.vf2 v16, v8
-; CHECK-F-NEXT: li a1, 127
-; CHECK-F-NEXT: vsub.vx v8, v16, a1
-; CHECK-F-NEXT: fsrm a0
-; CHECK-F-NEXT: ret
+; RV32F-LABEL: cttz_zero_undef_nxv8i64:
+; RV32F: # %bb.0:
+; RV32F-NEXT: vsetvli a0, zero, e64, m8, ta, ma
+; RV32F-NEXT: vrsub.vi v16, v8, 0
+; RV32F-NEXT: vand.vv v8, v8, v16
+; RV32F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
+; RV32F-NEXT: fsrmi a0, 1
+; RV32F-NEXT: vfncvt.f.xu.w v16, v8
+; RV32F-NEXT: vsrl.vi v8, v16, 23
+; RV32F-NEXT: vsetvli zero, zero, e64, m8, ta, ma
+; RV32F-NEXT: vzext.vf2 v16, v8
+; RV32F-NEXT: li a1, 127
+; RV32F-NEXT: vsub.vx v8, v16, a1
+; RV32F-NEXT: fsrm a0
+; RV32F-NEXT: ret
+;
+; RV64F-LABEL: cttz_zero_undef_nxv8i64:
+; RV64F: # %bb.0:
+; RV64F-NEXT: vsetvli a0, zero, e64, m8, ta, ma
+; RV64F-NEXT: vrsub.vi v16, v8, 0
+; RV64F-NEXT: vand.vv v8, v8, v16
+; RV64F-NEXT: vsetvli zero, zero, e32, m4, ta, ma
+; RV64F-NEXT: fsrmi a0, 1
+; RV64F-NEXT: vfncvt.f.xu.w v16, v8
+; RV64F-NEXT: vsrl.vi v16, v16, 23
+; RV64F-NEXT: li a1, 127
+; RV64F-NEXT: vwsubu.vx v8, v16, a1
+; RV64F-NEXT: fsrm a0
+; RV64F-NEXT: ret
;
; CHECK-D-LABEL: cttz_zero_undef_nxv8i64:
; CHECK-D: # %bb.0:
diff --git a/llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll b/llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll
index 0992c9fe495f..4b6ad0f27214 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vector-interleave.ll
@@ -674,6 +674,26 @@ define <vscale x 8 x i32> @vector_interleave_nxv8i32_nxv4i32_poison(<vscale x 4
ret <vscale x 8 x i32> %res
}
+define <vscale x 8 x i32> @vector_interleave_nxv8i32_nxv4i32_poison2(<vscale x 4 x i32> %a) {
+; CHECK-LABEL: vector_interleave_nxv8i32_nxv4i32_poison2:
+; CHECK: # %bb.0:
+; CHECK-NEXT: vsetvli a0, zero, e64, m4, ta, ma
+; CHECK-NEXT: vzext.vf2 v12, v8
+; CHECK-NEXT: li a0, 32
+; CHECK-NEXT: vsll.vx v8, v12, a0
+; CHECK-NEXT: ret
+;
+; ZVBB-LABEL: vector_interleave_nxv8i32_nxv4i32_poison2:
+; ZVBB: # %bb.0:
+; ZVBB-NEXT: li a0, 32
+; ZVBB-NEXT: vsetvli a1, zero, e32, m2, ta, ma
+; ZVBB-NEXT: vwsll.vx v12, v8, a0
+; ZVBB-NEXT: vmv4r.v v8, v12
+; ZVBB-NEXT: ret
+ %res = call <vscale x 8 x i32> @llvm.experimental.vector.interleave2.nxv8i32(<vscale x 4 x i32> poison, <vscale x 4 x i32> %a)
+ ret <vscale x 8 x i32> %res
+}
+
declare <vscale x 64 x half> @llvm.experimental.vector.interleave2.nxv64f16(<vscale x 32 x half>, <vscale x 32 x half>)
declare <vscale x 32 x float> @llvm.experimental.vector.interleave2.nxv32f32(<vscale x 16 x float>, <vscale x 16 x float>)
declare <vscale x 16 x double> @llvm.experimental.vector.interleave2.nxv16f64(<vscale x 8 x double>, <vscale x 8 x double>)
diff --git a/llvm/test/CodeGen/RISCV/rvv/vwadd-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vwadd-sdnode.ll
index 5dd01c654eff..21ddf1a6e114 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vwadd-sdnode.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vwadd-sdnode.ll
@@ -1466,3 +1466,159 @@ define <vscale x 2 x i32> @vwadd_wv_disjoint_or(<vscale x 2 x i32> %x.i32, <vsca
%or = or disjoint <vscale x 2 x i32> %x.i32, %y.i32
ret <vscale x 2 x i32> %or
}
+
+define <vscale x 8 x i64> @vwadd_vx_splat_zext(<vscale x 8 x i32> %va, i32 %b) {
+; RV32-LABEL: vwadd_vx_splat_zext:
+; RV32: # %bb.0:
+; RV32-NEXT: addi sp, sp, -16
+; RV32-NEXT: .cfi_def_cfa_offset 16
+; RV32-NEXT: sw zero, 12(sp)
+; RV32-NEXT: sw a0, 8(sp)
+; RV32-NEXT: addi a0, sp, 8
+; RV32-NEXT: vsetvli a1, zero, e32, m4, ta, ma
+; RV32-NEXT: vlse64.v v16, (a0), zero
+; RV32-NEXT: vwaddu.wv v16, v16, v8
+; RV32-NEXT: vmv8r.v v8, v16
+; RV32-NEXT: addi sp, sp, 16
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_vx_splat_zext:
+; RV64: # %bb.0:
+; RV64-NEXT: andi a0, a0, -1
+; RV64-NEXT: vsetvli a1, zero, e32, m4, ta, ma
+; RV64-NEXT: vwaddu.vx v16, v8, a0
+; RV64-NEXT: vmv8r.v v8, v16
+; RV64-NEXT: ret
+ %zb = zext i32 %b to i64
+ %head = insertelement <vscale x 8 x i64> poison, i64 %zb, i32 0
+ %splat = shufflevector <vscale x 8 x i64> %head, <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
+ %vc = zext <vscale x 8 x i32> %va to <vscale x 8 x i64>
+ %ve = add <vscale x 8 x i64> %vc, %splat
+ ret <vscale x 8 x i64> %ve
+}
+
+define <vscale x 8 x i32> @vwadd_vx_splat_zext_i1(<vscale x 8 x i1> %va, i16 %b) {
+; RV32-LABEL: vwadd_vx_splat_zext_i1:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a0, a0, 16
+; RV32-NEXT: srli a0, a0, 16
+; RV32-NEXT: vsetvli a1, zero, e32, m4, ta, mu
+; RV32-NEXT: vmv.v.x v8, a0
+; RV32-NEXT: vadd.vi v8, v8, 1, v0.t
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_vx_splat_zext_i1:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a0, a0, 48
+; RV64-NEXT: srli a0, a0, 48
+; RV64-NEXT: vsetvli a1, zero, e32, m4, ta, mu
+; RV64-NEXT: vmv.v.x v8, a0
+; RV64-NEXT: vadd.vi v8, v8, 1, v0.t
+; RV64-NEXT: ret
+ %zb = zext i16 %b to i32
+ %head = insertelement <vscale x 8 x i32> poison, i32 %zb, i32 0
+ %splat = shufflevector <vscale x 8 x i32> %head, <vscale x 8 x i32> poison, <vscale x 8 x i32> zeroinitializer
+ %vc = zext <vscale x 8 x i1> %va to <vscale x 8 x i32>
+ %ve = add <vscale x 8 x i32> %vc, %splat
+ ret <vscale x 8 x i32> %ve
+}
+
+define <vscale x 8 x i64> @vwadd_wx_splat_zext(<vscale x 8 x i64> %va, i32 %b) {
+; RV32-LABEL: vwadd_wx_splat_zext:
+; RV32: # %bb.0:
+; RV32-NEXT: addi sp, sp, -16
+; RV32-NEXT: .cfi_def_cfa_offset 16
+; RV32-NEXT: sw zero, 12(sp)
+; RV32-NEXT: sw a0, 8(sp)
+; RV32-NEXT: addi a0, sp, 8
+; RV32-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV32-NEXT: vlse64.v v16, (a0), zero
+; RV32-NEXT: vadd.vv v8, v8, v16
+; RV32-NEXT: addi sp, sp, 16
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_wx_splat_zext:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a0, a0, 32
+; RV64-NEXT: srli a0, a0, 32
+; RV64-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV64-NEXT: vadd.vx v8, v8, a0
+; RV64-NEXT: ret
+ %zb = zext i32 %b to i64
+ %head = insertelement <vscale x 8 x i64> poison, i64 %zb, i32 0
+ %splat = shufflevector <vscale x 8 x i64> %head, <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
+ %ve = add <vscale x 8 x i64> %va, %splat
+ ret <vscale x 8 x i64> %ve
+}
+
+define <vscale x 8 x i64> @vwadd_vx_splat_sext(<vscale x 8 x i32> %va, i32 %b) {
+; RV32-LABEL: vwadd_vx_splat_sext:
+; RV32: # %bb.0:
+; RV32-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV32-NEXT: vmv.v.x v16, a0
+; RV32-NEXT: vsetvli zero, zero, e32, m4, ta, ma
+; RV32-NEXT: vwadd.wv v16, v16, v8
+; RV32-NEXT: vmv8r.v v8, v16
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_vx_splat_sext:
+; RV64: # %bb.0:
+; RV64-NEXT: vsetvli a1, zero, e32, m4, ta, ma
+; RV64-NEXT: vwadd.vx v16, v8, a0
+; RV64-NEXT: vmv8r.v v8, v16
+; RV64-NEXT: ret
+ %sb = sext i32 %b to i64
+ %head = insertelement <vscale x 8 x i64> poison, i64 %sb, i32 0
+ %splat = shufflevector <vscale x 8 x i64> %head, <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
+ %vc = sext <vscale x 8 x i32> %va to <vscale x 8 x i64>
+ %ve = add <vscale x 8 x i64> %vc, %splat
+ ret <vscale x 8 x i64> %ve
+}
+
+define <vscale x 8 x i32> @vwadd_vx_splat_sext_i1(<vscale x 8 x i1> %va, i16 %b) {
+; RV32-LABEL: vwadd_vx_splat_sext_i1:
+; RV32: # %bb.0:
+; RV32-NEXT: slli a0, a0, 16
+; RV32-NEXT: srai a0, a0, 16
+; RV32-NEXT: vsetvli a1, zero, e32, m4, ta, mu
+; RV32-NEXT: vmv.v.x v8, a0
+; RV32-NEXT: li a0, 1
+; RV32-NEXT: vsub.vx v8, v8, a0, v0.t
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_vx_splat_sext_i1:
+; RV64: # %bb.0:
+; RV64-NEXT: slli a0, a0, 48
+; RV64-NEXT: srai a0, a0, 48
+; RV64-NEXT: vsetvli a1, zero, e32, m4, ta, mu
+; RV64-NEXT: vmv.v.x v8, a0
+; RV64-NEXT: li a0, 1
+; RV64-NEXT: vsub.vx v8, v8, a0, v0.t
+; RV64-NEXT: ret
+ %sb = sext i16 %b to i32
+ %head = insertelement <vscale x 8 x i32> poison, i32 %sb, i32 0
+ %splat = shufflevector <vscale x 8 x i32> %head, <vscale x 8 x i32> poison, <vscale x 8 x i32> zeroinitializer
+ %vc = sext <vscale x 8 x i1> %va to <vscale x 8 x i32>
+ %ve = add <vscale x 8 x i32> %vc, %splat
+ ret <vscale x 8 x i32> %ve
+}
+
+define <vscale x 8 x i64> @vwadd_wx_splat_sext(<vscale x 8 x i64> %va, i32 %b) {
+; RV32-LABEL: vwadd_wx_splat_sext:
+; RV32: # %bb.0:
+; RV32-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV32-NEXT: vadd.vx v8, v8, a0
+; RV32-NEXT: ret
+;
+; RV64-LABEL: vwadd_wx_splat_sext:
+; RV64: # %bb.0:
+; RV64-NEXT: sext.w a0, a0
+; RV64-NEXT: vsetvli a1, zero, e64, m8, ta, ma
+; RV64-NEXT: vadd.vx v8, v8, a0
+; RV64-NEXT: ret
+ %sb = sext i32 %b to i64
+ %head = insertelement <vscale x 8 x i64> poison, i64 %sb, i32 0
+ %splat = shufflevector <vscale x 8 x i64> %head, <vscale x 8 x i64> poison, <vscale x 8 x i32> zeroinitializer
+ %ve = add <vscale x 8 x i64> %va, %splat
+ ret <vscale x 8 x i64> %ve
+}
diff --git a/llvm/test/CodeGen/RISCV/rvv/vwsll-sdnode.ll b/llvm/test/CodeGen/RISCV/rvv/vwsll-sdnode.ll
index 72fc9c918f22..41ec2fc443d0 100644
--- a/llvm/test/CodeGen/RISCV/rvv/vwsll-sdnode.ll
+++ b/llvm/test/CodeGen/RISCV/rvv/vwsll-sdnode.ll
@@ -1,8 +1,8 @@
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2
; RUN: llc -mtriple=riscv32 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
; RUN: llc -mtriple=riscv64 -mattr=+v -verify-machineinstrs < %s | FileCheck %s
-; RUN: llc -mtriple=riscv32 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB
-; RUN: llc -mtriple=riscv64 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB
+; RUN: llc -mtriple=riscv32 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB,RV32ZVBB
+; RUN: llc -mtriple=riscv64 -mattr=+v,+zvbb -verify-machineinstrs < %s | FileCheck %s --check-prefixes=CHECK-ZVBB,RV64ZVBB
; ==============================================================================
; i32 -> i64
@@ -864,12 +864,19 @@ define <vscale x 2 x i64> @vwsll_vi_nxv2i64_nxv2i8(<vscale x 2 x i8> %a) {
; CHECK-NEXT: vsll.vi v8, v10, 2
; CHECK-NEXT: ret
;
-; CHECK-ZVBB-LABEL: vwsll_vi_nxv2i64_nxv2i8:
-; CHECK-ZVBB: # %bb.0:
-; CHECK-ZVBB-NEXT: vsetvli a0, zero, e64, m2, ta, ma
-; CHECK-ZVBB-NEXT: vzext.vf8 v10, v8
-; CHECK-ZVBB-NEXT: vsll.vi v8, v10, 2
-; CHECK-ZVBB-NEXT: ret
+; RV32ZVBB-LABEL: vwsll_vi_nxv2i64_nxv2i8:
+; RV32ZVBB: # %bb.0:
+; RV32ZVBB-NEXT: vsetvli a0, zero, e64, m2, ta, ma
+; RV32ZVBB-NEXT: vzext.vf8 v10, v8
+; RV32ZVBB-NEXT: vsll.vi v8, v10, 2
+; RV32ZVBB-NEXT: ret
+;
+; RV64ZVBB-LABEL: vwsll_vi_nxv2i64_nxv2i8:
+; RV64ZVBB: # %bb.0:
+; RV64ZVBB-NEXT: vsetvli a0, zero, e32, m1, ta, ma
+; RV64ZVBB-NEXT: vzext.vf4 v10, v8
+; RV64ZVBB-NEXT: vwsll.vi v8, v10, 2
+; RV64ZVBB-NEXT: ret
%x = zext <vscale x 2 x i8> %a to <vscale x 2 x i64>
%z = shl <vscale x 2 x i64> %x, splat (i64 2)
ret <vscale x 2 x i64> %z
diff --git a/llvm/test/CodeGen/SPIRV/SampledImageRetType.ll b/llvm/test/CodeGen/SPIRV/SampledImageRetType.ll
index 1aa3af83bcd2..7af5876a023e 100644
--- a/llvm/test/CodeGen/SPIRV/SampledImageRetType.ll
+++ b/llvm/test/CodeGen/SPIRV/SampledImageRetType.ll
@@ -8,6 +8,8 @@ declare dso_local spir_func ptr addrspace(4) @_Z20__spirv_SampledImageI14ocl_ima
declare dso_local spir_func <4 x float> @_Z30__spirv_ImageSampleExplicitLodIPvDv4_fiET0_T_T1_if(ptr addrspace(4) %0, i32 %1, i32 %2, float %3) local_unnamed_addr
+declare dso_local spir_func <4 x i32> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_jfET0_T_T1_if(target("spirv.SampledImage", void, 0, 0, 0, 0, 0, 0, 0) %0, float %1, i32 %2, float %3) local_unnamed_addr
+
@__spirv_BuiltInGlobalInvocationId = external dso_local local_unnamed_addr addrspace(2) constant <3 x i64>, align 32
define weak_odr dso_local spir_kernel void @_ZTS17image_kernel_readILi1EE(target("spirv.Image", void, 0, 0, 0, 0, 0, 0, 0), target("spirv.Sampler")) {
@@ -25,3 +27,10 @@ define weak_odr dso_local spir_kernel void @_ZTS17image_kernel_readILi1EE(target
ret void
}
+
+define weak_odr dso_local spir_kernel void @foo_lod(target("spirv.SampledImage", void, 0, 0, 0, 0, 0, 0, 0) %_arg) {
+ %lod = call spir_func <4 x i32> @_Z30__spirv_ImageSampleExplicitLodI32__spirv_SampledImage__image1d_roDv4_jfET0_T_T1_if(target("spirv.SampledImage", void, 0, 0, 0, 0, 0, 0, 0) %_arg, float 0x3FE7FFEB00000000, i32 2, float 0.000000e+00)
+; CHECK: %[[#sampled_image_lod:]] = OpFunctionParameter %[[#sampled_image_t]]
+; CHECK: %[[#]] = OpImageSampleExplicitLod %[[#]] %[[#sampled_image_lod]] %[[#]] {{.*}} %[[#]]
+ ret void
+}
diff --git a/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/all.ll b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/all.ll
new file mode 100644
index 000000000000..ef8d463cbd81
--- /dev/null
+++ b/llvm/test/CodeGen/SPIRV/hlsl-intrinsics/all.ll
@@ -0,0 +1,187 @@
+; RUN: llc -O0 -mtriple=spirv-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-HLSL
+; RUN: llc -O0 -mtriple=spirv32-unknown-unknown %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-OCL
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; RUN: %if spirv-tools %{ llc -O0 -mtriple=spirv32-unknown-unknown %s -o - -filetype=obj | spirv-val %}
+; Make sure spirv operation function calls for all are generated.
+
+; CHECK-HLSL-DAG: OpMemoryModel Logical GLSL450
+; CHECK-OCL-DAG: OpMemoryModel Physical32 OpenCL
+; CHECK-DAG: OpName %[[#all_bool_arg:]] "a"
+; CHECK-DAG: %[[#int_64:]] = OpTypeInt 64 0
+; CHECK-DAG: %[[#bool:]] = OpTypeBool
+; CHECK-DAG: %[[#int_32:]] = OpTypeInt 32 0
+; CHECK-DAG: %[[#int_16:]] = OpTypeInt 16 0
+; CHECK-DAG: %[[#float_64:]] = OpTypeFloat 64
+; CHECK-DAG: %[[#float_32:]] = OpTypeFloat 32
+; CHECK-DAG: %[[#float_16:]] = OpTypeFloat 16
+; CHECK-DAG: %[[#vec4_bool:]] = OpTypeVector %[[#bool]] 4
+; CHECK-DAG: %[[#vec4_16:]] = OpTypeVector %[[#int_16]] 4
+; CHECK-DAG: %[[#vec4_32:]] = OpTypeVector %[[#int_32]] 4
+; CHECK-DAG: %[[#vec4_64:]] = OpTypeVector %[[#int_64]] 4
+; CHECK-DAG: %[[#vec4_float_16:]] = OpTypeVector %[[#float_16]] 4
+; CHECK-DAG: %[[#vec4_float_32:]] = OpTypeVector %[[#float_32]] 4
+; CHECK-DAG: %[[#vec4_float_64:]] = OpTypeVector %[[#float_64]] 4
+
+; CHECK-HLSL-DAG: %[[#const_i64_0:]] = OpConstant %[[#int_64]] 0
+; CHECK-HLSL-DAG: %[[#const_i32_0:]] = OpConstant %[[#int_32]] 0
+; CHECK-HLSL-DAG: %[[#const_i16_0:]] = OpConstant %[[#int_16]] 0
+; CHECK-HLSL-DAG: %[[#const_f64_0:]] = OpConstant %[[#float_64]] 0
+; CHECK-HLSL-DAG: %[[#const_f32_0:]] = OpConstant %[[#float_32:]] 0
+; CHECK-HLSL-DAG: %[[#const_f16_0:]] = OpConstant %[[#float_16:]] 0
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_i16:]] = OpConstantComposite %[[#vec4_16:]] %[[#const_i16_0:]] %[[#const_i16_0:]] %[[#const_i16_0:]] %[[#const_i16_0:]]
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_i32:]] = OpConstantComposite %[[#vec4_32:]] %[[#const_i32_0:]] %[[#const_i32_0:]] %[[#const_i32_0:]] %[[#const_i32_0:]]
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_i64:]] = OpConstantComposite %[[#vec4_64:]] %[[#const_i64_0:]] %[[#const_i64_0:]] %[[#const_i64_0:]] %[[#const_i64_0:]]
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_f16:]] = OpConstantComposite %[[#vec4_float_16:]] %[[#const_f16_0:]] %[[#const_f16_0:]] %[[#const_f16_0:]] %[[#const_f16_0:]]
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_f32:]] = OpConstantComposite %[[#vec4_float_32:]] %[[#const_f32_0:]] %[[#const_f32_0:]] %[[#const_f32_0:]] %[[#const_f32_0:]]
+; CHECK-HLSL-DAG: %[[#vec4_const_zeros_f64:]] = OpConstantComposite %[[#vec4_float_64:]] %[[#const_f64_0:]] %[[#const_f64_0:]] %[[#const_f64_0:]] %[[#const_f64_0:]]
+
+; CHECK-OCL-DAG: %[[#const_i64_0:]] = OpConstantNull %[[#int_64]]
+; CHECK-OCL-DAG: %[[#const_i32_0:]] = OpConstantNull %[[#int_32]]
+; CHECK-OCL-DAG: %[[#const_i16_0:]] = OpConstantNull %[[#int_16]]
+; CHECK-OCL-DAG: %[[#const_f64_0:]] = OpConstantNull %[[#float_64]]
+; CHECK-OCL-DAG: %[[#const_f32_0:]] = OpConstantNull %[[#float_32:]]
+; CHECK-OCL-DAG: %[[#const_f16_0:]] = OpConstantNull %[[#float_16:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_i16:]] = OpConstantNull %[[#vec4_16:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_i32:]] = OpConstantNull %[[#vec4_32:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_i64:]] = OpConstantNull %[[#vec4_64:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_f16:]] = OpConstantNull %[[#vec4_float_16:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_f32:]] = OpConstantNull %[[#vec4_float_32:]]
+; CHECK-OCL-DAG: %[[#vec4_const_zeros_f64:]] = OpConstantNull %[[#vec4_float_64:]]
+
+define noundef i1 @all_int64_t(i64 noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpINotEqual %[[#bool:]] %[[#arg0:]] %[[#const_i64_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.i64(i64 %p0)
+ ret i1 %hlsl.all
+}
+
+
+define noundef i1 @all_int(i32 noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpINotEqual %[[#bool:]] %[[#arg0:]] %[[#const_i32_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.i32(i32 %p0)
+ ret i1 %hlsl.all
+}
+
+
+define noundef i1 @all_int16_t(i16 noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpINotEqual %[[#bool:]] %[[#arg0:]] %[[#const_i16_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.i16(i16 %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_double(double noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpFOrdNotEqual %[[#bool:]] %[[#arg0:]] %[[#const_f64_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.f64(double %p0)
+ ret i1 %hlsl.all
+}
+
+
+define noundef i1 @all_float(float noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpFOrdNotEqual %[[#bool:]] %[[#arg0:]] %[[#const_f32_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.f32(float %p0)
+ ret i1 %hlsl.all
+}
+
+
+define noundef i1 @all_half(half noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpFOrdNotEqual %[[#bool:]] %[[#arg0:]] %[[#const_f16_0:]]
+ %hlsl.all = call i1 @llvm.spv.all.f16(half %p0)
+ ret i1 %hlsl.all
+}
+
+
+define noundef i1 @all_bool4(<4 x i1> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#]] = OpAll %[[#vec4_bool:]] %[[#arg0:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4i1(<4 x i1> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_short4(<4 x i16> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#shortVecNotEq:]] = OpINotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_i16:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool:]] %[[#shortVecNotEq:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4i16(<4 x i16> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_int4(<4 x i32> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#i32VecNotEq:]] = OpINotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_i32:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool:]] %[[#i32VecNotEq:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4i32(<4 x i32> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_int64_t4(<4 x i64> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#i64VecNotEq:]] = OpINotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_i64:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool:]] %[[#i64VecNotEq]]
+ %hlsl.all = call i1 @llvm.spv.all.v4i64(<4 x i64> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_half4(<4 x half> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#f16VecNotEq:]] = OpFOrdNotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_f16:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool]] %[[#f16VecNotEq:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4f16(<4 x half> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_float4(<4 x float> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#f32VecNotEq:]] = OpFOrdNotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_f32:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool:]] %[[#f32VecNotEq:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4f32(<4 x float> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_double4(<4 x double> noundef %p0) {
+entry:
+ ; CHECK: %[[#arg0:]] = OpFunctionParameter %[[#]]
+ ; CHECK: %[[#f64VecNotEq:]] = OpFOrdNotEqual %[[#vec4_bool:]] %[[#arg0:]] %[[#vec4_const_zeros_f64:]]
+ ; CHECK: %[[#]] = OpAll %[[#bool:]] %[[#f64VecNotEq:]]
+ %hlsl.all = call i1 @llvm.spv.all.v4f64(<4 x double> %p0)
+ ret i1 %hlsl.all
+}
+
+define noundef i1 @all_bool(i1 noundef %a) {
+entry:
+ ; CHECK: %[[#all_bool_arg:]] = OpFunctionParameter %[[#bool:]]
+ ; CHECK: OpReturnValue %[[#all_bool_arg:]]
+ %hlsl.all = call i1 @llvm.spv.all.i1(i1 %a)
+ ret i1 %hlsl.all
+}
+
+declare i1 @llvm.spv.all.v4f16(<4 x half>)
+declare i1 @llvm.spv.all.v4f32(<4 x float>)
+declare i1 @llvm.spv.all.v4f64(<4 x double>)
+declare i1 @llvm.spv.all.v4i1(<4 x i1>)
+declare i1 @llvm.spv.all.v4i16(<4 x i16>)
+declare i1 @llvm.spv.all.v4i32(<4 x i32>)
+declare i1 @llvm.spv.all.v4i64(<4 x i64>)
+declare i1 @llvm.spv.all.i1(i1)
+declare i1 @llvm.spv.all.i16(i16)
+declare i1 @llvm.spv.all.i32(i32)
+declare i1 @llvm.spv.all.i64(i64)
+declare i1 @llvm.spv.all.f16(half)
+declare i1 @llvm.spv.all.f32(float)
+declare i1 @llvm.spv.all.f64(double)
diff --git a/llvm/test/CodeGen/X86/bitreverse.ll b/llvm/test/CodeGen/X86/bitreverse.ll
index 26b1d64874e5..704563ab1bbf 100644
--- a/llvm/test/CodeGen/X86/bitreverse.ll
+++ b/llvm/test/CodeGen/X86/bitreverse.ll
@@ -172,26 +172,10 @@ define i64 @test_bitreverse_i64(i64 %a) nounwind {
;
; GFNI-LABEL: test_bitreverse_i64:
; GFNI: # %bb.0:
-; GFNI-NEXT: bswapq %rdi
-; GFNI-NEXT: movq %rdi, %rax
-; GFNI-NEXT: shrq $4, %rax
-; GFNI-NEXT: movabsq $1085102592571150095, %rcx # imm = 0xF0F0F0F0F0F0F0F
-; GFNI-NEXT: andq %rcx, %rax
-; GFNI-NEXT: andq %rcx, %rdi
-; GFNI-NEXT: shlq $4, %rdi
-; GFNI-NEXT: orq %rax, %rdi
-; GFNI-NEXT: movabsq $3689348814741910323, %rax # imm = 0x3333333333333333
-; GFNI-NEXT: movq %rdi, %rcx
-; GFNI-NEXT: andq %rax, %rcx
-; GFNI-NEXT: shrq $2, %rdi
-; GFNI-NEXT: andq %rax, %rdi
-; GFNI-NEXT: leaq (%rdi,%rcx,4), %rax
-; GFNI-NEXT: movabsq $6148914691236517205, %rcx # imm = 0x5555555555555555
-; GFNI-NEXT: movq %rax, %rdx
-; GFNI-NEXT: andq %rcx, %rdx
-; GFNI-NEXT: shrq %rax
-; GFNI-NEXT: andq %rcx, %rax
-; GFNI-NEXT: leaq (%rax,%rdx,2), %rax
+; GFNI-NEXT: vmovq %rdi, %xmm0
+; GFNI-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm0
+; GFNI-NEXT: vmovq %xmm0, %rax
+; GFNI-NEXT: bswapq %rax
; GFNI-NEXT: retq
%b = call i64 @llvm.bitreverse.i64(i64 %a)
ret i64 %b
@@ -253,24 +237,10 @@ define i32 @test_bitreverse_i32(i32 %a) nounwind {
;
; GFNI-LABEL: test_bitreverse_i32:
; GFNI: # %bb.0:
-; GFNI-NEXT: # kill: def $edi killed $edi def $rdi
-; GFNI-NEXT: bswapl %edi
-; GFNI-NEXT: movl %edi, %eax
-; GFNI-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
-; GFNI-NEXT: shll $4, %eax
-; GFNI-NEXT: shrl $4, %edi
-; GFNI-NEXT: andl $252645135, %edi # imm = 0xF0F0F0F
-; GFNI-NEXT: orl %eax, %edi
-; GFNI-NEXT: movl %edi, %eax
-; GFNI-NEXT: andl $858993459, %eax # imm = 0x33333333
-; GFNI-NEXT: shrl $2, %edi
-; GFNI-NEXT: andl $858993459, %edi # imm = 0x33333333
-; GFNI-NEXT: leal (%rdi,%rax,4), %eax
-; GFNI-NEXT: movl %eax, %ecx
-; GFNI-NEXT: andl $1431655765, %ecx # imm = 0x55555555
-; GFNI-NEXT: shrl %eax
-; GFNI-NEXT: andl $1431655765, %eax # imm = 0x55555555
-; GFNI-NEXT: leal (%rax,%rcx,2), %eax
+; GFNI-NEXT: vmovd %edi, %xmm0
+; GFNI-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm0
+; GFNI-NEXT: vmovd %xmm0, %eax
+; GFNI-NEXT: bswapl %eax
; GFNI-NEXT: retq
%b = call i32 @llvm.bitreverse.i32(i32 %a)
ret i32 %b
@@ -335,24 +305,10 @@ define i24 @test_bitreverse_i24(i24 %a) nounwind {
;
; GFNI-LABEL: test_bitreverse_i24:
; GFNI: # %bb.0:
-; GFNI-NEXT: # kill: def $edi killed $edi def $rdi
-; GFNI-NEXT: bswapl %edi
-; GFNI-NEXT: movl %edi, %eax
-; GFNI-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
-; GFNI-NEXT: shll $4, %eax
-; GFNI-NEXT: shrl $4, %edi
-; GFNI-NEXT: andl $252645135, %edi # imm = 0xF0F0F0F
-; GFNI-NEXT: orl %eax, %edi
-; GFNI-NEXT: movl %edi, %eax
-; GFNI-NEXT: andl $858993459, %eax # imm = 0x33333333
-; GFNI-NEXT: shrl $2, %edi
-; GFNI-NEXT: andl $858993459, %edi # imm = 0x33333333
-; GFNI-NEXT: leal (%rdi,%rax,4), %eax
-; GFNI-NEXT: movl %eax, %ecx
-; GFNI-NEXT: andl $1431655680, %ecx # imm = 0x55555500
-; GFNI-NEXT: shrl %eax
-; GFNI-NEXT: andl $1431655680, %eax # imm = 0x55555500
-; GFNI-NEXT: leal (%rax,%rcx,2), %eax
+; GFNI-NEXT: vmovd %edi, %xmm0
+; GFNI-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip){1to2}, %xmm0, %xmm0
+; GFNI-NEXT: vmovd %xmm0, %eax
+; GFNI-NEXT: bswapl %eax
; GFNI-NEXT: shrl $8, %eax
; GFNI-NEXT: retq
%b = call i24 @llvm.bitreverse.i24(i24 %a)
@@ -1412,196 +1368,67 @@ define i528 @large_promotion(i528 %A) nounwind {
;
; GFNI-LABEL: large_promotion:
; GFNI: # %bb.0:
-; GFNI-NEXT: pushq %r15
; GFNI-NEXT: pushq %r14
-; GFNI-NEXT: pushq %r13
-; GFNI-NEXT: pushq %r12
; GFNI-NEXT: pushq %rbx
; GFNI-NEXT: movq %rdi, %rax
-; GFNI-NEXT: movq {{[0-9]+}}(%rsp), %r12
-; GFNI-NEXT: movq {{[0-9]+}}(%rsp), %r15
-; GFNI-NEXT: movq {{[0-9]+}}(%rsp), %rbx
-; GFNI-NEXT: movq {{[0-9]+}}(%rsp), %rdi
+; GFNI-NEXT: vpbroadcastq {{.*#+}} xmm0 = [9241421688590303745,9241421688590303745]
+; GFNI-NEXT: vmovq {{.*#+}} xmm1 = mem[0],zero
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %r10
+; GFNI-NEXT: bswapq %r10
+; GFNI-NEXT: vmovq %r9, %xmm1
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %rdi
; GFNI-NEXT: bswapq %rdi
-; GFNI-NEXT: movq %rdi, %r10
-; GFNI-NEXT: shrq $4, %r10
-; GFNI-NEXT: movabsq $1085102592571150095, %r11 # imm = 0xF0F0F0F0F0F0F0F
-; GFNI-NEXT: andq %r11, %r10
-; GFNI-NEXT: andq %r11, %rdi
-; GFNI-NEXT: shlq $4, %rdi
-; GFNI-NEXT: orq %r10, %rdi
-; GFNI-NEXT: movabsq $3689348814741910323, %r10 # imm = 0x3333333333333333
-; GFNI-NEXT: movq %rdi, %r14
-; GFNI-NEXT: andq %r10, %r14
-; GFNI-NEXT: shrq $2, %rdi
-; GFNI-NEXT: andq %r10, %rdi
-; GFNI-NEXT: leaq (%rdi,%r14,4), %rdi
-; GFNI-NEXT: movabsq $6148820866244280320, %r14 # imm = 0x5555000000000000
-; GFNI-NEXT: movq %rdi, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %rdi
-; GFNI-NEXT: andq %r14, %rdi
-; GFNI-NEXT: leaq (%rdi,%r13,2), %rdi
-; GFNI-NEXT: bswapq %rbx
-; GFNI-NEXT: movq %rbx, %r14
-; GFNI-NEXT: shrq $4, %r14
-; GFNI-NEXT: andq %r11, %r14
-; GFNI-NEXT: andq %r11, %rbx
-; GFNI-NEXT: shlq $4, %rbx
-; GFNI-NEXT: orq %r14, %rbx
-; GFNI-NEXT: movq %rbx, %r14
-; GFNI-NEXT: andq %r10, %r14
-; GFNI-NEXT: shrq $2, %rbx
-; GFNI-NEXT: andq %r10, %rbx
-; GFNI-NEXT: leaq (%rbx,%r14,4), %rbx
-; GFNI-NEXT: movabsq $6148914691236517205, %r14 # imm = 0x5555555555555555
-; GFNI-NEXT: movq %rbx, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %rbx
-; GFNI-NEXT: andq %r14, %rbx
-; GFNI-NEXT: leaq (%rbx,%r13,2), %rbx
-; GFNI-NEXT: shrdq $48, %rbx, %rdi
-; GFNI-NEXT: bswapq %r15
-; GFNI-NEXT: movq %r15, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %r15
-; GFNI-NEXT: shlq $4, %r15
-; GFNI-NEXT: orq %r13, %r15
-; GFNI-NEXT: movq %r15, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %r15
-; GFNI-NEXT: andq %r10, %r15
-; GFNI-NEXT: leaq (%r15,%r13,4), %r15
-; GFNI-NEXT: movq %r15, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %r15
-; GFNI-NEXT: andq %r14, %r15
-; GFNI-NEXT: leaq (%r15,%r13,2), %r15
-; GFNI-NEXT: shrdq $48, %r15, %rbx
-; GFNI-NEXT: bswapq %r12
-; GFNI-NEXT: movq %r12, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %r12
-; GFNI-NEXT: shlq $4, %r12
-; GFNI-NEXT: orq %r13, %r12
-; GFNI-NEXT: movq %r12, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %r12
-; GFNI-NEXT: andq %r10, %r12
-; GFNI-NEXT: leaq (%r12,%r13,4), %r12
-; GFNI-NEXT: movq %r12, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %r12
-; GFNI-NEXT: andq %r14, %r12
-; GFNI-NEXT: leaq (%r12,%r13,2), %r12
-; GFNI-NEXT: shrdq $48, %r12, %r15
-; GFNI-NEXT: bswapq %r9
-; GFNI-NEXT: movq %r9, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %r9
-; GFNI-NEXT: shlq $4, %r9
-; GFNI-NEXT: orq %r13, %r9
-; GFNI-NEXT: movq %r9, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %r9
-; GFNI-NEXT: andq %r10, %r9
-; GFNI-NEXT: leaq (%r9,%r13,4), %r9
-; GFNI-NEXT: movq %r9, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %r9
-; GFNI-NEXT: andq %r14, %r9
-; GFNI-NEXT: leaq (%r9,%r13,2), %r9
-; GFNI-NEXT: shrdq $48, %r9, %r12
+; GFNI-NEXT: vmovq %r8, %xmm1
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %r8
; GFNI-NEXT: bswapq %r8
-; GFNI-NEXT: movq %r8, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %r8
-; GFNI-NEXT: shlq $4, %r8
-; GFNI-NEXT: orq %r13, %r8
-; GFNI-NEXT: movq %r8, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %r8
-; GFNI-NEXT: andq %r10, %r8
-; GFNI-NEXT: leaq (%r8,%r13,4), %r8
-; GFNI-NEXT: movq %r8, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %r8
-; GFNI-NEXT: andq %r14, %r8
-; GFNI-NEXT: leaq (%r8,%r13,2), %r8
-; GFNI-NEXT: shrdq $48, %r8, %r9
+; GFNI-NEXT: movq %r8, %r9
+; GFNI-NEXT: shldq $16, %rdi, %r9
+; GFNI-NEXT: shldq $16, %r10, %rdi
+; GFNI-NEXT: vmovq %rcx, %xmm1
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %rcx
; GFNI-NEXT: bswapq %rcx
-; GFNI-NEXT: movq %rcx, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %rcx
-; GFNI-NEXT: shlq $4, %rcx
-; GFNI-NEXT: orq %r13, %rcx
-; GFNI-NEXT: movq %rcx, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %rcx
-; GFNI-NEXT: andq %r10, %rcx
-; GFNI-NEXT: leaq (%rcx,%r13,4), %rcx
-; GFNI-NEXT: movq %rcx, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %rcx
-; GFNI-NEXT: andq %r14, %rcx
-; GFNI-NEXT: leaq (%rcx,%r13,2), %rcx
; GFNI-NEXT: shrdq $48, %rcx, %r8
+; GFNI-NEXT: vmovq %rdx, %xmm1
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %rdx
; GFNI-NEXT: bswapq %rdx
-; GFNI-NEXT: movq %rdx, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %rdx
-; GFNI-NEXT: shlq $4, %rdx
-; GFNI-NEXT: orq %r13, %rdx
-; GFNI-NEXT: movq %rdx, %r13
-; GFNI-NEXT: andq %r10, %r13
-; GFNI-NEXT: shrq $2, %rdx
-; GFNI-NEXT: andq %r10, %rdx
-; GFNI-NEXT: leaq (%rdx,%r13,4), %rdx
-; GFNI-NEXT: movq %rdx, %r13
-; GFNI-NEXT: andq %r14, %r13
-; GFNI-NEXT: shrq %rdx
-; GFNI-NEXT: andq %r14, %rdx
-; GFNI-NEXT: leaq (%rdx,%r13,2), %rdx
; GFNI-NEXT: shrdq $48, %rdx, %rcx
+; GFNI-NEXT: vmovq %rsi, %xmm1
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %rsi
; GFNI-NEXT: bswapq %rsi
-; GFNI-NEXT: movq %rsi, %r13
-; GFNI-NEXT: shrq $4, %r13
-; GFNI-NEXT: andq %r11, %r13
-; GFNI-NEXT: andq %r11, %rsi
-; GFNI-NEXT: shlq $4, %rsi
-; GFNI-NEXT: orq %r13, %rsi
-; GFNI-NEXT: movq %rsi, %r11
-; GFNI-NEXT: andq %r10, %r11
-; GFNI-NEXT: shrq $2, %rsi
-; GFNI-NEXT: andq %r10, %rsi
-; GFNI-NEXT: leaq (%rsi,%r11,4), %rsi
-; GFNI-NEXT: movq %rsi, %r10
-; GFNI-NEXT: andq %r14, %r10
-; GFNI-NEXT: shrq %rsi
-; GFNI-NEXT: andq %r14, %rsi
-; GFNI-NEXT: leaq (%rsi,%r10,2), %rsi
; GFNI-NEXT: shrdq $48, %rsi, %rdx
+; GFNI-NEXT: vmovq {{.*#+}} xmm1 = mem[0],zero
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %r11
+; GFNI-NEXT: bswapq %r11
+; GFNI-NEXT: vmovq {{.*#+}} xmm1 = mem[0],zero
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm1
+; GFNI-NEXT: vmovq %xmm1, %rbx
+; GFNI-NEXT: bswapq %rbx
+; GFNI-NEXT: shrdq $48, %rbx, %r11
+; GFNI-NEXT: vmovq {{.*#+}} xmm1 = mem[0],zero
+; GFNI-NEXT: vgf2p8affineqb $0, %xmm0, %xmm1, %xmm0
+; GFNI-NEXT: vmovq %xmm0, %r14
+; GFNI-NEXT: bswapq %r14
+; GFNI-NEXT: shrdq $48, %r14, %rbx
+; GFNI-NEXT: shrdq $48, %r10, %r14
; GFNI-NEXT: shrq $48, %rsi
+; GFNI-NEXT: movq %r14, 16(%rax)
+; GFNI-NEXT: movq %rbx, 8(%rax)
+; GFNI-NEXT: movq %r11, (%rax)
; GFNI-NEXT: movq %rdx, 56(%rax)
; GFNI-NEXT: movq %rcx, 48(%rax)
; GFNI-NEXT: movq %r8, 40(%rax)
; GFNI-NEXT: movq %r9, 32(%rax)
-; GFNI-NEXT: movq %r12, 24(%rax)
-; GFNI-NEXT: movq %r15, 16(%rax)
-; GFNI-NEXT: movq %rbx, 8(%rax)
-; GFNI-NEXT: movq %rdi, (%rax)
+; GFNI-NEXT: movq %rdi, 24(%rax)
; GFNI-NEXT: movw %si, 64(%rax)
; GFNI-NEXT: popq %rbx
-; GFNI-NEXT: popq %r12
-; GFNI-NEXT: popq %r13
; GFNI-NEXT: popq %r14
-; GFNI-NEXT: popq %r15
; GFNI-NEXT: retq
%Z = call i528 @llvm.bitreverse.i528(i528 %A)
ret i528 %Z
diff --git a/llvm/test/CodeGen/X86/mmx-intrinsics.ll b/llvm/test/CodeGen/X86/mmx-intrinsics.ll
index 54b1a3135918..a43d9400cde6 100644
--- a/llvm/test/CodeGen/X86/mmx-intrinsics.ll
+++ b/llvm/test/CodeGen/X86/mmx-intrinsics.ll
@@ -1,13 +1,42 @@
-; RUN: llc < %s -mtriple=i686-- -mattr=+mmx,+ssse3,-avx | FileCheck %s --check-prefix=ALL --check-prefix=X86
-; RUN: llc < %s -mtriple=i686-- -mattr=+mmx,+avx | FileCheck %s --check-prefix=ALL --check-prefix=X86
-; RUN: llc < %s -mtriple=x86_64-- -mattr=+mmx,+ssse3,-avx | FileCheck %s --check-prefix=ALL --check-prefix=X64
-; RUN: llc < %s -mtriple=x86_64-- -mattr=+mmx,+avx | FileCheck %s --check-prefix=ALL --check-prefix=X64
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 4
+; RUN: llc < %s -mtriple=i686-- -mattr=+mmx,+ssse3,-avx | FileCheck %s --check-prefixes=ALL,X86
+; RUN: llc < %s -mtriple=i686-- -mattr=+mmx,+avx | FileCheck %s --check-prefixes=ALL,X86
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+mmx,+ssse3,-avx | FileCheck %s --check-prefixes=ALL,X64
+; RUN: llc < %s -mtriple=x86_64-- -mattr=+mmx,+avx | FileCheck %s --check-prefixes=ALL,X64
declare x86_mmx @llvm.x86.ssse3.phadd.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test1(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test1
-; ALL: phaddw
+; X86-LABEL: test1:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phaddw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test1:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phaddw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -23,8 +52,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpgt.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test88(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test88
-; ALL: pcmpgtd
+; X86-LABEL: test88:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpgtd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test88:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpgtd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -40,8 +97,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpgt.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test87(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test87
-; ALL: pcmpgtw
+; X86-LABEL: test87:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpgtw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test87:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpgtw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -57,8 +142,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpgt.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test86(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test86
-; ALL: pcmpgtb
+; X86-LABEL: test86:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpgtb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test86:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpgtb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -74,8 +187,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpeq.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test85(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test85
-; ALL: pcmpeqd
+; X86-LABEL: test85:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpeqd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test85:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpeqd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -91,8 +232,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpeq.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test84(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test84
-; ALL: pcmpeqw
+; X86-LABEL: test84:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpeqw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test84:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpeqw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -108,8 +277,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pcmpeq.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test83(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test83
-; ALL: pcmpeqb
+; X86-LABEL: test83:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pcmpeqb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test83:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pcmpeqb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -125,9 +322,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpckldq(x86_mmx, x86_mmx) nounwind readnone
define i64 @test82(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test82
-; X86: punpckldq {{.*#+}} mm0 = mm0[0],mem[0]
-; X64: punpckldq {{.*#+}} mm0 = mm0[0],mm1[0]
+; X86-LABEL: test82:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpckldq {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[0],mem[0]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test82:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpckldq %mm1, %mm0 # mm0 = mm0[0],mm1[0]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -143,9 +367,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpcklwd(x86_mmx, x86_mmx) nounwind readnone
define i64 @test81(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test81
-; X86: punpcklwd {{.*#+}} mm0 = mm0[0],mem[0],mm0[1],mem[1]
-; X64: punpcklwd {{.*#+}} mm0 = mm0[0],mm1[0],mm0[1],mm1[1]
+; X86-LABEL: test81:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpcklwd {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[0],mem[0],mm0[1],mem[1]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test81:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpcklwd %mm1, %mm0 # mm0 = mm0[0],mm1[0],mm0[1],mm1[1]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -161,9 +412,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpcklbw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test80(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test80
-; X86: punpcklbw {{.*#+}} mm0 = mm0[0],mem[0],mm0[1],mem[1],mm0[2],mem[2],mm0[3],mem[3]
-; X64: punpcklbw {{.*#+}} mm0 = mm0[0],mm1[0],mm0[1],mm1[1],mm0[2],mm1[2],mm0[3],mm1[3]
+; X86-LABEL: test80:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpcklbw {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[0],mem[0],mm0[1],mem[1],mm0[2],mem[2],mm0[3],mem[3]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test80:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpcklbw %mm1, %mm0 # mm0 = mm0[0],mm1[0],mm0[1],mm1[1],mm0[2],mm1[2],mm0[3],mm1[3]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -179,9 +457,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpckhdq(x86_mmx, x86_mmx) nounwind readnone
define i64 @test79(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test79
-; X86: punpckhdq {{.*#+}} mm0 = mm0[1],mem[1]
-; X64: punpckhdq {{.*#+}} mm0 = mm0[1],mm1[1]
+; X86-LABEL: test79:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpckhdq {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[1],mem[1]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test79:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpckhdq %mm1, %mm0 # mm0 = mm0[1],mm1[1]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -197,9 +502,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpckhwd(x86_mmx, x86_mmx) nounwind readnone
define i64 @test78(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test78
-; X86: punpckhwd {{.*#+}} mm0 = mm0[2],mem[2],mm0[3],mem[3]
-; X64: punpckhwd {{.*#+}} mm0 = mm0[2],mm1[2],mm0[3],mm1[3]
+; X86-LABEL: test78:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpckhwd {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[2],mem[2],mm0[3],mem[3]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test78:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpckhwd %mm1, %mm0 # mm0 = mm0[2],mm1[2],mm0[3],mm1[3]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -215,9 +547,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.punpckhbw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test77(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test77
-; X86: punpckhbw {{.*#+}} mm0 = mm0[4],mem[4],mm0[5],mem[5],mm0[6],mem[6],mm0[7],mem[7]
-; X64: punpckhbw {{.*#+}} mm0 = mm0[4],mm1[4],mm0[5],mm1[5],mm0[6],mm1[6],mm0[7],mm1[7]
+; X86-LABEL: test77:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: punpckhbw {{[0-9]+}}(%esp), %mm0 # mm0 = mm0[4],mem[4],mm0[5],mem[5],mm0[6],mem[6],mm0[7],mem[7]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test77:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: punpckhbw %mm1, %mm0 # mm0 = mm0[4],mm1[4],mm0[5],mm1[5],mm0[6],mm1[6],mm0[7],mm1[7]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -233,8 +592,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.packuswb(x86_mmx, x86_mmx) nounwind readnone
define i64 @test76(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test76
-; ALL: packuswb
+; X86-LABEL: test76:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: packuswb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test76:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: packuswb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -250,8 +637,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.packssdw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test75(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test75
-; ALL: packssdw
+; X86-LABEL: test75:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: packssdw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test75:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: packssdw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -267,8 +682,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.packsswb(x86_mmx, x86_mmx) nounwind readnone
define i64 @test74(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test74
-; ALL: packsswb
+; X86-LABEL: test74:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: packsswb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test74:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: packsswb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -284,8 +727,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrai.d(x86_mmx, i32) nounwind readnone
define i64 @test73(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test73
-; ALL: psrad
+; X86-LABEL: test73:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrad $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test73:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psrad $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -299,8 +765,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrai.w(x86_mmx, i32) nounwind readnone
define i64 @test72(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test72
-; ALL: psraw
+; X86-LABEL: test72:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psraw $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test72:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psraw $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -312,8 +801,28 @@ entry:
}
define i64 @test72_2(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test72_2
-; ALL-NOT: psraw
+; X86-LABEL: test72_2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test72_2:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -327,8 +836,27 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrli.q(x86_mmx, i32) nounwind readnone
define i64 @test71(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test71
-; ALL: psrlq
+; X86-LABEL: test71:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: psrlq $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test71:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psrlq $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var.i = bitcast i64 %0 to x86_mmx
@@ -340,8 +868,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrli.d(x86_mmx, i32) nounwind readnone
define i64 @test70(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test70
-; ALL: psrld
+; X86-LABEL: test70:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrld $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test70:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psrld $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -353,8 +904,28 @@ entry:
}
define i64 @test70_2(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test70_2
-; ALL-NOT: psrld
+; X86-LABEL: test70_2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test70_2:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -368,8 +939,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrli.w(x86_mmx, i32) nounwind readnone
define i64 @test69(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test69
-; ALL: psrlw
+; X86-LABEL: test69:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrlw $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test69:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psrlw $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -383,8 +977,27 @@ entry:
declare x86_mmx @llvm.x86.mmx.pslli.q(x86_mmx, i32) nounwind readnone
define i64 @test68(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test68
-; ALL: psllq
+; X86-LABEL: test68:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: psllq $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test68:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psllq $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var.i = bitcast i64 %0 to x86_mmx
@@ -396,8 +1009,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.pslli.d(x86_mmx, i32) nounwind readnone
define i64 @test67(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test67
-; ALL: pslld
+; X86-LABEL: test67:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pslld $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test67:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pslld $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -411,8 +1047,31 @@ entry:
declare x86_mmx @llvm.x86.mmx.pslli.w(x86_mmx, i32) nounwind readnone
define i64 @test66(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test66
-; ALL: psllw
+; X86-LABEL: test66:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psllw $3, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test66:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: psllw $3, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -424,8 +1083,28 @@ entry:
}
define i64 @test66_2(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test66_2
-; ALL-NOT: psllw
+; X86-LABEL: test66_2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test66_2:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -439,8 +1118,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psra.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test65(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test65
-; ALL: psrad
+; X86-LABEL: test65:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrad 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test65:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psrad %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -456,8 +1159,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psra.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test64(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test64
-; ALL: psraw
+; X86-LABEL: test64:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psraw 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test64:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psraw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -473,8 +1200,28 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrl.q(x86_mmx, x86_mmx) nounwind readnone
define i64 @test63(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test63
-; ALL: psrlq
+; X86-LABEL: test63:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: psrlq 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test63:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psrlq %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var.i = bitcast i64 %0 to x86_mmx
@@ -488,8 +1235,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrl.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test62(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test62
-; ALL: psrld
+; X86-LABEL: test62:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrld 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test62:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psrld %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -505,8 +1276,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psrl.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test61(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test61
-; ALL: psrlw
+; X86-LABEL: test61:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psrlw 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test61:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psrlw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -522,8 +1317,28 @@ entry:
declare x86_mmx @llvm.x86.mmx.psll.q(x86_mmx, x86_mmx) nounwind readnone
define i64 @test60(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test60
-; ALL: psllq
+; X86-LABEL: test60:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: psllq 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test60:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psllq %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var.i = bitcast i64 %0 to x86_mmx
@@ -537,8 +1352,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psll.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test59(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test59
-; ALL: pslld
+; X86-LABEL: test59:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pslld 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test59:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pslld %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%mmx_var.i = bitcast <2 x i32> %0 to x86_mmx
@@ -554,8 +1393,32 @@ entry:
declare x86_mmx @llvm.x86.mmx.psll.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test58(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test58
-; ALL: psllw
+; X86-LABEL: test58:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psllw 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test58:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psllw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%mmx_var.i = bitcast <4 x i16> %0 to x86_mmx
@@ -571,8 +1434,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pxor(x86_mmx, x86_mmx) nounwind readnone
define i64 @test56(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test56
-; ALL: pxor
+; X86-LABEL: test56:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pxor {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test56:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pxor %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -588,8 +1479,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.por(x86_mmx, x86_mmx) nounwind readnone
define i64 @test55(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test55
-; ALL: por
+; X86-LABEL: test55:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: por {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test55:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: por %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -605,8 +1524,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pandn(x86_mmx, x86_mmx) nounwind readnone
define i64 @test54(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test54
-; ALL: pandn
+; X86-LABEL: test54:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pandn {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test54:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pandn %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -622,8 +1569,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pand(x86_mmx, x86_mmx) nounwind readnone
define i64 @test53(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test53
-; ALL: pand
+; X86-LABEL: test53:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pand {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test53:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pand %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -639,8 +1614,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmull.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test52(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test52
-; ALL: pmullw
+; X86-LABEL: test52:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmullw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test52:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmullw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -654,8 +1657,36 @@ entry:
}
define i64 @test51(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test51
-; ALL: pmullw
+; X86-LABEL: test51:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmullw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test51:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmullw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -671,8 +1702,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmulh.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test50(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test50
-; ALL: pmulhw
+; X86-LABEL: test50:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmulhw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test50:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmulhw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -688,8 +1747,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmadd.wd(x86_mmx, x86_mmx) nounwind readnone
define i64 @test49(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test49
-; ALL: pmaddwd
+; X86-LABEL: test49:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmaddwd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test49:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmaddwd %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -705,8 +1792,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psubus.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test48(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test48
-; ALL: psubusw
+; X86-LABEL: test48:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubusw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test48:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubusw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -722,8 +1837,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psubus.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test47(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test47
-; ALL: psubusb
+; X86-LABEL: test47:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubusb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test47:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubusb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -739,8 +1882,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psubs.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test46(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test46
-; ALL: psubsw
+; X86-LABEL: test46:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test46:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubsw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -756,8 +1927,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psubs.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test45(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test45
-; ALL: psubsb
+; X86-LABEL: test45:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubsb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test45:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubsb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -771,8 +1970,28 @@ entry:
}
define i64 @test44(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test44
-; ALL: psubq
+; X86-LABEL: test44:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: psubq 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test44:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubq %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var = bitcast i64 %0 to x86_mmx
@@ -788,8 +2007,36 @@ declare x86_mmx @llvm.x86.mmx.psub.q(x86_mmx, x86_mmx) nounwind readnone
declare x86_mmx @llvm.x86.mmx.psub.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test43(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test43
-; ALL: psubd
+; X86-LABEL: test43:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test43:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -805,8 +2052,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psub.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test42(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test42
-; ALL: psubw
+; X86-LABEL: test42:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test42:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -822,8 +2097,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psub.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test41(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test41
-; ALL: psubb
+; X86-LABEL: test41:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psubb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test41:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psubb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -839,8 +2142,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.paddus.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test40(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test40
-; ALL: paddusw
+; X86-LABEL: test40:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddusw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test40:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddusw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -856,8 +2187,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.paddus.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test39(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test39
-; ALL: paddusb
+; X86-LABEL: test39:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddusb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test39:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddusb %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -873,8 +2232,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.padds.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test38(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test38
-; ALL: paddsw
+; X86-LABEL: test38:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test38:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddsw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -890,8 +2277,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.padds.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test37(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test37
-; ALL: paddsb
+; X86-LABEL: test37:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddsb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test37:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddsb %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -907,8 +2322,28 @@ entry:
declare x86_mmx @llvm.x86.mmx.padd.q(x86_mmx, x86_mmx) nounwind readnone
define i64 @test36(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test36
-; ALL: paddq
+; X86-LABEL: test36:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: paddq 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test36:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddq %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var = bitcast i64 %0 to x86_mmx
@@ -922,8 +2357,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.padd.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test35(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test35
-; ALL: paddd
+; X86-LABEL: test35:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test35:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddd %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -939,8 +2402,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.padd.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test34(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test34
-; ALL: paddw
+; X86-LABEL: test34:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test34:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -956,8 +2447,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.padd.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test33(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test33
-; ALL: paddb
+; X86-LABEL: test33:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: paddb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test33:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: paddb %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -973,8 +2492,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.psad.bw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test32(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test32
-; ALL: psadbw
+; X86-LABEL: test32:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psadbw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test32:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psadbw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -988,8 +2535,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmins.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test31(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test31
-; ALL: pminsw
+; X86-LABEL: test31:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pminsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test31:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pminsw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1005,8 +2580,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pminu.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test30(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test30
-; ALL: pminub
+; X86-LABEL: test30:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pminub {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test30:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pminub %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1022,8 +2625,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmaxs.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test29(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test29
-; ALL: pmaxsw
+; X86-LABEL: test29:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmaxsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test29:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmaxsw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1039,8 +2670,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmaxu.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test28(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test28
-; ALL: pmaxub
+; X86-LABEL: test28:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmaxub {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test28:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmaxub %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1056,8 +2715,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pavg.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test27(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test27
-; ALL: pavgw
+; X86-LABEL: test27:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pavgw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test27:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pavgw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1073,8 +2760,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pavg.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test26(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test26
-; ALL: pavgb
+; X86-LABEL: test26:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pavgb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test26:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pavgb %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1090,8 +2805,18 @@ entry:
declare void @llvm.x86.mmx.movnt.dq(ptr, x86_mmx) nounwind
define void @test25(ptr %p, <1 x i64> %a) nounwind optsize ssp {
-; ALL-LABEL: @test25
-; ALL: movntq
+; X86-LABEL: test25:
+; X86: # %bb.0: # %entry
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movl {{[0-9]+}}(%esp), %eax
+; X86-NEXT: movntq %mm0, (%eax)
+; X86-NEXT: retl
+;
+; X64-LABEL: test25:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rsi, %mm0
+; X64-NEXT: movntq %mm0, (%rdi)
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var.i = bitcast i64 %0 to x86_mmx
@@ -1102,8 +2827,27 @@ entry:
declare i32 @llvm.x86.mmx.pmovmskb(x86_mmx) nounwind readnone
define i32 @test24(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test24
-; ALL: pmovmskb
+; X86-LABEL: test24:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, (%esp)
+; X86-NEXT: movq (%esp), %mm0
+; X86-NEXT: pmovmskb %mm0, %eax
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test24:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pmovmskb %mm0, %eax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <8 x i8>
%mmx_var.i = bitcast <8 x i8> %0 to x86_mmx
@@ -1114,8 +2858,37 @@ entry:
declare void @llvm.x86.mmx.maskmovq(x86_mmx, x86_mmx, ptr) nounwind
define void @test23(<1 x i64> %d, <1 x i64> %n, ptr %p) nounwind optsize ssp {
-; ALL-LABEL: @test23
-; ALL: maskmovq
+; X86-LABEL: test23:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: pushl %edi
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, (%esp)
+; X86-NEXT: movl 24(%ebp), %edi
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq (%esp), %mm1
+; X86-NEXT: maskmovq %mm0, %mm1
+; X86-NEXT: leal -4(%ebp), %esp
+; X86-NEXT: popl %edi
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test23:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: movq %rdx, %rdi
+; X64-NEXT: maskmovq %mm1, %mm0
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %n to <8 x i8>
%1 = bitcast <1 x i64> %d to <8 x i8>
@@ -1128,8 +2901,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmulhu.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test22(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test22
-; ALL: pmulhuw
+; X86-LABEL: test22:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmulhuw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test22:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmulhuw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1145,9 +2946,30 @@ entry:
declare x86_mmx @llvm.x86.sse.pshuf.w(x86_mmx, i8) nounwind readnone
define i64 @test21(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test21
-; X86: pshufw {{.*#+}} mm0 = mem[3,0,0,0]
-; X64: pshufw {{.*#+}} mm0 = mm0[3,0,0,0]
+; X86-LABEL: test21:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: pshufw $3, {{[0-9]+}}(%esp), %mm0 # mm0 = mem[3,0,0,0]
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test21:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pshufw $3, %mm0, %mm0 # mm0 = mm0[3,0,0,0]
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%1 = bitcast <4 x i16> %0 to x86_mmx
@@ -1159,10 +2981,28 @@ entry:
}
define i32 @test21_2(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test21_2
-; X86: pshufw {{.*#+}} mm0 = mem[3,0,0,0]
-; X64: pshufw {{.*#+}} mm0 = mm0[3,0,0,0]
-; ALL: movd
+; X86-LABEL: test21_2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, (%esp)
+; X86-NEXT: pshufw $3, (%esp), %mm0 # mm0 = mem[3,0,0,0]
+; X86-NEXT: movd %mm0, %eax
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test21_2:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pshufw $3, %mm0, %mm0 # mm0 = mm0[3,0,0,0]
+; X64-NEXT: movd %mm0, %eax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%1 = bitcast <4 x i16> %0 to x86_mmx
@@ -1176,8 +3016,36 @@ entry:
declare x86_mmx @llvm.x86.mmx.pmulu.dq(x86_mmx, x86_mmx) nounwind readnone
define i64 @test20(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test20
-; ALL: pmuludq
+; X86-LABEL: test20:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmuludq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test20:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmuludq %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -1191,8 +3059,26 @@ entry:
declare <2 x double> @llvm.x86.sse.cvtpi2pd(x86_mmx) nounwind readnone
define <2 x double> @test19(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test19
-; ALL: cvtpi2pd
+; X86-LABEL: test19:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, (%esp)
+; X86-NEXT: cvtpi2pd (%esp), %xmm0
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test19:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: cvtpi2pd %mm0, %xmm0
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%1 = bitcast <2 x i32> %0 to x86_mmx
@@ -1203,8 +3089,25 @@ entry:
declare x86_mmx @llvm.x86.sse.cvttpd2pi(<2 x double>) nounwind readnone
define i64 @test18(<2 x double> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test18
-; ALL: cvttpd2pi
+; X86-LABEL: test18:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: cvttpd2pi %xmm0, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test18:
+; X64: # %bb.0: # %entry
+; X64-NEXT: cvttpd2pi %xmm0, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = tail call x86_mmx @llvm.x86.sse.cvttpd2pi(<2 x double> %a) nounwind readnone
%1 = bitcast x86_mmx %0 to <2 x i32>
@@ -1216,8 +3119,25 @@ entry:
declare x86_mmx @llvm.x86.sse.cvtpd2pi(<2 x double>) nounwind readnone
define i64 @test17(<2 x double> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test17
-; ALL: cvtpd2pi
+; X86-LABEL: test17:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: cvtpd2pi %xmm0, %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test17:
+; X64: # %bb.0: # %entry
+; X64-NEXT: cvtpd2pi %xmm0, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = tail call x86_mmx @llvm.x86.sse.cvtpd2pi(<2 x double> %a) nounwind readnone
%1 = bitcast x86_mmx %0 to <2 x i32>
@@ -1229,8 +3149,28 @@ entry:
declare x86_mmx @llvm.x86.mmx.palignr.b(x86_mmx, x86_mmx, i8) nounwind readnone
define i64 @test16(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test16
-; ALL: palignr
+; X86-LABEL: test16:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $8, %esp
+; X86-NEXT: movq 8(%ebp), %mm0
+; X86-NEXT: palignr $16, 16(%ebp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test16:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: palignr $16, %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = extractelement <1 x i64> %a, i32 0
%mmx_var = bitcast i64 %0 to x86_mmx
@@ -1244,8 +3184,30 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pabs.d(x86_mmx) nounwind readnone
define i64 @test15(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test15
-; ALL: pabsd
+; X86-LABEL: test15:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: pabsd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test15:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pabsd %mm0, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <2 x i32>
%1 = bitcast <2 x i32> %0 to x86_mmx
@@ -1259,8 +3221,30 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pabs.w(x86_mmx) nounwind readnone
define i64 @test14(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test14
-; ALL: pabsw
+; X86-LABEL: test14:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: pabsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test14:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pabsw %mm0, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <4 x i16>
%1 = bitcast <4 x i16> %0 to x86_mmx
@@ -1274,8 +3258,30 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pabs.b(x86_mmx) nounwind readnone
define i64 @test13(<1 x i64> %a) nounwind readnone optsize ssp {
-; ALL-LABEL: @test13
-; ALL: pabsb
+; X86-LABEL: test13:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $16, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: pabsb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test13:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: pabsb %mm0, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %a to <8 x i8>
%1 = bitcast <8 x i8> %0 to x86_mmx
@@ -1289,8 +3295,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.psign.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test12(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test12
-; ALL: psignd
+; X86-LABEL: test12:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psignd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test12:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psignd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -1306,8 +3340,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.psign.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test11(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test11
-; ALL: psignw
+; X86-LABEL: test11:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psignw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test11:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psignw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1323,8 +3385,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.psign.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test10(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test10
-; ALL: psignb
+; X86-LABEL: test10:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: psignb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test10:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: psignb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1340,8 +3430,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pshuf.b(x86_mmx, x86_mmx) nounwind readnone
define i64 @test9(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test9
-; ALL: pshufb
+; X86-LABEL: test9:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pshufb {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test9:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pshufb %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1357,8 +3475,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pmul.hr.sw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test8(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test8
-; ALL: pmulhrsw
+; X86-LABEL: test8:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmulhrsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test8:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmulhrsw %mm0, %mm1
+; X64-NEXT: movq %mm1, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1374,8 +3520,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.pmadd.ub.sw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test7(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test7
-; ALL: pmaddubsw
+; X86-LABEL: test7:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: pmaddubsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test7:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: pmaddubsw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <8 x i8>
%1 = bitcast <1 x i64> %a to <8 x i8>
@@ -1391,8 +3565,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.phsub.sw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test6(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test6
-; ALL: phsubsw
+; X86-LABEL: test6:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phsubsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test6:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phsubsw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1408,8 +3610,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.phsub.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test5(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test5
-; ALL: phsubd
+; X86-LABEL: test5:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phsubd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test5:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phsubd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -1425,8 +3655,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.phsub.w(x86_mmx, x86_mmx) nounwind readnone
define i64 @test4(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test4
-; ALL: phsubw
+; X86-LABEL: test4:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phsubw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test4:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phsubw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1442,8 +3700,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.phadd.sw(x86_mmx, x86_mmx) nounwind readnone
define i64 @test3(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test3
-; ALL: phaddsw
+; X86-LABEL: test3:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phaddsw {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test3:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phaddsw %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <4 x i16>
%1 = bitcast <1 x i64> %a to <4 x i16>
@@ -1459,8 +3745,36 @@ entry:
declare x86_mmx @llvm.x86.ssse3.phadd.d(x86_mmx, x86_mmx) nounwind readnone
define i64 @test2(<1 x i64> %a, <1 x i64> %b) nounwind readnone optsize ssp {
-; ALL-LABEL: @test2
-; ALL: phaddd
+; X86-LABEL: test2:
+; X86: # %bb.0: # %entry
+; X86-NEXT: pushl %ebp
+; X86-NEXT: movl %esp, %ebp
+; X86-NEXT: andl $-8, %esp
+; X86-NEXT: subl $24, %esp
+; X86-NEXT: movl 8(%ebp), %eax
+; X86-NEXT: movl 12(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movl 16(%ebp), %eax
+; X86-NEXT: movl 20(%ebp), %ecx
+; X86-NEXT: movl %ecx, {{[0-9]+}}(%esp)
+; X86-NEXT: movl %eax, {{[0-9]+}}(%esp)
+; X86-NEXT: movq {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: phaddd {{[0-9]+}}(%esp), %mm0
+; X86-NEXT: movq %mm0, (%esp)
+; X86-NEXT: movl (%esp), %eax
+; X86-NEXT: movl {{[0-9]+}}(%esp), %edx
+; X86-NEXT: movl %ebp, %esp
+; X86-NEXT: popl %ebp
+; X86-NEXT: retl
+;
+; X64-LABEL: test2:
+; X64: # %bb.0: # %entry
+; X64-NEXT: movq %rdi, %mm0
+; X64-NEXT: movq %rsi, %mm1
+; X64-NEXT: phaddd %mm1, %mm0
+; X64-NEXT: movq %mm0, %rax
+; X64-NEXT: retq
entry:
%0 = bitcast <1 x i64> %b to <2 x i32>
%1 = bitcast <1 x i64> %a to <2 x i32>
@@ -1474,18 +3788,21 @@ entry:
}
define <4 x float> @test89(<4 x float> %a, x86_mmx %b) nounwind {
-; ALL-LABEL: @test89
-; ALL: cvtpi2ps
+; ALL-LABEL: test89:
+; ALL: # %bb.0:
+; ALL-NEXT: cvtpi2ps %mm0, %xmm0
+; ALL-NEXT: ret{{[l|q]}}
%c = tail call <4 x float> @llvm.x86.sse.cvtpi2ps(<4 x float> %a, x86_mmx %b)
ret <4 x float> %c
}
declare <4 x float> @llvm.x86.sse.cvtpi2ps(<4 x float>, x86_mmx) nounwind readnone
-; ALL-LABEL: test90
define void @test90() {
-; ALL-LABEL: @test90
-; ALL: emms
+; ALL-LABEL: test90:
+; ALL: # %bb.0:
+; ALL-NEXT: emms
+; ALL-NEXT: ret{{[l|q]}}
call void @llvm.x86.mmx.emms()
ret void
}
diff --git a/llvm/test/CodeGen/X86/uint_to_fp.ll b/llvm/test/CodeGen/X86/uint_to_fp.ll
index d8e0b61ed199..8c8cbb151974 100644
--- a/llvm/test/CodeGen/X86/uint_to_fp.ll
+++ b/llvm/test/CodeGen/X86/uint_to_fp.ll
@@ -25,3 +25,57 @@ entry:
store float %1, ptr %y
ret void
}
+
+define float @test_without_nneg(i32 %x) nounwind {
+; X86-LABEL: test_without_nneg:
+; X86: ## %bb.0:
+; X86-NEXT: pushl %eax
+; X86-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
+; X86-NEXT: orpd {{\.?LCPI[0-9]+_[0-9]+}}, %xmm0
+; X86-NEXT: subsd {{\.?LCPI[0-9]+_[0-9]+}}, %xmm0
+; X86-NEXT: cvtsd2ss %xmm0, %xmm0
+; X86-NEXT: movss %xmm0, (%esp)
+; X86-NEXT: flds (%esp)
+; X86-NEXT: popl %eax
+; X86-NEXT: retl
+;
+; X64-LABEL: test_without_nneg:
+; X64: ## %bb.0:
+; X64-NEXT: movl %edi, %eax
+; X64-NEXT: cvtsi2ss %rax, %xmm0
+; X64-NEXT: retq
+ %r = uitofp i32 %x to float
+ ret float %r
+}
+
+define float @test_with_nneg(i32 %x) nounwind {
+; X86-LABEL: test_with_nneg:
+; X86: ## %bb.0:
+; X86-NEXT: pushl %eax
+; X86-NEXT: cvtsi2ssl {{[0-9]+}}(%esp), %xmm0
+; X86-NEXT: movss %xmm0, (%esp)
+; X86-NEXT: flds (%esp)
+; X86-NEXT: popl %eax
+; X86-NEXT: retl
+;
+; X64-LABEL: test_with_nneg:
+; X64: ## %bb.0:
+; X64-NEXT: cvtsi2ss %edi, %xmm0
+; X64-NEXT: retq
+ %r = uitofp nneg i32 %x to float
+ ret float %r
+}
+
+define <4 x float> @test_with_nneg_vec(<4 x i32> %x) nounwind {
+; X86-LABEL: test_with_nneg_vec:
+; X86: ## %bb.0:
+; X86-NEXT: cvtdq2ps %xmm0, %xmm0
+; X86-NEXT: retl
+;
+; X64-LABEL: test_with_nneg_vec:
+; X64: ## %bb.0:
+; X64-NEXT: cvtdq2ps %xmm0, %xmm0
+; X64-NEXT: retq
+ %r = uitofp nneg <4 x i32> %x to <4 x float>
+ ret <4 x float> %r
+}
diff --git a/llvm/test/CodeGen/X86/vector-bitreverse.ll b/llvm/test/CodeGen/X86/vector-bitreverse.ll
index d3f357cd1795..1c5326d35bb0 100644
--- a/llvm/test/CodeGen/X86/vector-bitreverse.ll
+++ b/llvm/test/CodeGen/X86/vector-bitreverse.ll
@@ -276,24 +276,10 @@ define i32 @test_bitreverse_i32(i32 %a) nounwind {
;
; GFNIAVX-LABEL: test_bitreverse_i32:
; GFNIAVX: # %bb.0:
-; GFNIAVX-NEXT: # kill: def $edi killed $edi def $rdi
-; GFNIAVX-NEXT: bswapl %edi
-; GFNIAVX-NEXT: movl %edi, %eax
-; GFNIAVX-NEXT: andl $252645135, %eax # imm = 0xF0F0F0F
-; GFNIAVX-NEXT: shll $4, %eax
-; GFNIAVX-NEXT: shrl $4, %edi
-; GFNIAVX-NEXT: andl $252645135, %edi # imm = 0xF0F0F0F
-; GFNIAVX-NEXT: orl %eax, %edi
-; GFNIAVX-NEXT: movl %edi, %eax
-; GFNIAVX-NEXT: andl $858993459, %eax # imm = 0x33333333
-; GFNIAVX-NEXT: shrl $2, %edi
-; GFNIAVX-NEXT: andl $858993459, %edi # imm = 0x33333333
-; GFNIAVX-NEXT: leal (%rdi,%rax,4), %eax
-; GFNIAVX-NEXT: movl %eax, %ecx
-; GFNIAVX-NEXT: andl $1431655765, %ecx # imm = 0x55555555
-; GFNIAVX-NEXT: shrl %eax
-; GFNIAVX-NEXT: andl $1431655765, %eax # imm = 0x55555555
-; GFNIAVX-NEXT: leal (%rax,%rcx,2), %eax
+; GFNIAVX-NEXT: vmovd %edi, %xmm0
+; GFNIAVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0
+; GFNIAVX-NEXT: vmovd %xmm0, %eax
+; GFNIAVX-NEXT: bswapl %eax
; GFNIAVX-NEXT: retq
%b = call i32 @llvm.bitreverse.i32(i32 %a)
ret i32 %b
@@ -381,26 +367,10 @@ define i64 @test_bitreverse_i64(i64 %a) nounwind {
;
; GFNIAVX-LABEL: test_bitreverse_i64:
; GFNIAVX: # %bb.0:
-; GFNIAVX-NEXT: bswapq %rdi
-; GFNIAVX-NEXT: movq %rdi, %rax
-; GFNIAVX-NEXT: shrq $4, %rax
-; GFNIAVX-NEXT: movabsq $1085102592571150095, %rcx # imm = 0xF0F0F0F0F0F0F0F
-; GFNIAVX-NEXT: andq %rcx, %rax
-; GFNIAVX-NEXT: andq %rcx, %rdi
-; GFNIAVX-NEXT: shlq $4, %rdi
-; GFNIAVX-NEXT: orq %rax, %rdi
-; GFNIAVX-NEXT: movabsq $3689348814741910323, %rax # imm = 0x3333333333333333
-; GFNIAVX-NEXT: movq %rdi, %rcx
-; GFNIAVX-NEXT: andq %rax, %rcx
-; GFNIAVX-NEXT: shrq $2, %rdi
-; GFNIAVX-NEXT: andq %rax, %rdi
-; GFNIAVX-NEXT: leaq (%rdi,%rcx,4), %rax
-; GFNIAVX-NEXT: movabsq $6148914691236517205, %rcx # imm = 0x5555555555555555
-; GFNIAVX-NEXT: movq %rax, %rdx
-; GFNIAVX-NEXT: andq %rcx, %rdx
-; GFNIAVX-NEXT: shrq %rax
-; GFNIAVX-NEXT: andq %rcx, %rax
-; GFNIAVX-NEXT: leaq (%rax,%rdx,2), %rax
+; GFNIAVX-NEXT: vmovq %rdi, %xmm0
+; GFNIAVX-NEXT: vgf2p8affineqb $0, {{\.?LCPI[0-9]+_[0-9]+}}(%rip), %xmm0, %xmm0
+; GFNIAVX-NEXT: vmovq %xmm0, %rax
+; GFNIAVX-NEXT: bswapq %rax
; GFNIAVX-NEXT: retq
%b = call i64 @llvm.bitreverse.i64(i64 %a)
ret i64 %b
diff --git a/llvm/test/Instrumentation/MemorySanitizer/overflow.ll b/llvm/test/Instrumentation/MemorySanitizer/overflow.ll
new file mode 100644
index 000000000000..0cfae0008263
--- /dev/null
+++ b/llvm/test/Instrumentation/MemorySanitizer/overflow.ll
@@ -0,0 +1,130 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt %s -S -passes=msan 2>&1 | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define {i64, i1} @test_sadd_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_sadd_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.sadd.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+
+define {i64, i1} @test_uadd_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_uadd_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.uadd.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+
+define {i64, i1} @test_smul_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_smul_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.smul.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+define {i64, i1} @test_umul_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_umul_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.umul.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+define {i64, i1} @test_ssub_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_ssub_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.ssub.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+define {i64, i1} @test_usub_with_overflow(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define { i64, i1 } @test_usub_with_overflow(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { i64, i1 } poison, i64 [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { i64, i1 } [[TMP5]], i1 [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store { i64, i1 } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { i64, i1 } [[RES]]
+;
+ %res = call { i64, i1 } @llvm.usub.with.overflow.i64(i64 %a, i64 %b)
+ ret { i64, i1 } %res
+}
+
+define {<4 x i32>, <4 x i1>} @test_sadd_with_overflow_vec(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: define { <4 x i32>, <4 x i1> } @test_sadd_with_overflow_vec(
+; CHECK-SAME: <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 16) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[TMP3:%.*]] = or <4 x i32> [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[TMP4:%.*]] = icmp ne <4 x i32> [[TMP3]], zeroinitializer
+; CHECK-NEXT: [[TMP5:%.*]] = insertvalue { <4 x i32>, <4 x i1> } poison, <4 x i32> [[TMP3]], 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertvalue { <4 x i32>, <4 x i1> } [[TMP5]], <4 x i1> [[TMP4]], 1
+; CHECK-NEXT: [[RES:%.*]] = call { <4 x i32>, <4 x i1> } @llvm.sadd.with.overflow.v4i32(<4 x i32> [[A]], <4 x i32> [[B]])
+; CHECK-NEXT: store { <4 x i32>, <4 x i1> } [[TMP6]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret { <4 x i32>, <4 x i1> } [[RES]]
+;
+ %res = call { <4 x i32>, <4 x i1> } @llvm.sadd.with.overflow.v4i32(<4 x i32> %a, <4 x i32> %b)
+ ret { <4 x i32>, <4 x i1> } %res
+}
+
+attributes #0 = { sanitize_memory }
diff --git a/llvm/test/Instrumentation/MemorySanitizer/saturating.ll b/llvm/test/Instrumentation/MemorySanitizer/saturating.ll
new file mode 100644
index 000000000000..dcd8a080144b
--- /dev/null
+++ b/llvm/test/Instrumentation/MemorySanitizer/saturating.ll
@@ -0,0 +1,113 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt %s -S -passes=msan 2>&1 | FileCheck %s
+
+target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i64 @test_sadd_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_sadd_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.sadd.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.sadd.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define i64 @test_uadd_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_uadd_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.uadd.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.uadd.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define i64 @test_ssub_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_ssub_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.ssub.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.ssub.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define i64 @test_usub_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_usub_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.usub.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.usub.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define i64 @test_sshl_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_sshl_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.sshl.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.sshl.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define i64 @test_ushl_sat(i64 %a, i64 %b) #0 {
+; CHECK-LABEL: define i64 @test_ushl_sat(
+; CHECK-SAME: i64 [[A:%.*]], i64 [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load i64, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load i64, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 8) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or i64 [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call i64 @llvm.ushl.sat.i64(i64 [[A]], i64 [[B]])
+; CHECK-NEXT: store i64 [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret i64 [[RES]]
+;
+ %res = call i64 @llvm.ushl.sat(i64 %a, i64 %b)
+ ret i64 %res
+}
+
+define <4 x i32> @test_sadd_sat_vec(<4 x i32> %a, <4 x i32> %b) #0 {
+; CHECK-LABEL: define <4 x i32> @test_sadd_sat_vec(
+; CHECK-SAME: <4 x i32> [[A:%.*]], <4 x i32> [[B:%.*]]) #[[ATTR0]] {
+; CHECK-NEXT: [[TMP1:%.*]] = load <4 x i32>, ptr @__msan_param_tls, align 8
+; CHECK-NEXT: [[TMP2:%.*]] = load <4 x i32>, ptr inttoptr (i64 add (i64 ptrtoint (ptr @__msan_param_tls to i64), i64 16) to ptr), align 8
+; CHECK-NEXT: call void @llvm.donothing()
+; CHECK-NEXT: [[_MSPROP:%.*]] = or <4 x i32> [[TMP1]], [[TMP2]]
+; CHECK-NEXT: [[RES:%.*]] = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> [[A]], <4 x i32> [[B]])
+; CHECK-NEXT: store <4 x i32> [[_MSPROP]], ptr @__msan_retval_tls, align 8
+; CHECK-NEXT: ret <4 x i32> [[RES]]
+;
+ %res = call <4 x i32> @llvm.sadd.sat.v4i32(<4 x i32> %a, <4 x i32> %b)
+ ret <4 x i32> %res
+}
+
+
+attributes #0 = { sanitize_memory }
diff --git a/llvm/test/Transforms/InstCombine/and-or-icmps.ll b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
index c8d348df5f42..63b11d0c0bc0 100644
--- a/llvm/test/Transforms/InstCombine/and-or-icmps.ll
+++ b/llvm/test/Transforms/InstCombine/and-or-icmps.ll
@@ -3038,3 +3038,63 @@ define i32 @icmp_slt_0_or_icmp_add_1_sge_100_i32_fail(i32 %x) {
%D = or i32 %C, %B
ret i32 %D
}
+
+define i1 @logical_and_icmps1(i32 %a, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP3:%.*]] = icmp ult i32 [[A:%.*]], 10086
+; CHECK-NEXT: [[RET2:%.*]] = select i1 [[RET1:%.*]], i1 [[CMP3]], i1 false
+; CHECK-NEXT: ret i1 [[RET2]]
+;
+entry:
+ %cmp1 = icmp sgt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp slt i32 %a, 10086
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
+
+define i1 @logical_and_icmps2(i32 %a, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps2(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: ret i1 false
+;
+entry:
+ %cmp1 = icmp slt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp eq i32 %a, 10086
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
+
+define <4 x i1> @logical_and_icmps_vec1(<4 x i32> %a, <4 x i1> %other_cond) {
+; CHECK-LABEL: @logical_and_icmps_vec1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP3:%.*]] = icmp ult <4 x i32> [[A:%.*]], <i32 10086, i32 10086, i32 10086, i32 10086>
+; CHECK-NEXT: [[RET2:%.*]] = select <4 x i1> [[RET1:%.*]], <4 x i1> [[CMP3]], <4 x i1> zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[RET2]]
+;
+entry:
+ %cmp1 = icmp sgt <4 x i32> %a, <i32 -1, i32 -1, i32 -1, i32 -1 >
+ %logical_and = select <4 x i1> %other_cond, <4 x i1> %cmp1, <4 x i1> zeroinitializer
+ %cmp2 = icmp slt <4 x i32> %a, <i32 10086, i32 10086, i32 10086, i32 10086 >
+ %ret = select <4 x i1> %logical_and, <4 x i1> %cmp2, <4 x i1> zeroinitializer
+ ret <4 x i1> %ret
+}
+
+define i1 @logical_and_icmps_fail1(i32 %a, i32 %b, i1 %other_cond) {
+; CHECK-LABEL: @logical_and_icmps_fail1(
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[A:%.*]], -1
+; CHECK-NEXT: [[LOGICAL_AND:%.*]] = select i1 [[OTHER_COND:%.*]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: [[CMP2:%.*]] = icmp slt i32 [[A]], [[B:%.*]]
+; CHECK-NEXT: [[RET:%.*]] = select i1 [[LOGICAL_AND]], i1 [[CMP2]], i1 false
+; CHECK-NEXT: ret i1 [[RET]]
+;
+entry:
+ %cmp1 = icmp sgt i32 %a, -1
+ %logical_and = select i1 %other_cond, i1 %cmp1, i1 false
+ %cmp2 = icmp slt i32 %a, %b
+ %ret = select i1 %logical_and, i1 %cmp2, i1 false
+ ret i1 %ret
+}
diff --git a/llvm/test/Transforms/InstCombine/known-bits.ll b/llvm/test/Transforms/InstCombine/known-bits.ll
index 769f7661fc8d..e27e4a3eddfb 100644
--- a/llvm/test/Transforms/InstCombine/known-bits.ll
+++ b/llvm/test/Transforms/InstCombine/known-bits.ll
@@ -630,5 +630,374 @@ define i8 @or_ne_bits_must_be_unset2_fail(i8 %x, i8 %y) {
ret i8 %r
}
+declare void @use.i1(i1)
+declare void @use.i8(i8)
+
+declare void @use.2xi1(<2 x i1>)
+
+define i1 @extract_value_uadd(<2 x i8> %xx, <2 x i8> %yy) {
+; CHECK-LABEL: @extract_value_uadd(
+; CHECK-NEXT: [[X0:%.*]] = and <2 x i8> [[XX:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[Y0:%.*]] = and <2 x i8> [[YY:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[X0]], <i8 1, i8 0>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <2 x i8> [[Y0]], <i8 1, i8 0>
+; CHECK-NEXT: [[ADD_UOV:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 1
+; CHECK-NEXT: call void @use.2xi1(<2 x i1> [[UOV]])
+; CHECK-NEXT: ret i1 false
+;
+ %x0 = and <2 x i8> %xx, <i8 63, i8 255>
+ %y0 = and <2 x i8> %yy, <i8 63, i8 255>
+ %x = add nuw <2 x i8> %x0, <i8 1, i8 0>
+ %y = add nuw <2 x i8> %y0, <i8 1, i8 0>
+
+ %add_uov = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow(<2 x i8> %x, <2 x i8> %y)
+ %add = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 0
+ %uov = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 1
+ call void @use.2xi1(<2 x i1> %uov)
+ %add_ele = extractelement <2 x i8> %add, i32 0
+ %r = icmp eq i8 %add_ele, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_uadd2(<2 x i8> %xx, <2 x i8> %yy) {
+; CHECK-LABEL: @extract_value_uadd2(
+; CHECK-NEXT: [[X0:%.*]] = and <2 x i8> [[XX:%.*]], <i8 -1, i8 63>
+; CHECK-NEXT: [[Y0:%.*]] = and <2 x i8> [[YY:%.*]], <i8 -1, i8 63>
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[X0]], <i8 0, i8 1>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <2 x i8> [[Y0]], <i8 0, i8 1>
+; CHECK-NEXT: [[ADD_UOV:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 1
+; CHECK-NEXT: call void @use.2xi1(<2 x i1> [[UOV]])
+; CHECK-NEXT: ret i1 false
+;
+ %x0 = and <2 x i8> %xx, <i8 255, i8 63>
+ %y0 = and <2 x i8> %yy, <i8 255, i8 63>
+ %x = add nuw <2 x i8> %x0, <i8 0, i8 1>
+ %y = add nuw <2 x i8> %y0, <i8 0, i8 1>
+
+ %add_uov = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow(<2 x i8> %x, <2 x i8> %y)
+ %add = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 0
+ %uov = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 1
+ call void @use.2xi1(<2 x i1> %uov)
+ %add_ele = extractelement <2 x i8> %add, i32 1
+ %r = icmp eq i8 %add_ele, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_uadd_fail(<2 x i8> %xx, <2 x i8> %yy) {
+; CHECK-LABEL: @extract_value_uadd_fail(
+; CHECK-NEXT: [[X0:%.*]] = and <2 x i8> [[XX:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[Y0:%.*]] = and <2 x i8> [[YY:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[X0]], <i8 1, i8 0>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <2 x i8> [[Y0]], <i8 1, i8 0>
+; CHECK-NEXT: [[ADD_UOV:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
+; CHECK-NEXT: [[ADD:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 1
+; CHECK-NEXT: call void @use.2xi1(<2 x i1> [[UOV]])
+; CHECK-NEXT: [[ADD_ELE:%.*]] = extractelement <2 x i8> [[ADD]], i64 1
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD_ELE]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = and <2 x i8> %xx, <i8 63, i8 255>
+ %y0 = and <2 x i8> %yy, <i8 63, i8 255>
+ %x = add nuw <2 x i8> %x0, <i8 1, i8 0>
+ %y = add nuw <2 x i8> %y0, <i8 1, i8 0>
+
+ %add_uov = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow(<2 x i8> %x, <2 x i8> %y)
+ %add = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 0
+ %uov = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 1
+ call void @use.2xi1(<2 x i1> %uov)
+ %add_ele = extractelement <2 x i8> %add, i32 1
+ %r = icmp eq i8 %add_ele, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_uadd_fail2(<2 x i8> %xx, <2 x i8> %yy, i32 %idx) {
+; CHECK-LABEL: @extract_value_uadd_fail2(
+; CHECK-NEXT: [[X0:%.*]] = and <2 x i8> [[XX:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[Y0:%.*]] = and <2 x i8> [[YY:%.*]], <i8 63, i8 -1>
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[X0]], <i8 1, i8 0>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <2 x i8> [[Y0]], <i8 1, i8 0>
+; CHECK-NEXT: [[ADD_UOV:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
+; CHECK-NEXT: [[ADD:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 1
+; CHECK-NEXT: call void @use.2xi1(<2 x i1> [[UOV]])
+; CHECK-NEXT: [[ADD_ELE:%.*]] = extractelement <2 x i8> [[ADD]], i32 [[IDX:%.*]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD_ELE]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = and <2 x i8> %xx, <i8 63, i8 255>
+ %y0 = and <2 x i8> %yy, <i8 63, i8 255>
+ %x = add nuw <2 x i8> %x0, <i8 1, i8 0>
+ %y = add nuw <2 x i8> %y0, <i8 1, i8 0>
+
+ %add_uov = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow(<2 x i8> %x, <2 x i8> %y)
+ %add = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 0
+ %uov = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 1
+ call void @use.2xi1(<2 x i1> %uov)
+ %add_ele = extractelement <2 x i8> %add, i32 %idx
+ %r = icmp eq i8 %add_ele, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_uadd_fail3(<2 x i8> %xx, <2 x i8> %yy) {
+; CHECK-LABEL: @extract_value_uadd_fail3(
+; CHECK-NEXT: [[X0:%.*]] = and <2 x i8> [[XX:%.*]], <i8 127, i8 127>
+; CHECK-NEXT: [[Y0:%.*]] = and <2 x i8> [[YY:%.*]], <i8 127, i8 127>
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[X0]], <i8 1, i8 1>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <2 x i8> [[Y0]], <i8 1, i8 1>
+; CHECK-NEXT: [[ADD_UOV:%.*]] = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow.v2i8(<2 x i8> [[X]], <2 x i8> [[Y]])
+; CHECK-NEXT: [[ADD:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { <2 x i8>, <2 x i1> } [[ADD_UOV]], 1
+; CHECK-NEXT: call void @use.2xi1(<2 x i1> [[UOV]])
+; CHECK-NEXT: [[ADD_ELE:%.*]] = extractelement <2 x i8> [[ADD]], i64 0
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD_ELE]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = and <2 x i8> %xx, <i8 127, i8 127>
+ %y0 = and <2 x i8> %yy, <i8 127, i8 127>
+ %x = add nuw <2 x i8> %x0, <i8 1, i8 1>
+ %y = add nuw <2 x i8> %y0, <i8 1, i8 1>
+
+ %add_uov = call { <2 x i8>, <2 x i1> } @llvm.uadd.with.overflow(<2 x i8> %x, <2 x i8> %y)
+ %add = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 0
+ %uov = extractvalue { <2 x i8>, <2 x i1> } %add_uov, 1
+ call void @use.2xi1(<2 x i1> %uov)
+ %add_ele = extractelement <2 x i8> %add, i32 0
+ %r = icmp eq i8 %add_ele, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_sadd(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_sadd(
+; CHECK-NEXT: [[X:%.*]] = add nuw i8 [[XX:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[X_LEMMA:%.*]] = icmp sgt i8 [[X]], -1
+; CHECK-NEXT: [[Y_LEMMA:%.*]] = icmp sgt i8 [[Y]], -1
+; CHECK-NEXT: call void @llvm.assume(i1 [[X_LEMMA]])
+; CHECK-NEXT: call void @llvm.assume(i1 [[Y_LEMMA]])
+; CHECK-NEXT: [[ADD_SOV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[ADD_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: ret i1 false
+;
+ %x = add nuw i8 %xx, 1
+ %y = add nuw i8 %yy, 1
+ %x_lemma = icmp ult i8 %x, 128
+ %y_lemma = icmp ult i8 %y, 128
+ call void @llvm.assume(i1 %x_lemma)
+ call void @llvm.assume(i1 %y_lemma)
+
+ %add_sov = call { i8, i1 } @llvm.sadd.with.overflow(i8 %x, i8 %y)
+ %add = extractvalue { i8, i1 } %add_sov, 0
+ %sov = extractvalue { i8, i1 } %add_sov, 1
+ call void @use.i1(i1 %sov)
+ %r = icmp eq i8 %add, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_sadd_fail(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_sadd_fail(
+; CHECK-NEXT: [[X:%.*]] = add i8 [[XX:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[ADD_SOV:%.*]] = call { i8, i1 } @llvm.sadd.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[ADD:%.*]] = extractvalue { i8, i1 } [[ADD_SOV]], 0
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[ADD_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[ADD]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = add i8 %xx, 1
+ %y = add i8 %yy, 1
+
+ %add_sov = call { i8, i1 } @llvm.sadd.with.overflow(i8 %x, i8 %y)
+ %add = extractvalue { i8, i1 } %add_sov, 0
+ %sov = extractvalue { i8, i1 } %add_sov, 1
+ call void @use.i1(i1 %sov)
+ %r = icmp eq i8 %add, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_usub(i8 %x, i8 %zz) {
+; CHECK-LABEL: @extract_value_usub(
+; CHECK-NEXT: [[Z:%.*]] = add nuw i8 [[ZZ:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[Z]], [[X:%.*]]
+; CHECK-NEXT: [[SUB_UOV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SUB_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { i8, i1 } [[SUB_UOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[UOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[SUB]])
+; CHECK-NEXT: ret i1 false
+;
+ %z = add nuw i8 %zz, 1
+ %y = add i8 %x, %z
+
+ %sub_uov = call { i8, i1 } @llvm.usub.with.overflow(i8 %x, i8 %y)
+ %sub = extractvalue { i8, i1 } %sub_uov, 0
+ %uov = extractvalue { i8, i1 } %sub_uov, 1
+ call void @use.i1(i1 %uov)
+ call void @use.i8(i8 %sub)
+ %r = icmp eq i8 %sub, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_usub_fail(i8 %x, i8 %z) {
+; CHECK-LABEL: @extract_value_usub_fail(
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[X:%.*]], [[Z:%.*]]
+; CHECK-NEXT: [[SUB_UOV:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SUB_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { i8, i1 } [[SUB_UOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[UOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[SUB]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[SUB]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %y = add i8 %x, %z
+ %sub_uov = call { i8, i1 } @llvm.usub.with.overflow(i8 %x, i8 %y)
+ %sub = extractvalue { i8, i1 } %sub_uov, 0
+ %uov = extractvalue { i8, i1 } %sub_uov, 1
+ call void @use.i1(i1 %uov)
+ call void @use.i8(i8 %sub)
+ %r = icmp eq i8 %sub, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_ssub(i8 %x, i8 %zz) {
+; CHECK-LABEL: @extract_value_ssub(
+; CHECK-NEXT: [[Z:%.*]] = add nuw i8 [[ZZ:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[Z]], [[X:%.*]]
+; CHECK-NEXT: [[SUB_SOV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[Y]], i8 [[X]])
+; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SUB_SOV]], 0
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[SUB_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[SUB]])
+; CHECK-NEXT: ret i1 false
+;
+ %z = add nuw i8 %zz, 1
+ %y = add i8 %x, %z
+
+ %sub_sov = call { i8, i1 } @llvm.ssub.with.overflow(i8 %y, i8 %x)
+ %sub = extractvalue { i8, i1 } %sub_sov, 0
+ %sov = extractvalue { i8, i1 } %sub_sov, 1
+ call void @use.i1(i1 %sov)
+ call void @use.i8(i8 %sub)
+ %r = icmp eq i8 %sub, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_ssub_fail(i8 %x) {
+; CHECK-LABEL: @extract_value_ssub_fail(
+; CHECK-NEXT: [[SUB_SOV:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 10, i8 [[X:%.*]])
+; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SUB_SOV]], 0
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[SUB_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[SUB]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[SUB]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %sub_sov = call { i8, i1 } @llvm.ssub.with.overflow(i8 10, i8 %x)
+ %sub = extractvalue { i8, i1 } %sub_sov, 0
+ %sov = extractvalue { i8, i1 } %sub_sov, 1
+ call void @use.i1(i1 %sov)
+ call void @use.i8(i8 %sub)
+ %r = icmp eq i8 %sub, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_umul(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_umul(
+; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[MUL_UOV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i8, i1 } [[MUL_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { i8, i1 } [[MUL_UOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[UOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[MUL]])
+; CHECK-NEXT: ret i1 false
+;
+ %x = or i8 %xx, 1
+ %y = add nuw i8 %yy, 1
+
+ %mul_uov = call { i8, i1 } @llvm.umul.with.overflow(i8 %x, i8 %y)
+ %mul = extractvalue { i8, i1 } %mul_uov, 0
+ %uov = extractvalue { i8, i1 } %mul_uov, 1
+ call void @use.i1(i1 %uov)
+ call void @use.i8(i8 %mul)
+ %r = icmp eq i8 %mul, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_umul_fail(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_umul_fail(
+; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], 2
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[MUL_UOV:%.*]] = call { i8, i1 } @llvm.umul.with.overflow.i8(i8 [[X]], i8 [[Y]])
+; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i8, i1 } [[MUL_UOV]], 0
+; CHECK-NEXT: [[UOV:%.*]] = extractvalue { i8, i1 } [[MUL_UOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[UOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[MUL]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[MUL]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = or i8 %xx, 2
+ %y = add nuw i8 %yy, 1
+
+ %mul_uov = call { i8, i1 } @llvm.umul.with.overflow(i8 %x, i8 %y)
+ %mul = extractvalue { i8, i1 } %mul_uov, 0
+ %uov = extractvalue { i8, i1 } %mul_uov, 1
+ call void @use.i1(i1 %uov)
+ call void @use.i8(i8 %mul)
+ %r = icmp eq i8 %mul, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_smul(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_smul(
+; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[MUL_SOV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[Y]], i8 [[X]])
+; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i8, i1 } [[MUL_SOV]], 0
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[MUL_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[MUL]])
+; CHECK-NEXT: ret i1 false
+;
+ %x = or i8 %xx, 1
+ %y = add nuw i8 %yy, 1
+
+ %mul_sov = call { i8, i1 } @llvm.smul.with.overflow(i8 %y, i8 %x)
+ %mul = extractvalue { i8, i1 } %mul_sov, 0
+ %sov = extractvalue { i8, i1 } %mul_sov, 1
+ call void @use.i1(i1 %sov)
+ call void @use.i8(i8 %mul)
+ %r = icmp eq i8 %mul, 0
+ ret i1 %r
+}
+
+define i1 @extract_value_smul_fail(i8 %xx, i8 %yy) {
+; CHECK-LABEL: @extract_value_smul_fail(
+; CHECK-NEXT: [[X:%.*]] = or i8 [[XX:%.*]], 1
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[MUL_SOV:%.*]] = call { i8, i1 } @llvm.smul.with.overflow.i8(i8 [[Y]], i8 [[X]])
+; CHECK-NEXT: [[MUL:%.*]] = extractvalue { i8, i1 } [[MUL_SOV]], 0
+; CHECK-NEXT: [[SOV:%.*]] = extractvalue { i8, i1 } [[MUL_SOV]], 1
+; CHECK-NEXT: call void @use.i1(i1 [[SOV]])
+; CHECK-NEXT: call void @use.i8(i8 [[MUL]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[MUL]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = or i8 %xx, 1
+ %y = add i8 %yy, 1
+
+ %mul_sov = call { i8, i1 } @llvm.smul.with.overflow(i8 %y, i8 %x)
+ %mul = extractvalue { i8, i1 } %mul_sov, 0
+ %sov = extractvalue { i8, i1 } %mul_sov, 1
+ call void @use.i1(i1 %sov)
+ call void @use.i8(i8 %mul)
+ %r = icmp eq i8 %mul, 0
+ ret i1 %r
+}
+
declare void @use(i1)
declare void @sink(i8)
diff --git a/llvm/test/Transforms/InstCombine/logical-select.ll b/llvm/test/Transforms/InstCombine/logical-select.ll
index f0ea09c08847..c850b87bb2dd 100644
--- a/llvm/test/Transforms/InstCombine/logical-select.ll
+++ b/llvm/test/Transforms/InstCombine/logical-select.ll
@@ -1303,3 +1303,221 @@ define i1 @logical_or_and_with_common_not_op_variant5(i1 %a) {
%or = select i1 %a, i1 true, i1 %and
ret i1 %or
}
+
+define i1 @reduce_logical_and1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP1]], [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp1, i1 false
+ %and2 = select i1 %and1, i1 %cmp, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @reduce_logical_and2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[TMP0:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT: [[B:%.*]] = and i1 [[TMP0]], [[B1:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 [[B]], i1 false
+; CHECK-NEXT: ret i1 [[AND3]]
+;
+bb:
+ %or = xor i1 %c, %b
+ %and1 = select i1 %a, i1 %or, i1 false
+ %and2 = select i1 %and1, i1 %b, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and3(i1 %a, i32 %b, i32 noundef %c) {
+; CHECK-LABEL: @reduce_logical_and3(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = and i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 [[TMP0]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP1]], [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp1
+ %and2 = select i1 %and1, i1 true, i1 %cmp
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or2(i1 %a, i1 %b, i1 %c) {
+; CHECK-LABEL: @reduce_logical_or2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[B:%.*]] = or i1 [[C:%.*]], [[B1:%.*]]
+; CHECK-NEXT: [[AND3:%.*]] = select i1 [[AND2:%.*]], i1 true, i1 [[B]]
+; CHECK-NEXT: ret i1 [[AND3]]
+;
+bb:
+ %or = xor i1 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %or
+ %and2 = select i1 %and1, i1 true, i1 %b
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or3(i1 %a, i32 %b, i32 noundef %c) {
+; CHECK-LABEL: @reduce_logical_or3(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[TMP0:%.*]] = or i1 [[CMP]], [[CMP1]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[TMP0]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and_fail1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and_fail1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and_fail2(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and_fail2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP]], i1 false
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, 7
+ %and1 = select i1 %a, i1 %cmp, i1 false
+ %and2 = select i1 %and1, i1 %cmp1, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or_fail1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or_fail1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_or_fail2(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_or_fail2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], 7
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 true, i1 [[CMP]]
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 true, i1 [[CMP1]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, 7
+ %and1 = select i1 %a, i1 true, i1 %cmp
+ %and2 = select i1 %and1, i1 true, i1 %cmp1
+ ret i1 %and2
+}
+
+define i1 @reduce_logical_and_multiuse(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_logical_and_multiuse(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: call void @use1(i1 [[AND1]])
+; CHECK-NEXT: [[AND2:%.*]] = select i1 [[AND1]], i1 [[CMP]], i1 false
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp1, i1 false
+ call void @use1(i1 %and1)
+ %and2 = select i1 %and1, i1 %cmp, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_bitwise_and1(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_bitwise_and1(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = or i1 [[CMP1]], [[A:%.*]]
+; CHECK-NEXT: [[AND2:%.*]] = and i1 [[AND1]], [[CMP]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = or i1 %a, %cmp1
+ %and2 = select i1 %and1, i1 %cmp, i1 false
+ ret i1 %and2
+}
+
+define i1 @reduce_bitwise_and2(i1 %a, i32 %b, i32 %c) {
+; CHECK-LABEL: @reduce_bitwise_and2(
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[B:%.*]], 6
+; CHECK-NEXT: [[CMP1:%.*]] = icmp sgt i32 [[C:%.*]], [[B]]
+; CHECK-NEXT: [[AND1:%.*]] = select i1 [[A:%.*]], i1 [[CMP1]], i1 false
+; CHECK-NEXT: [[AND2:%.*]] = or i1 [[AND1]], [[CMP]]
+; CHECK-NEXT: ret i1 [[AND2]]
+;
+bb:
+ %cmp = icmp slt i32 %b, 6
+ %cmp1 = icmp sgt i32 %c, %b
+ %and1 = select i1 %a, i1 %cmp1, i1 false
+ %and2 = or i1 %and1, %cmp
+ ret i1 %and2
+}
diff --git a/llvm/test/Transforms/InstCombine/shl-demand.ll b/llvm/test/Transforms/InstCombine/shl-demand.ll
index 85752890b4b8..26175ebbe153 100644
--- a/llvm/test/Transforms/InstCombine/shl-demand.ll
+++ b/llvm/test/Transforms/InstCombine/shl-demand.ll
@@ -1,6 +1,124 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
; RUN: opt -passes=instcombine -S < %s | FileCheck %s
+
+; If we only want bits that already match the signbit then we don't need to shift.
+; https://alive2.llvm.org/ce/z/WJBPVt
+define i32 @src_srem_shl_demand_max_signbit(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_max_signbit(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 2
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SREM]], -2147483648
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 2 ; srem = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSD
+ %shl = shl i32 %srem, 30 ; shl = SD000000000000000000000000000000
+ %mask = and i32 %shl, -2147483648 ; mask = 10000000000000000000000000000000
+ ret i32 %mask
+}
+
+define i32 @src_srem_shl_demand_min_signbit(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_min_signbit(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 1073741823
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SREM]], -2147483648
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 1073741823 ; srem = SSDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ %shl = shl i32 %srem, 1 ; shl = SDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD0
+ %mask = and i32 %shl, -2147483648 ; mask = 10000000000000000000000000000000
+ ret i32 %mask
+}
+
+define i32 @src_srem_shl_demand_max_mask(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_max_mask(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 2
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SREM]], -4
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 2 ; srem = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSSD
+ %shl = shl i32 %srem, 1 ; shl = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSD0
+ %mask = and i32 %shl, -4 ; mask = 11111111111111111111111111111100
+ ret i32 %mask
+}
+
+; Negative test - mask demands non-signbit from shift source
+define i32 @src_srem_shl_demand_max_signbit_mask_hit_first_demand(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_max_signbit_mask_hit_first_demand(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 4
+; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[SREM]], 29
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SHL]], -1073741824
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 4 ; srem = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSDD
+ %shl = shl i32 %srem, 29 ; shl = SDD00000000000000000000000000000
+ %mask = and i32 %shl, -1073741824 ; mask = 11000000000000000000000000000000
+ ret i32 %mask
+}
+
+define i32 @src_srem_shl_demand_min_signbit_mask_hit_last_demand(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_min_signbit_mask_hit_last_demand(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 536870912
+; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[SREM]], 1
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SHL]], -1073741822
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 536870912 ; srem = SSSDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ %shl = shl i32 %srem, 1 ; shl = SSDDDDDDDDDDDDDDDDDDDDDDDDDDDDD0
+ %mask = and i32 %shl, -1073741822 ; mask = 11000000000000000000000000000010
+ ret i32 %mask
+}
+
+define i32 @src_srem_shl_demand_eliminate_signbit(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_eliminate_signbit(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 1073741824
+; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[SREM]], 1
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SHL]], 2
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 1073741824 ; srem = SSDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD
+ %shl = shl i32 %srem, 1 ; shl = DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD0
+ %mask = and i32 %shl, 2 ; mask = 00000000000000000000000000000010
+ ret i32 %mask
+}
+
+define i32 @src_srem_shl_demand_max_mask_hit_demand(i32 %a0) {
+; CHECK-LABEL: @src_srem_shl_demand_max_mask_hit_demand(
+; CHECK-NEXT: [[SREM:%.*]] = srem i32 [[A0:%.*]], 4
+; CHECK-NEXT: [[SHL:%.*]] = shl nsw i32 [[SREM]], 1
+; CHECK-NEXT: [[MASK:%.*]] = and i32 [[SHL]], -4
+; CHECK-NEXT: ret i32 [[MASK]]
+;
+ %srem = srem i32 %a0, 4 ; srem = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSSDD
+ %shl= shl i32 %srem, 1 ; shl = SSSSSSSSSSSSSSSSSSSSSSSSSSSSSDD0
+ %mask = and i32 %shl, -4 ; mask = 11111111111111111111111111111100
+ ret i32 %mask
+}
+
+define <2 x i32> @src_srem_shl_mask_vector(<2 x i32> %a0) {
+; CHECK-LABEL: @src_srem_shl_mask_vector(
+; CHECK-NEXT: [[SREM:%.*]] = srem <2 x i32> [[A0:%.*]], <i32 4, i32 4>
+; CHECK-NEXT: [[SHL:%.*]] = shl nsw <2 x i32> [[SREM]], <i32 29, i32 29>
+; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[SHL]], <i32 -1073741824, i32 -1073741824>
+; CHECK-NEXT: ret <2 x i32> [[MASK]]
+;
+ %srem = srem <2 x i32> %a0, <i32 4, i32 4>
+ %shl = shl <2 x i32> %srem, <i32 29, i32 29>
+ %mask = and <2 x i32> %shl, <i32 -1073741824, i32 -1073741824>
+ ret <2 x i32> %mask
+}
+
+define <2 x i32> @src_srem_shl_mask_vector_nonconstant(<2 x i32> %a0, <2 x i32> %a1) {
+; CHECK-LABEL: @src_srem_shl_mask_vector_nonconstant(
+; CHECK-NEXT: [[SREM:%.*]] = srem <2 x i32> [[A0:%.*]], <i32 4, i32 4>
+; CHECK-NEXT: [[SHL:%.*]] = shl <2 x i32> [[SREM]], [[A1:%.*]]
+; CHECK-NEXT: [[MASK:%.*]] = and <2 x i32> [[SHL]], <i32 -1073741824, i32 -1073741824>
+; CHECK-NEXT: ret <2 x i32> [[MASK]]
+;
+ %srem = srem <2 x i32> %a0, <i32 4, i32 4>
+ %shl = shl <2 x i32> %srem, %a1
+ %mask = and <2 x i32> %shl, <i32 -1073741824, i32 -1073741824>
+ ret <2 x i32> %mask
+}
+
define i16 @sext_shl_trunc_same_size(i16 %x, i32 %y) {
; CHECK-LABEL: @sext_shl_trunc_same_size(
; CHECK-NEXT: [[CONV1:%.*]] = zext i16 [[X:%.*]] to i32
diff --git a/llvm/test/Transforms/InstCombine/vector-reduce-min-max-known.ll b/llvm/test/Transforms/InstCombine/vector-reduce-min-max-known.ll
new file mode 100644
index 000000000000..65d000835326
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/vector-reduce-min-max-known.ll
@@ -0,0 +1,274 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+define i1 @vec_reduce_umax_non_zero(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_non_zero(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 0, i8 1, i8 0, i8 0>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 0, i8 1, i8 0, i8 0>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_umax_non_zero_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_non_zero_fail(
+; CHECK-NEXT: [[X:%.*]] = add nsw <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = add nsw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_umin_non_zero(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_non_zero(
+; CHECK-NEXT: ret i1 false
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_umin_non_zero_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_non_zero_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 0, i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 0, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smax_non_zero0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smax_non_zero0(
+; CHECK-NEXT: ret i1 false
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.smax(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smax_non_zero1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smax_non_zero1(
+; CHECK-NEXT: [[X0:%.*]] = and <4 x i8> [[XX:%.*]], <i8 127, i8 -1, i8 -1, i8 -1>
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[X0]], <i8 1, i8 0, i8 0, i8 0>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.smax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = and <4 x i8> %xx, <i8 127, i8 255, i8 255, i8 255>
+ %x = or <4 x i8> %x0, <i8 1, i8 0, i8 0, i8 0>
+ %v = call i8 @llvm.vector.reduce.smax(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smax_non_zero_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smax_non_zero_fail(
+; CHECK-NEXT: [[X0:%.*]] = and <4 x i8> [[XX:%.*]], <i8 127, i8 -1, i8 -1, i8 -1>
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[X0]], <i8 1, i8 0, i8 0, i8 0>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.smax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = and <4 x i8> %xx, <i8 127, i8 255, i8 255, i8 255>
+ %x = add nuw <4 x i8> %x0, <i8 1, i8 0, i8 0, i8 0>
+ %v = call i8 @llvm.vector.reduce.smax(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smin_non_zero0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smin_non_zero0(
+; CHECK-NEXT: ret i1 false
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.smin(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smin_non_zero1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smin_non_zero1(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 0, i8 0, i8 0, i8 -128>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.smin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 0, i8 0, i8 0, i8 128>
+ %v = call i8 @llvm.vector.reduce.smin(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i1 @vec_reduce_smin_non_zero_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smin_non_zero_fail(
+; CHECK-NEXT: [[X0:%.*]] = or <4 x i8> [[XX:%.*]], <i8 0, i8 0, i8 0, i8 -128>
+; CHECK-NEXT: [[X:%.*]] = add <4 x i8> [[X0]], <i8 0, i8 0, i8 0, i8 1>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.smin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[V]], 0
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %x0 = or <4 x i8> %xx, <i8 0, i8 0, i8 0, i8 128>
+ %x = add <4 x i8> %x0, <i8 0, i8 0, i8 0, i8 1>
+ %v = call i8 @llvm.vector.reduce.smin(<4 x i8> %x)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define i8 @vec_reduce_umax_known0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_known0(
+; CHECK-NEXT: ret i8 1
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umax_known1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_known1(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 -128>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], -128
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 128>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = and i8 %v, 128
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umax_known_fail0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_known_fail0(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 -128>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 1
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 128>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umax_known_fail1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umax_known_fail1(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 1, i8 2, i8 4, i8 8>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 1
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 2, i8 4, i8 8>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umin_known0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_known0(
+; CHECK-NEXT: ret i8 1
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umin_known1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_known1(
+; CHECK-NEXT: [[X:%.*]] = and <4 x i8> [[XX:%.*]], <i8 127, i8 -1, i8 -1, i8 -1>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], -128
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = and <4 x i8> %xx, <i8 127, i8 255, i8 255, i8 255>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = and i8 %v, 128
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umin_known_fail0(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_known_fail0(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 1, i8 0, i8 0, i8 0>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 1
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x0 = and <4 x i8> %xx, <i8 127, i8 255, i8 255, i8 255>
+ %x = or <4 x i8> %xx, <i8 1, i8 0, i8 0, i8 0>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_umin_known_fail1(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_umin_known_fail1(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 1, i8 2, i8 4, i8 8>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 1
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 1, i8 2, i8 4, i8 8>
+ %v = call i8 @llvm.vector.reduce.umin(<4 x i8> %x)
+ %r = and i8 %v, 1
+ ret i8 %r
+}
+
+define i8 @vec_reduce_smax_known(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smax_known(
+; CHECK-NEXT: ret i8 4
+;
+ %x = or <4 x i8> %xx, <i8 4, i8 4, i8 4, i8 5>
+ %v = call i8 @llvm.vector.reduce.smax(<4 x i8> %x)
+ %r = and i8 %v, 4
+ ret i8 %r
+}
+
+define i8 @vec_reduce_smax_known_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smax_known_fail(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 4, i8 4, i8 8, i8 5>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.umax.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 4
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 4, i8 4, i8 8, i8 5>
+ %v = call i8 @llvm.vector.reduce.umax(<4 x i8> %x)
+ %r = and i8 %v, 4
+ ret i8 %r
+}
+
+define i8 @vec_reduce_smin_known(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smin_known(
+; CHECK-NEXT: ret i8 8
+;
+ %x = or <4 x i8> %xx, <i8 8, i8 24, i8 56, i8 9>
+ %v = call i8 @llvm.vector.reduce.smin(<4 x i8> %x)
+ %r = and i8 %v, 8
+ ret i8 %r
+}
+
+define i8 @vec_reduce_smin_known_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @vec_reduce_smin_known_fail(
+; CHECK-NEXT: [[X:%.*]] = or <4 x i8> [[XX:%.*]], <i8 8, i8 23, i8 56, i8 9>
+; CHECK-NEXT: [[V:%.*]] = call i8 @llvm.vector.reduce.smin.v4i8(<4 x i8> [[X]])
+; CHECK-NEXT: [[R:%.*]] = and i8 [[V]], 8
+; CHECK-NEXT: ret i8 [[R]]
+;
+ %x = or <4 x i8> %xx, <i8 8, i8 23, i8 56, i8 9>
+ %v = call i8 @llvm.vector.reduce.smin(<4 x i8> %x)
+ %r = and i8 %v, 8
+ ret i8 %r
+}
diff --git a/llvm/test/Transforms/InstSimplify/icmp.ll b/llvm/test/Transforms/InstSimplify/icmp.ll
index 3109768bdfe0..c94922197096 100644
--- a/llvm/test/Transforms/InstSimplify/icmp.ll
+++ b/llvm/test/Transforms/InstSimplify/icmp.ll
@@ -270,7 +270,7 @@ define i1 @load_ptr(ptr %p) {
define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
; CHECK-LABEL: @load_ptr_null_valid(
-; CHECK-NEXT: [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable !0
+; CHECK-NEXT: [[LOAD_P:%.*]] = load ptr, ptr [[P:%.*]], align 8, !dereferenceable [[META0:![0-9]+]]
; CHECK-NEXT: [[R:%.*]] = icmp ne ptr [[LOAD_P]], null
; CHECK-NEXT: ret i1 [[R]]
;
@@ -278,3 +278,139 @@ define i1 @load_ptr_null_valid(ptr %p) null_pointer_is_valid {
%r = icmp ne ptr %load_p, null
ret i1 %r
}
+
+define i1 @non_eq_disjoint_or_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op(
+; CHECK-NEXT: ret i1 false
+;
+ %w = add nuw i8 %ww, 1
+ %z = add i8 %y, %w
+
+ %xy = or disjoint i8 %x, %y
+ %xz = or disjoint i8 %x, %z
+
+ %axy = add i8 %a, %xy
+ %axz = add i8 %a, %xz
+ %r = icmp eq i8 %axy, %axz
+ ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_disjoint_or_common_op_fail(
+; CHECK-NEXT: [[W:%.*]] = add nuw i8 [[WW:%.*]], 1
+; CHECK-NEXT: [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT: [[XY:%.*]] = or i8 [[X:%.*]], [[Y]]
+; CHECK-NEXT: [[XZ:%.*]] = or disjoint i8 [[X]], [[Z]]
+; CHECK-NEXT: [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT: [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %w = add nuw i8 %ww, 1
+ %z = add i8 %y, %w
+
+ %xy = or i8 %x, %y
+ %xz = or disjoint i8 %x, %z
+
+ %axy = add i8 %a, %xy
+ %axz = add i8 %a, %xz
+ %r = icmp eq i8 %axy, %axz
+ ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op(
+; CHECK-NEXT: ret i1 false
+;
+ %w = add nuw i8 %ww, 1
+ %z = add i8 %y, %w
+
+ %xy = xor i8 %y, %x
+ %xz = xor i8 %x, %z
+
+ %axy = add i8 %a, %xy
+ %axz = add i8 %a, %xz
+ %r = icmp eq i8 %axy, %axz
+ ret i1 %r
+}
+
+define i1 @non_eq_xor_common_op_fail(i8 %x, i8 %y, i8 %ww, i8 %a) {
+; CHECK-LABEL: @non_eq_xor_common_op_fail(
+; CHECK-NEXT: [[W:%.*]] = add nsw i8 [[WW:%.*]], 1
+; CHECK-NEXT: [[Z:%.*]] = add i8 [[Y:%.*]], [[W]]
+; CHECK-NEXT: [[XY:%.*]] = xor i8 [[Y]], [[X:%.*]]
+; CHECK-NEXT: [[XZ:%.*]] = xor i8 [[X]], [[Z]]
+; CHECK-NEXT: [[AXY:%.*]] = add i8 [[A:%.*]], [[XY]]
+; CHECK-NEXT: [[AXZ:%.*]] = add i8 [[A]], [[XZ]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[AXY]], [[AXZ]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %w = add nsw i8 %ww, 1
+ %z = add i8 %y, %w
+
+ %xy = xor i8 %y, %x
+ %xz = xor i8 %x, %z
+
+ %axy = add i8 %a, %xy
+ %axz = add i8 %a, %xz
+ %r = icmp eq i8 %axy, %axz
+ ret i1 %r
+}
+
+define i1 @non_eq_disjoint_or(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_disjoint_or(
+; CHECK-NEXT: ret i1 false
+;
+ %y = add nuw i8 %yy, 1
+ %lhs = add i8 %x, %w
+ %val = or disjoint i8 %y, %w
+ %rhs = add i8 %x, %val
+ %r = icmp eq i8 %lhs, %rhs
+ ret i1 %r
+}
+
+define i1 @non_eq_or_fail(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_or_fail(
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT: [[VAL:%.*]] = or i8 [[Y]], [[W]]
+; CHECK-NEXT: [[RHS:%.*]] = add i8 [[X]], [[VAL]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %y = add nuw i8 %yy, 1
+ %lhs = add i8 %x, %w
+ %val = or i8 %y, %w
+ %rhs = add i8 %x, %val
+ %r = icmp eq i8 %lhs, %rhs
+ ret i1 %r
+}
+
+define i1 @non_eq_xor(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_xor(
+; CHECK-NEXT: ret i1 false
+;
+ %y = add nuw i8 %yy, 1
+ %lhs = add i8 %x, %w
+ %val = xor i8 %y, %w
+ %rhs = add i8 %x, %val
+ %r = icmp eq i8 %lhs, %rhs
+ ret i1 %r
+}
+
+define i1 @non_eq_xor_fail(i8 %x, i8 %yy, i8 %w) {
+; CHECK-LABEL: @non_eq_xor_fail(
+; CHECK-NEXT: [[Y:%.*]] = add nsw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[LHS:%.*]] = add i8 [[X:%.*]], [[W:%.*]]
+; CHECK-NEXT: [[VAL:%.*]] = xor i8 [[Y]], [[W]]
+; CHECK-NEXT: [[RHS:%.*]] = add i8 [[X]], [[VAL]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq i8 [[LHS]], [[RHS]]
+; CHECK-NEXT: ret i1 [[R]]
+;
+ %y = add nsw i8 %yy, 1
+ %lhs = add i8 %x, %w
+ %val = xor i8 %y, %w
+ %rhs = add i8 %x, %val
+ %r = icmp eq i8 %lhs, %rhs
+ ret i1 %r
+}
diff --git a/llvm/test/Transforms/InstSimplify/known-non-zero.ll b/llvm/test/Transforms/InstSimplify/known-non-zero.ll
index b647f11af446..d9b8f5eed323 100644
--- a/llvm/test/Transforms/InstSimplify/known-non-zero.ll
+++ b/llvm/test/Transforms/InstSimplify/known-non-zero.ll
@@ -166,3 +166,214 @@ A:
B:
ret i1 0
}
+
+define i1 @smax_non_zero(i8 %xx, i8 %y) {
+; CHECK-LABEL: @smax_non_zero(
+; CHECK-NEXT: ret i1 false
+;
+ %x0 = and i8 %xx, 63
+ %x = add i8 %x0, 1
+ %v = call i8 @llvm.smax.i8(i8 %x, i8 %y)
+ %r = icmp eq i8 %v, 0
+ ret i1 %r
+}
+
+define <4 x i1> @shuf_nonzero_both(<4 x i8> %xx, <4 x i8> %yy) {
+; CHECK-LABEL: @shuf_nonzero_both(
+; CHECK-NEXT: ret <4 x i1> zeroinitializer
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %y = add nuw <4 x i8> %yy, <i8 1, i8 1, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> %y, <4 x i32> <i32 0, i32 4, i32 7, i32 2>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_both_fail(<4 x i8> %xx, <4 x i8> %yy) {
+; CHECK-LABEL: @shuf_nonzero_both_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[Y:%.*]] = add nuw <4 x i8> [[YY:%.*]], <i8 1, i8 1, i8 1, i8 0>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i8> [[X]], <4 x i8> [[Y]], <4 x i32> <i32 0, i32 4, i32 7, i32 2>
+; CHECK-NEXT: [[R:%.*]] = icmp eq <4 x i8> [[SHUF]], zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %y = add nuw <4 x i8> %yy, <i8 1, i8 1, i8 1, i8 0>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> %y, <4 x i32> <i32 0, i32 4, i32 7, i32 2>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_both_fail2(<4 x i8> %xx, <4 x i8> %yy) {
+; CHECK-LABEL: @shuf_nonzero_both_fail2(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[Y:%.*]] = add <4 x i8> [[YY:%.*]], <i8 1, i8 1, i8 1, i8 1>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i8> [[X]], <4 x i8> [[Y]], <4 x i32> <i32 0, i32 4, i32 7, i32 2>
+; CHECK-NEXT: [[R:%.*]] = icmp eq <4 x i8> [[SHUF]], zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+ %y = add <4 x i8> %yy, <i8 1, i8 1, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> %y, <4 x i32> <i32 0, i32 4, i32 7, i32 2>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_lhs(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_lhs(
+; CHECK-NEXT: ret <4 x i1> zeroinitializer
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> poison, <4 x i32> <i32 2, i32 2, i32 0, i32 1>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_lhs2(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_lhs2(
+; CHECK-NEXT: ret <4 x i1> zeroinitializer
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 0>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> poison, <4 x i32> <i32 2, i32 0, i32 1, i32 1>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_lhs2_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_lhs2_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 1, i8 1, i8 1, i8 0>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i8> [[X]], <4 x i8> poison, <4 x i32> <i32 2, i32 0, i32 3, i32 1>
+; CHECK-NEXT: [[R:%.*]] = icmp eq <4 x i8> [[SHUF]], zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 0>
+
+ %shuf = shufflevector <4 x i8> %x, <4 x i8> poison, <4 x i32> <i32 2, i32 0, i32 3, i32 1>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_rhs(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_rhs(
+; CHECK-NEXT: ret <4 x i1> zeroinitializer
+;
+ %x = add nuw <4 x i8> %xx, <i8 1, i8 1, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> poison, <4 x i8> %x, <4 x i32> <i32 6, i32 7, i32 5, i32 4>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_rhs2(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_rhs2(
+; CHECK-NEXT: ret <4 x i1> zeroinitializer
+;
+ %x = add nuw <4 x i8> %xx, <i8 0, i8 0, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> poison, <4 x i8> %x, <4 x i32> <i32 6, i32 7, i32 7, i32 6>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <4 x i1> @shuf_nonzero_rhs2_fail(<4 x i8> %xx) {
+; CHECK-LABEL: @shuf_nonzero_rhs2_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <4 x i8> [[XX:%.*]], <i8 0, i8 0, i8 1, i8 1>
+; CHECK-NEXT: [[SHUF:%.*]] = shufflevector <4 x i8> poison, <4 x i8> [[X]], <4 x i32> <i32 6, i32 7, i32 5, i32 6>
+; CHECK-NEXT: [[R:%.*]] = icmp eq <4 x i8> [[SHUF]], zeroinitializer
+; CHECK-NEXT: ret <4 x i1> [[R]]
+;
+ %x = add nuw <4 x i8> %xx, <i8 0, i8 0, i8 1, i8 1>
+
+ %shuf = shufflevector <4 x i8> poison, <4 x i8> %x, <4 x i32> <i32 6, i32 7, i32 5, i32 6>
+ %r = icmp eq <4 x i8> %shuf, zeroinitializer
+ ret <4 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero0(<2 x i8> %xx, i8 %yy) {
+; CHECK-LABEL: @insert_nonzero0(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %x = add nuw <2 x i8> %xx, <i8 1, i8 0>
+ %y = add nuw i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 1
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero1(<2 x i8> %xx, i8 %yy) {
+; CHECK-LABEL: @insert_nonzero1(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %x = add nuw <2 x i8> %xx, <i8 0, i8 1>
+ %y = add nuw i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 0
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero_fail(<2 x i8> %xx, i8 %yy) {
+; CHECK-LABEL: @insert_nonzero_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[XX:%.*]], <i8 1, i8 0>
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[INS:%.*]] = insertelement <2 x i8> [[X]], i8 [[Y]], i32 0
+; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[INS]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[R]]
+;
+ %x = add nuw <2 x i8> %xx, <i8 1, i8 0>
+ %y = add nuw i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 0
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero_fail2(<2 x i8> %xx, i8 %yy) {
+; CHECK-LABEL: @insert_nonzero_fail2(
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[XX:%.*]], <i8 0, i8 1>
+; CHECK-NEXT: [[Y:%.*]] = add i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[INS:%.*]] = insertelement <2 x i8> [[X]], i8 [[Y]], i32 0
+; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[INS]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[R]]
+;
+ %x = add nuw <2 x i8> %xx, <i8 0, i8 1>
+ %y = add i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 0
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero_any_idx(<2 x i8> %xx, i8 %yy, i32 %idx) {
+; CHECK-LABEL: @insert_nonzero_any_idx(
+; CHECK-NEXT: ret <2 x i1> zeroinitializer
+;
+ %x = add nuw <2 x i8> %xx, <i8 1, i8 1>
+ %y = add nuw i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 %idx
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
+
+define <2 x i1> @insert_nonzero_any_idx_fail(<2 x i8> %xx, i8 %yy, i32 %idx) {
+; CHECK-LABEL: @insert_nonzero_any_idx_fail(
+; CHECK-NEXT: [[X:%.*]] = add nuw <2 x i8> [[XX:%.*]], <i8 1, i8 0>
+; CHECK-NEXT: [[Y:%.*]] = add nuw i8 [[YY:%.*]], 1
+; CHECK-NEXT: [[INS:%.*]] = insertelement <2 x i8> [[X]], i8 [[Y]], i32 [[IDX:%.*]]
+; CHECK-NEXT: [[R:%.*]] = icmp eq <2 x i8> [[INS]], zeroinitializer
+; CHECK-NEXT: ret <2 x i1> [[R]]
+;
+ %x = add nuw <2 x i8> %xx, <i8 1, i8 0>
+ %y = add nuw i8 %yy, 1
+
+ %ins = insertelement <2 x i8> %x, i8 %y, i32 %idx
+ %r = icmp eq <2 x i8> %ins, zeroinitializer
+ ret <2 x i1> %r
+}
diff --git a/llvm/test/Transforms/LoopVectorize/AArch64/veclib-function-calls.ll b/llvm/test/Transforms/LoopVectorize/AArch64/veclib-function-calls.ll
index dd1495626eb9..d9cc630482fc 100644
--- a/llvm/test/Transforms/LoopVectorize/AArch64/veclib-function-calls.ll
+++ b/llvm/test/Transforms/LoopVectorize/AArch64/veclib-function-calls.ll
@@ -2925,11 +2925,12 @@ define void @modf_f64(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @modf_f64
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: [[DATA:%.*]] = call double @modf(double [[NUM:%.*]], ptr [[GEPB:%.*]]) #[[ATTR4:[0-9]+]]
+; ARMPL-SVE: [[TMP23:%.*]] = call <vscale x 2 x double> @armpl_svmodf_f64_x(<vscale x 2 x double> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP22:%.*]], <vscale x 2 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @modf_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: [[TMP5:%.*]] = call <2 x double> @armpl_vmodfq_f64(<2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP4:%.*]])
+; ARMPL-SVE-NOPRED: [[TMP17:%.*]] = call <vscale x 2 x double> @armpl_svmodf_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP16:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: [[DATA:%.*]] = call double @modf(double [[NUM:%.*]], ptr [[GEPB:%.*]]) #[[ATTR64:[0-9]+]]
;
entry:
br label %for.body
@@ -2970,11 +2971,12 @@ define void @modf_f32(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @modf_f32
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: [[DATA:%.*]] = call float @modff(float [[NUM:%.*]], ptr [[GEPB:%.*]]) #[[ATTR5:[0-9]+]]
+; ARMPL-SVE: [[TMP23:%.*]] = call <vscale x 4 x float> @armpl_svmodf_f32_x(<vscale x 4 x float> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP22:%.*]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @modf_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: [[TMP5:%.*]] = call <4 x float> @armpl_vmodfq_f32(<4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP4:%.*]])
+; ARMPL-SVE-NOPRED: [[TMP17:%.*]] = call <vscale x 4 x float> @armpl_svmodf_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP16:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: [[DATA:%.*]] = call float @modff(float [[NUM:%.*]], ptr [[GEPB:%.*]]) #[[ATTR65:[0-9]+]]
;
entry:
br label %for.body
@@ -3023,7 +3025,7 @@ define void @nextafter_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @nextafter_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svnextafter_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x double> [[WIDE_LOAD]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @nextafter(double [[IN:%.*]], double [[IN]]) #[[ATTR64:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @nextafter(double [[IN:%.*]], double [[IN]]) #[[ATTR66:[0-9]+]]
;
entry:
br label %for.body
@@ -3068,7 +3070,7 @@ define void @nextafter_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @nextafter_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svnextafter_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x float> [[WIDE_LOAD]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @nextafterf(float [[IN:%.*]], float [[IN]]) #[[ATTR65:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @nextafterf(float [[IN:%.*]], float [[IN]]) #[[ATTR67:[0-9]+]]
;
entry:
br label %for.body
@@ -3116,7 +3118,7 @@ define void @pow_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @pow_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svpow_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x double> [[WIDE_LOAD]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @pow(double [[IN:%.*]], double [[IN]]) #[[ATTR66:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @pow(double [[IN:%.*]], double [[IN]]) #[[ATTR68:[0-9]+]]
;
entry:
br label %for.body
@@ -3161,7 +3163,7 @@ define void @pow_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @pow_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svpow_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x float> [[WIDE_LOAD]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @powf(float [[IN:%.*]], float [[IN]]) #[[ATTR67:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @powf(float [[IN:%.*]], float [[IN]]) #[[ATTR69:[0-9]+]]
;
entry:
br label %for.body
@@ -3209,7 +3211,7 @@ define void @sin_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sin_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svsin_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sin(double [[IN:%.*]]) #[[ATTR68:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sin(double [[IN:%.*]]) #[[ATTR70:[0-9]+]]
;
entry:
br label %for.body
@@ -3254,7 +3256,7 @@ define void @sin_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sin_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svsin_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinf(float [[IN:%.*]]) #[[ATTR69:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinf(float [[IN:%.*]]) #[[ATTR71:[0-9]+]]
;
entry:
br label %for.body
@@ -3297,11 +3299,12 @@ define void @sincos_f64(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @sincos_f64
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: call void @sincos(double [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR6:[0-9]+]]
+; ARMPL-SVE: call void @armpl_svsincos_f64_x(<vscale x 2 x double> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP23:%.*]], ptr [[TMP24:%.*]], <vscale x 2 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @sincos_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: call void @armpl_vsincosq_f64(<2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]])
+; ARMPL-SVE-NOPRED: call void @armpl_svsincos_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP17:%.*]], ptr [[TMP18:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: call void @sincos(double [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR72:[0-9]+]]
;
entry:
br label %for.body
@@ -3341,11 +3344,12 @@ define void @sincos_f32(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @sincos_f32
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: call void @sincosf(float [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR7:[0-9]+]]
+; ARMPL-SVE: call void @armpl_svsincos_f32_x(<vscale x 4 x float> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP23:%.*]], ptr [[TMP24:%.*]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @sincos_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: call void @armpl_vsincosq_f32(<4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]])
+; ARMPL-SVE-NOPRED: call void @armpl_svsincos_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP17:%.*]], ptr [[TMP18:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: call void @sincosf(float [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR73:[0-9]+]]
;
entry:
br label %for.body
@@ -3388,11 +3392,12 @@ define void @sincospi_f64(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @sincospi_f64
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: call void @sincospi(double [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR8:[0-9]+]]
+; ARMPL-SVE: call void @armpl_svsincospi_f64_x(<vscale x 2 x double> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP23:%.*]], ptr [[TMP24:%.*]], <vscale x 2 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @sincospi_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: call void @armpl_vsincospiq_f64(<2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]])
+; ARMPL-SVE-NOPRED: call void @armpl_svsincospi_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], ptr [[TMP17:%.*]], ptr [[TMP18:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: call void @sincospi(double [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR74:[0-9]+]]
;
entry:
br label %for.body
@@ -3432,11 +3437,12 @@ define void @sincospi_f32(ptr noalias %a, ptr noalias %b, ptr noalias %c) {
;
; ARMPL-SVE-LABEL: define void @sincospi_f32
; ARMPL-SVE-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE: call void @sincospif(float [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR9:[0-9]+]]
+; ARMPL-SVE: call void @armpl_svsincospi_f32_x(<vscale x 4 x float> [[WIDE_MASKED_LOAD:%.*]], ptr [[TMP23:%.*]], ptr [[TMP24:%.*]], <vscale x 4 x i1> [[ACTIVE_LANE_MASK:%.*]])
;
; ARMPL-SVE-NOPRED-LABEL: define void @sincospi_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]]) #[[ATTR0]] {
-; ARMPL-SVE-NOPRED: call void @armpl_vsincospiq_f32(<4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP5:%.*]], ptr [[TMP6:%.*]])
+; ARMPL-SVE-NOPRED: call void @armpl_svsincospi_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], ptr [[TMP17:%.*]], ptr [[TMP18:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
+; ARMPL-SVE-NOPRED: call void @sincospif(float [[NUM:%.*]], ptr [[GEPB:%.*]], ptr [[GEPC:%.*]]) #[[ATTR75:[0-9]+]]
;
entry:
br label %for.body
@@ -3484,7 +3490,7 @@ define void @sinh_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sinh_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svsinh_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sinh(double [[IN:%.*]]) #[[ATTR70:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sinh(double [[IN:%.*]]) #[[ATTR76:[0-9]+]]
;
entry:
br label %for.body
@@ -3529,7 +3535,7 @@ define void @sinh_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sinh_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svsinh_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinhf(float [[IN:%.*]]) #[[ATTR71:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinhf(float [[IN:%.*]]) #[[ATTR77:[0-9]+]]
;
entry:
br label %for.body
@@ -3577,7 +3583,7 @@ define void @sinpi_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sinpi_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svsinpi_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sinpi(double [[IN:%.*]]) #[[ATTR72:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sinpi(double [[IN:%.*]]) #[[ATTR78:[0-9]+]]
;
entry:
br label %for.body
@@ -3622,7 +3628,7 @@ define void @sinpi_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sinpi_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svsinpi_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinpif(float [[IN:%.*]]) #[[ATTR73:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sinpif(float [[IN:%.*]]) #[[ATTR79:[0-9]+]]
;
entry:
br label %for.body
@@ -3670,7 +3676,7 @@ define void @sqrt_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sqrt_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svsqrt_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sqrt(double [[IN:%.*]]) #[[ATTR74:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @sqrt(double [[IN:%.*]]) #[[ATTR80:[0-9]+]]
;
entry:
br label %for.body
@@ -3715,7 +3721,7 @@ define void @sqrt_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @sqrt_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svsqrt_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sqrtf(float [[IN:%.*]]) #[[ATTR75:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @sqrtf(float [[IN:%.*]]) #[[ATTR81:[0-9]+]]
;
entry:
br label %for.body
@@ -3763,7 +3769,7 @@ define void @tan_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tan_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svtan_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tan(double [[IN:%.*]]) #[[ATTR76:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tan(double [[IN:%.*]]) #[[ATTR82:[0-9]+]]
;
entry:
br label %for.body
@@ -3808,7 +3814,7 @@ define void @tan_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tan_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svtan_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tanf(float [[IN:%.*]]) #[[ATTR77:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tanf(float [[IN:%.*]]) #[[ATTR83:[0-9]+]]
;
entry:
br label %for.body
@@ -3856,7 +3862,7 @@ define void @tanh_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tanh_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svtanh_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tanh(double [[IN:%.*]]) #[[ATTR78:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tanh(double [[IN:%.*]]) #[[ATTR84:[0-9]+]]
;
entry:
br label %for.body
@@ -3901,7 +3907,7 @@ define void @tanh_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tanh_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svtanh_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tanhf(float [[IN:%.*]]) #[[ATTR79:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tanhf(float [[IN:%.*]]) #[[ATTR85:[0-9]+]]
;
entry:
br label %for.body
@@ -3949,7 +3955,7 @@ define void @tgamma_f64(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tgamma_f64
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 2 x double> @armpl_svtgamma_f64_x(<vscale x 2 x double> [[WIDE_LOAD:%.*]], <vscale x 2 x i1> shufflevector (<vscale x 2 x i1> insertelement (<vscale x 2 x i1> poison, i1 true, i64 0), <vscale x 2 x i1> poison, <vscale x 2 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tgamma(double [[IN:%.*]]) #[[ATTR80:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call double @tgamma(double [[IN:%.*]]) #[[ATTR86:[0-9]+]]
;
entry:
br label %for.body
@@ -3994,7 +4000,7 @@ define void @tgamma_f32(ptr noalias %in.ptr, ptr noalias %out.ptr) {
; ARMPL-SVE-NOPRED-LABEL: define void @tgamma_f32
; ARMPL-SVE-NOPRED-SAME: (ptr noalias [[IN_PTR:%.*]], ptr noalias [[OUT_PTR:%.*]]) #[[ATTR0]] {
; ARMPL-SVE-NOPRED: [[TMP9:%.*]] = call <vscale x 4 x float> @armpl_svtgamma_f32_x(<vscale x 4 x float> [[WIDE_LOAD:%.*]], <vscale x 4 x i1> shufflevector (<vscale x 4 x i1> insertelement (<vscale x 4 x i1> poison, i1 true, i64 0), <vscale x 4 x i1> poison, <vscale x 4 x i32> zeroinitializer))
-; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tgammaf(float [[IN:%.*]]) #[[ATTR81:[0-9]+]]
+; ARMPL-SVE-NOPRED: [[CALL:%.*]] = tail call float @tgammaf(float [[IN:%.*]]) #[[ATTR87:[0-9]+]]
;
entry:
br label %for.body
diff --git a/llvm/test/Transforms/PhaseOrdering/AArch64/hoist-runtime-checks.ll b/llvm/test/Transforms/PhaseOrdering/AArch64/hoist-runtime-checks.ll
index c6c9a52167d5..a140e17a0dd1 100644
--- a/llvm/test/Transforms/PhaseOrdering/AArch64/hoist-runtime-checks.ll
+++ b/llvm/test/Transforms/PhaseOrdering/AArch64/hoist-runtime-checks.ll
@@ -91,8 +91,151 @@ for.end: ; preds = %for.cond.cleanup
ret i32 %9
}
+%"class.std::__1::span" = type { ptr, i64 }
+%"class.std::__1::__wrap_iter" = type { ptr }
+
+define dso_local noundef i32 @sum_prefix_with_sum(ptr %s.coerce0, i64 %s.coerce1, i64 noundef %n) {
+; CHECK-LABEL: define dso_local noundef i32 @sum_prefix_with_sum(
+; CHECK-SAME: ptr nocapture readonly [[S_COERCE0:%.*]], i64 [[S_COERCE1:%.*]], i64 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i64 [[N]], 0
+; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]]
+; CHECK: for.body.preheader:
+; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N]], -1
+; CHECK-NEXT: [[DOTNOT_NOT:%.*]] = icmp ult i64 [[TMP0]], [[S_COERCE1]]
+; CHECK-NEXT: br label [[FOR_BODY:%.*]]
+; CHECK: for.cond.cleanup:
+; CHECK-NEXT: [[RET_0_LCSSA:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[ADD:%.*]], [[SPAN_CHECKED_ACCESS_EXIT:%.*]] ]
+; CHECK-NEXT: ret i32 [[RET_0_LCSSA]]
+; CHECK: for.body:
+; CHECK-NEXT: [[I_07:%.*]] = phi i64 [ [[INC:%.*]], [[SPAN_CHECKED_ACCESS_EXIT]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
+; CHECK-NEXT: [[RET_06:%.*]] = phi i32 [ [[ADD]], [[SPAN_CHECKED_ACCESS_EXIT]] ], [ 0, [[FOR_BODY_PREHEADER]] ]
+; CHECK-NEXT: br i1 [[DOTNOT_NOT]], label [[SPAN_CHECKED_ACCESS_EXIT]], label [[COND_FALSE_I:%.*]], !prof [[PROF0:![0-9]+]]
+; CHECK: cond.false.i:
+; CHECK-NEXT: tail call void @llvm.trap()
+; CHECK-NEXT: unreachable
+; CHECK: span_checked_access.exit:
+; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds i32, ptr [[S_COERCE0]], i64 [[I_07]]
+; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[ARRAYIDX_I]], align 4
+; CHECK-NEXT: [[ADD]] = add nsw i32 [[TMP7]], [[RET_06]]
+; CHECK-NEXT: [[INC]] = add nuw i64 [[I_07]], 1
+; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INC]], [[N]]
+; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY]]
+;
+entry:
+ %s = alloca %"class.std::__1::span", align 8
+ %n.addr = alloca i64, align 8
+ %ret = alloca i32, align 4
+ %i = alloca i64, align 8
+ %0 = getelementptr inbounds { ptr, i64 }, ptr %s, i32 0, i32 0
+ store ptr %s.coerce0, ptr %0, align 8
+ %1 = getelementptr inbounds { ptr, i64 }, ptr %s, i32 0, i32 1
+ store i64 %s.coerce1, ptr %1, align 8
+ store i64 %n, ptr %n.addr, align 8
+ call void @llvm.lifetime.start.p0(i64 4, ptr %ret) #7
+ store i32 0, ptr %ret, align 4
+ call void @llvm.lifetime.start.p0(i64 8, ptr %i) #7
+ store i64 0, ptr %i, align 8
+ br label %for.cond
+
+for.cond: ; preds = %for.inc, %entry
+ %2 = load i64, ptr %i, align 8
+ %3 = load i64, ptr %n.addr, align 8
+ %cmp = icmp ult i64 %2, %3
+ br i1 %cmp, label %for.body, label %for.cond.cleanup
+
+for.cond.cleanup: ; preds = %for.cond
+ call void @llvm.lifetime.end.p0(i64 8, ptr %i) #7
+ br label %for.end
+
+for.body: ; preds = %for.cond
+ %4 = load i64, ptr %i, align 8
+ %call = call noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access(ptr noundef nonnull align 8 dereferenceable(16) %s, i64 noundef %4) #7
+ %5 = load i32, ptr %call, align 4
+ %6 = load i32, ptr %ret, align 4
+ %add = add nsw i32 %6, %5
+ store i32 %add, ptr %ret, align 4
+ br label %for.inc
+
+for.inc: ; preds = %for.body
+ %7 = load i64, ptr %i, align 8
+ %inc = add i64 %7, 1
+ store i64 %inc, ptr %i, align 8
+ br label %for.cond
+
+for.end: ; preds = %for.cond.cleanup
+ %8 = load i32, ptr %ret, align 4
+ call void @llvm.lifetime.end.p0(i64 4, ptr %ret)
+ ret i32 %8
+}
+
+define hidden noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access(ptr noundef nonnull align 8 dereferenceable(16) %this, i64 noundef %__idx) {
+; CHECK-LABEL: define hidden noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access(
+; CHECK-SAME: ptr nocapture noundef nonnull readonly align 8 dereferenceable(16) [[THIS:%.*]], i64 noundef [[__IDX:%.*]]) local_unnamed_addr #[[ATTR0]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[__SIZE__I:%.*]] = getelementptr inbounds i8, ptr [[THIS]], i64 8
+; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[__SIZE__I]], align 8
+; CHECK-NEXT: [[CMP:%.*]] = icmp ugt i64 [[TMP0]], [[__IDX]]
+; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]], !prof [[PROF0]]
+; CHECK: cond.false:
+; CHECK-NEXT: tail call void @llvm.trap()
+; CHECK-NEXT: unreachable
+; CHECK: cond.end:
+; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[THIS]], align 8
+; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[__IDX]]
+; CHECK-NEXT: ret ptr [[ARRAYIDX]]
+;
+entry:
+ %this.addr = alloca ptr, align 8
+ %__idx.addr = alloca i64, align 8
+ store ptr %this, ptr %this.addr, align 8
+ store i64 %__idx, ptr %__idx.addr, align 8
+ %this1 = load ptr, ptr %this.addr, align 8
+ %0 = load i64, ptr %__idx.addr, align 8
+ %call = call noundef i64 @span_access(ptr noundef nonnull align 8 dereferenceable(16) %this1)
+ %cmp = icmp ult i64 %0, %call
+ %conv = zext i1 %cmp to i64
+ %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1)
+ %tobool = icmp ne i64 %expval, 0
+ br i1 %tobool, label %cond.true, label %cond.false
+
+cond.true: ; preds = %entry
+ br label %cond.end
+
+cond.false: ; preds = %entry
+ call void @llvm.trap()
+ br label %cond.end
+
+cond.end: ; preds = %cond.false, %cond.true
+ %__data_ = getelementptr inbounds %"class.std::__1::span", ptr %this1, i32 0, i32 0
+ %1 = load ptr, ptr %__data_, align 8
+ %2 = load i64, ptr %__idx.addr, align 8
+ %arrayidx = getelementptr inbounds i32, ptr %1, i64 %2
+ ret ptr %arrayidx
+}
+
+define hidden noundef i64 @span_access(ptr noundef nonnull align 8 dereferenceable(16) %this) {
+; CHECK-LABEL: define hidden noundef i64 @span_access(
+; CHECK-SAME: ptr nocapture noundef nonnull readonly align 8 dereferenceable(16) [[THIS:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] {
+; CHECK-NEXT: entry:
+; CHECK-NEXT: [[__SIZE_:%.*]] = getelementptr inbounds i8, ptr [[THIS]], i64 8
+; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[__SIZE_]], align 8
+; CHECK-NEXT: ret i64 [[TMP0]]
+;
+entry:
+ %this.addr = alloca ptr, align 8
+ store ptr %this, ptr %this.addr, align 8
+ %this1 = load ptr, ptr %this.addr, align 8
+ %__size_ = getelementptr inbounds %"class.std::__1::span", ptr %this1, i32 0, i32 1
+ %0 = load i64, ptr %__size_, align 8
+ ret i64 %0
+}
+
declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture)
declare void @llvm.trap()
declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture)
+;.
+; CHECK: [[PROF0]] = !{!"branch_weights", i32 2000, i32 1}
+;.
diff --git a/llvm/test/Transforms/SLPVectorizer/AArch64/extractelements-to-shuffle.ll b/llvm/test/Transforms/SLPVectorizer/AArch64/extractelements-to-shuffle.ll
index d2711d0546c0..283cc07dfb9b 100644
--- a/llvm/test/Transforms/SLPVectorizer/AArch64/extractelements-to-shuffle.ll
+++ b/llvm/test/Transforms/SLPVectorizer/AArch64/extractelements-to-shuffle.ll
@@ -104,16 +104,16 @@ define void @dist_vec(ptr nocapture noundef readonly %pA, ptr nocapture noundef
; CHECK-NEXT: [[AND95:%.*]] = and i32 [[B_0278]], 1
; CHECK-NEXT: [[SHR96]] = lshr i32 [[A_0279]], 1
; CHECK-NEXT: [[SHR97]] = lshr i32 [[B_0278]], 1
-; CHECK-NEXT: [[TMP22:%.*]] = insertelement <2 x i32> poison, i32 [[AND94]], i32 0
-; CHECK-NEXT: [[TMP23:%.*]] = shufflevector <2 x i32> [[TMP22]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP24:%.*]] = icmp eq <2 x i32> [[TMP23]], zeroinitializer
-; CHECK-NEXT: [[TMP25:%.*]] = icmp ne <2 x i32> [[TMP23]], zeroinitializer
-; CHECK-NEXT: [[TMP26:%.*]] = shufflevector <2 x i1> [[TMP24]], <2 x i1> [[TMP25]], <4 x i32> <i32 0, i32 3, i32 0, i32 3>
-; CHECK-NEXT: [[TMP27:%.*]] = insertelement <2 x i32> poison, i32 [[AND95]], i32 0
-; CHECK-NEXT: [[TMP28:%.*]] = shufflevector <2 x i32> [[TMP27]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP29:%.*]] = icmp ne <2 x i32> [[TMP28]], zeroinitializer
-; CHECK-NEXT: [[TMP30:%.*]] = icmp eq <2 x i32> [[TMP28]], zeroinitializer
-; CHECK-NEXT: [[TMP31:%.*]] = shufflevector <2 x i1> [[TMP29]], <2 x i1> [[TMP30]], <4 x i32> <i32 0, i32 3, i32 3, i32 0>
+; CHECK-NEXT: [[TOBOOL:%.*]] = icmp ne i32 [[AND94]], 0
+; CHECK-NEXT: [[TOBOOL98:%.*]] = icmp ne i32 [[AND95]], 0
+; CHECK-NEXT: [[TOBOOL100:%.*]] = icmp eq i32 [[AND94]], 0
+; CHECK-NEXT: [[TOBOOL103:%.*]] = icmp eq i32 [[AND95]], 0
+; CHECK-NEXT: [[TMP22:%.*]] = insertelement <4 x i1> poison, i1 [[TOBOOL100]], i32 0
+; CHECK-NEXT: [[TMP23:%.*]] = insertelement <4 x i1> [[TMP22]], i1 [[TOBOOL]], i32 1
+; CHECK-NEXT: [[TMP26:%.*]] = shufflevector <4 x i1> [[TMP23]], <4 x i1> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP25:%.*]] = insertelement <4 x i1> poison, i1 [[TOBOOL98]], i32 0
+; CHECK-NEXT: [[TMP27:%.*]] = insertelement <4 x i1> [[TMP25]], i1 [[TOBOOL103]], i32 1
+; CHECK-NEXT: [[TMP31:%.*]] = shufflevector <4 x i1> [[TMP27]], <4 x i1> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
; CHECK-NEXT: [[TMP32:%.*]] = select <4 x i1> [[TMP26]], <4 x i1> [[TMP31]], <4 x i1> zeroinitializer
; CHECK-NEXT: [[TMP33:%.*]] = zext <4 x i1> [[TMP32]] to <4 x i32>
; CHECK-NEXT: [[TMP34]] = add <4 x i32> [[TMP21]], [[TMP33]]
@@ -149,16 +149,16 @@ define void @dist_vec(ptr nocapture noundef readonly %pA, ptr nocapture noundef
; CHECK-NEXT: [[AND134:%.*]] = and i32 [[B_1300]], 1
; CHECK-NEXT: [[SHR135]] = lshr i32 [[A_1301]], 1
; CHECK-NEXT: [[SHR136]] = lshr i32 [[B_1300]], 1
-; CHECK-NEXT: [[TMP39:%.*]] = insertelement <2 x i32> poison, i32 [[AND133]], i32 0
-; CHECK-NEXT: [[TMP40:%.*]] = shufflevector <2 x i32> [[TMP39]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP41:%.*]] = icmp eq <2 x i32> [[TMP40]], zeroinitializer
-; CHECK-NEXT: [[TMP42:%.*]] = icmp ne <2 x i32> [[TMP40]], zeroinitializer
-; CHECK-NEXT: [[TMP43:%.*]] = shufflevector <2 x i1> [[TMP41]], <2 x i1> [[TMP42]], <4 x i32> <i32 0, i32 3, i32 0, i32 3>
-; CHECK-NEXT: [[TMP44:%.*]] = insertelement <2 x i32> poison, i32 [[AND134]], i32 0
-; CHECK-NEXT: [[TMP45:%.*]] = shufflevector <2 x i32> [[TMP44]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP46:%.*]] = icmp ne <2 x i32> [[TMP45]], zeroinitializer
-; CHECK-NEXT: [[TMP47:%.*]] = icmp eq <2 x i32> [[TMP45]], zeroinitializer
-; CHECK-NEXT: [[TMP48:%.*]] = shufflevector <2 x i1> [[TMP46]], <2 x i1> [[TMP47]], <4 x i32> <i32 0, i32 3, i32 3, i32 0>
+; CHECK-NEXT: [[TOBOOL137:%.*]] = icmp ne i32 [[AND133]], 0
+; CHECK-NEXT: [[TOBOOL139:%.*]] = icmp ne i32 [[AND134]], 0
+; CHECK-NEXT: [[TOBOOL144:%.*]] = icmp eq i32 [[AND133]], 0
+; CHECK-NEXT: [[TOBOOL147:%.*]] = icmp eq i32 [[AND134]], 0
+; CHECK-NEXT: [[TMP40:%.*]] = insertelement <4 x i1> poison, i1 [[TOBOOL144]], i32 0
+; CHECK-NEXT: [[TMP41:%.*]] = insertelement <4 x i1> [[TMP40]], i1 [[TOBOOL137]], i32 1
+; CHECK-NEXT: [[TMP43:%.*]] = shufflevector <4 x i1> [[TMP41]], <4 x i1> poison, <4 x i32> <i32 0, i32 1, i32 0, i32 1>
+; CHECK-NEXT: [[TMP42:%.*]] = insertelement <4 x i1> poison, i1 [[TOBOOL139]], i32 0
+; CHECK-NEXT: [[TMP39:%.*]] = insertelement <4 x i1> [[TMP42]], i1 [[TOBOOL147]], i32 1
+; CHECK-NEXT: [[TMP48:%.*]] = shufflevector <4 x i1> [[TMP39]], <4 x i1> poison, <4 x i32> <i32 0, i32 1, i32 1, i32 0>
; CHECK-NEXT: [[TMP49:%.*]] = select <4 x i1> [[TMP43]], <4 x i1> [[TMP48]], <4 x i1> zeroinitializer
; CHECK-NEXT: [[TMP50:%.*]] = zext <4 x i1> [[TMP49]] to <4 x i32>
; CHECK-NEXT: [[TMP51]] = add <4 x i32> [[TMP38]], [[TMP50]]
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/ext-int-reduced-not-operand.ll b/llvm/test/Transforms/SLPVectorizer/X86/ext-int-reduced-not-operand.ll
index 05534fa961ee..b76e26e0fd57 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/ext-int-reduced-not-operand.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/ext-int-reduced-not-operand.ll
@@ -9,13 +9,8 @@ define i64 @wombat() {
; CHECK-NEXT: br label [[BB2]]
; CHECK: bb2:
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ 0, [[BB:%.*]] ], [ 0, [[BB1:%.*]] ]
-; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> poison, i32 [[PHI]], i32 0
-; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x i32> [[TMP0]], <2 x i32> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP2:%.*]] = trunc <2 x i32> [[TMP1]] to <2 x i1>
-; CHECK-NEXT: [[TMP3:%.*]] = extractelement <2 x i1> [[TMP2]], i32 0
-; CHECK-NEXT: [[TMP4:%.*]] = zext i1 [[TMP3]] to i64
-; CHECK-NEXT: [[TMP5:%.*]] = extractelement <2 x i1> [[TMP2]], i32 1
-; CHECK-NEXT: [[TMP6:%.*]] = zext i1 [[TMP5]] to i64
+; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[PHI]] to i64
+; CHECK-NEXT: [[TMP6:%.*]] = sext i32 [[PHI]] to i64
; CHECK-NEXT: [[OR:%.*]] = or i64 [[TMP4]], [[TMP6]]
; CHECK-NEXT: ret i64 [[OR]]
;
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/extractlements-gathered-first-node.ll b/llvm/test/Transforms/SLPVectorizer/X86/extractlements-gathered-first-node.ll
new file mode 100644
index 000000000000..57fa83b1ccdd
--- /dev/null
+++ b/llvm/test/Transforms/SLPVectorizer/X86/extractlements-gathered-first-node.ll
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
+; RUN: opt -S --passes=slp-vectorizer -slp-threshold=-99999 -mtriple=x86_64-unknown-linux-gnu < %s | FileCheck %s
+
+define void @test() {
+; CHECK-LABEL: define void @test() {
+; CHECK-NEXT: bb:
+; CHECK-NEXT: [[TMP0:%.*]] = extractelement <4 x i32> zeroinitializer, i32 0
+; CHECK-NEXT: [[TMP1:%.*]] = extractelement <2 x i32> zeroinitializer, i32 0
+; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i32> <i32 0, i32 undef>, i32 [[TMP1]], i32 1
+; CHECK-NEXT: [[ICMP:%.*]] = icmp ult i32 [[TMP0]], [[TMP1]]
+; CHECK-NEXT: ret void
+;
+bb:
+ %0 = extractelement <4 x i32> zeroinitializer, i32 0
+ %1 = extractelement <2 x i32> zeroinitializer, i32 0
+ %icmp = icmp ult i32 %0, %1
+ ret void
+}
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/gather-move-out-of-loop.ll b/llvm/test/Transforms/SLPVectorizer/X86/gather-move-out-of-loop.ll
index 78fc3a60f051..3c3dea3f1ea8 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/gather-move-out-of-loop.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/gather-move-out-of-loop.ll
@@ -4,14 +4,12 @@
define void @test(i16 %0) {
; CHECK-LABEL: @test(
; CHECK-NEXT: for.body92.preheader:
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i16> <i16 0, i16 poison>, i16 [[TMP0:%.*]], i32 1
-; CHECK-NEXT: [[TMP2:%.*]] = sext <2 x i16> [[TMP1]] to <2 x i32>
-; CHECK-NEXT: [[TMP3:%.*]] = zext <2 x i16> [[TMP1]] to <2 x i32>
-; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> [[TMP3]], <2 x i32> <i32 0, i32 3>
-; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> poison, <4 x i32> <i32 0, i32 poison, i32 1, i32 poison>
-; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <4 x i32> <i32 poison, i32 0, i32 poison, i32 0>, <4 x i32> [[TMP5]], <4 x i32> <i32 4, i32 1, i32 6, i32 3>
; CHECK-NEXT: br label [[FOR_BODY92:%.*]]
; CHECK: for.body92:
+; CHECK-NEXT: [[CONV177_I:%.*]] = sext i16 0 to i32
+; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[TMP0:%.*]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = insertelement <4 x i32> <i32 poison, i32 0, i32 poison, i32 0>, i32 [[CONV177_I]], i32 0
+; CHECK-NEXT: [[TMP6:%.*]] = insertelement <4 x i32> [[TMP2]], i32 [[TMP1]], i32 2
; CHECK-NEXT: [[TMP7:%.*]] = add nsw <4 x i32> zeroinitializer, [[TMP6]]
; CHECK-NEXT: store <4 x i32> [[TMP7]], ptr undef, align 8
; CHECK-NEXT: br label [[FOR_BODY92]]
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/gathered-delayed-nodes-with-reused-user.ll b/llvm/test/Transforms/SLPVectorizer/X86/gathered-delayed-nodes-with-reused-user.ll
index 16ede231c200..19a8aa9b6181 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/gathered-delayed-nodes-with-reused-user.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/gathered-delayed-nodes-with-reused-user.ll
@@ -6,21 +6,19 @@ define i64 @foo() {
; CHECK-NEXT: bb:
; CHECK-NEXT: br label [[BB3:%.*]]
; CHECK: bb1:
-; CHECK-NEXT: [[TMP0:%.*]] = phi <2 x i64> [ [[TMP5:%.*]], [[BB3]] ]
+; CHECK-NEXT: [[PHI:%.*]] = phi i64 [ [[ADD:%.*]], [[BB3]] ]
+; CHECK-NEXT: [[PHI2:%.*]] = phi i64 [ [[TMP9:%.*]], [[BB3]] ]
; CHECK-NEXT: ret i64 0
; CHECK: bb3:
; CHECK-NEXT: [[PHI5:%.*]] = phi i64 [ 0, [[BB:%.*]] ], [ 0, [[BB3]] ]
; CHECK-NEXT: [[TMP1:%.*]] = phi <2 x i64> [ zeroinitializer, [[BB]] ], [ [[TMP7:%.*]], [[BB3]] ]
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i64> <i64 poison, i64 0>, i64 [[PHI5]], i32 0
-; CHECK-NEXT: [[TMP3:%.*]] = add <2 x i64> [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP4:%.*]] = or <2 x i64> [[TMP1]], [[TMP2]]
-; CHECK-NEXT: [[TMP5]] = shufflevector <2 x i64> [[TMP3]], <2 x i64> [[TMP4]], <2 x i32> <i32 0, i32 3>
-; CHECK-NEXT: [[TMP6:%.*]] = shufflevector <2 x i64> [[TMP1]], <2 x i64> <i64 poison, i64 0>, <2 x i32> <i32 0, i32 3>
-; CHECK-NEXT: [[TMP7]] = add <2 x i64> [[TMP6]], [[TMP2]]
-; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x i64> [[TMP7]], i32 1
-; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr i64, ptr addrspace(1) null, i64 [[TMP8]]
-; CHECK-NEXT: [[TMP9:%.*]] = extractelement <2 x i64> [[TMP5]], i32 1
+; CHECK-NEXT: [[TMP3:%.*]] = extractelement <2 x i64> [[TMP1]], i32 0
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i64> [[TMP1]], i32 1
+; CHECK-NEXT: [[ADD]] = add i64 [[TMP3]], [[TMP2]]
+; CHECK-NEXT: [[GETELEMENTPTR:%.*]] = getelementptr i64, ptr addrspace(1) null, i64 0
+; CHECK-NEXT: [[TMP9]] = or i64 [[PHI5]], 0
; CHECK-NEXT: [[ICMP:%.*]] = icmp ult i64 [[TMP9]], 0
+; CHECK-NEXT: [[TMP7]] = insertelement <2 x i64> <i64 poison, i64 0>, i64 [[ADD]], i32 0
; CHECK-NEXT: br i1 false, label [[BB3]], label [[BB1:%.*]]
;
bb:
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-reused-as-last-inst.ll b/llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-reused-as-last-inst.ll
index 3a9eca2bf2e6..59cd1c0ccddf 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-reused-as-last-inst.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/non-scheduled-inst-reused-as-last-inst.ll
@@ -4,22 +4,22 @@
define void @foo() {
; CHECK-LABEL: define void @foo() {
; CHECK-NEXT: bb:
-; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x i32> <i32 poison, i32 0>, i32 0, i32 0
; CHECK-NEXT: br label [[BB1:%.*]]
; CHECK: bb1:
; CHECK-NEXT: [[TMP1:%.*]] = phi <2 x i32> [ zeroinitializer, [[BB:%.*]] ], [ [[TMP6:%.*]], [[BB4:%.*]] ]
-; CHECK-NEXT: [[TMP2:%.*]] = shl <2 x i32> [[TMP1]], [[TMP0]]
-; CHECK-NEXT: [[TMP3:%.*]] = or <2 x i32> [[TMP1]], [[TMP0]]
-; CHECK-NEXT: [[TMP4:%.*]] = shufflevector <2 x i32> [[TMP2]], <2 x i32> [[TMP3]], <2 x i32> <i32 0, i32 3>
-; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <2 x i32> [[TMP4]], <2 x i32> [[TMP1]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP2:%.*]] = extractelement <2 x i32> [[TMP1]], i32 0
+; CHECK-NEXT: [[SHL:%.*]] = shl i32 [[TMP2]], 0
+; CHECK-NEXT: [[TMP5:%.*]] = insertelement <2 x i32> [[TMP1]], i32 [[SHL]], i32 0
; CHECK-NEXT: [[TMP6]] = or <2 x i32> [[TMP5]], zeroinitializer
; CHECK-NEXT: [[TMP7:%.*]] = extractelement <2 x i32> [[TMP6]], i32 0
; CHECK-NEXT: [[CALL:%.*]] = call i64 null(i32 [[TMP7]])
; CHECK-NEXT: br label [[BB4]]
; CHECK: bb4:
+; CHECK-NEXT: [[TMP8:%.*]] = extractelement <2 x i32> [[TMP6]], i32 1
; CHECK-NEXT: br i1 false, label [[BB5:%.*]], label [[BB1]]
; CHECK: bb5:
-; CHECK-NEXT: [[TMP8:%.*]] = phi <2 x i32> [ [[TMP4]], [[BB4]] ]
+; CHECK-NEXT: [[PHI6:%.*]] = phi i32 [ [[SHL]], [[BB4]] ]
+; CHECK-NEXT: [[PHI7:%.*]] = phi i32 [ [[TMP8]], [[BB4]] ]
; CHECK-NEXT: ret void
;
bb:
diff --git a/llvm/test/Transforms/SLPVectorizer/X86/reorder_with_external_users.ll b/llvm/test/Transforms/SLPVectorizer/X86/reorder_with_external_users.ll
index 09b3d25fd6dc..93258f2975f3 100644
--- a/llvm/test/Transforms/SLPVectorizer/X86/reorder_with_external_users.ll
+++ b/llvm/test/Transforms/SLPVectorizer/X86/reorder_with_external_users.ll
@@ -112,10 +112,10 @@ define void @addsub_and_external_users(ptr %A, ptr %ptr) {
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[LD:%.*]] = load double, ptr undef, align 8
; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x double> poison, double [[LD]], i32 0
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP1:%.*]] = fsub <2 x double> [[SHUFFLE]], <double 1.100000e+00, double 1.200000e+00>
-; CHECK-NEXT: [[TMP2:%.*]] = fadd <2 x double> [[SHUFFLE]], <double 1.100000e+00, double 1.200000e+00>
-; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> [[TMP2]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = fsub <2 x double> [[TMP1]], <double 1.100000e+00, double 1.200000e+00>
+; CHECK-NEXT: [[TMP6:%.*]] = fadd <2 x double> [[TMP1]], <double 1.100000e+00, double 1.200000e+00>
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> [[TMP6]], <2 x i32> <i32 0, i32 3>
; CHECK-NEXT: [[TMP4:%.*]] = fdiv <2 x double> [[TMP3]], <double 2.100000e+00, double 2.200000e+00>
; CHECK-NEXT: [[TMP5:%.*]] = fmul <2 x double> [[TMP4]], <double 3.100000e+00, double 3.200000e+00>
; CHECK-NEXT: [[SHUFFLE1:%.*]] = shufflevector <2 x double> [[TMP5]], <2 x double> poison, <2 x i32> <i32 1, i32 0>
@@ -159,10 +159,10 @@ define void @subadd_and_external_users(ptr %A, ptr %ptr) {
; CHECK-NEXT: bb1:
; CHECK-NEXT: [[LD:%.*]] = load double, ptr undef, align 8
; CHECK-NEXT: [[TMP0:%.*]] = insertelement <2 x double> poison, double [[LD]], i32 0
-; CHECK-NEXT: [[SHUFFLE:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP1:%.*]] = fadd <2 x double> [[SHUFFLE]], <double 1.200000e+00, double 1.100000e+00>
-; CHECK-NEXT: [[TMP2:%.*]] = fsub <2 x double> [[SHUFFLE]], <double 1.200000e+00, double 1.100000e+00>
-; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP1]], <2 x double> [[TMP2]], <2 x i32> <i32 2, i32 1>
+; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <2 x double> [[TMP0]], <2 x double> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT: [[TMP2:%.*]] = fsub <2 x double> [[TMP1]], <double 1.200000e+00, double 1.100000e+00>
+; CHECK-NEXT: [[TMP6:%.*]] = fadd <2 x double> [[TMP1]], <double 1.200000e+00, double 1.100000e+00>
+; CHECK-NEXT: [[TMP3:%.*]] = shufflevector <2 x double> [[TMP2]], <2 x double> [[TMP6]], <2 x i32> <i32 0, i32 3>
; CHECK-NEXT: [[TMP4:%.*]] = fdiv <2 x double> [[TMP3]], <double 2.200000e+00, double 2.100000e+00>
; CHECK-NEXT: [[TMP5:%.*]] = fmul <2 x double> [[TMP4]], <double 3.200000e+00, double 3.100000e+00>
; CHECK-NEXT: store <2 x double> [[TMP5]], ptr [[A:%.*]], align 8
diff --git a/llvm/test/Transforms/SLPVectorizer/alternate-non-profitable.ll b/llvm/test/Transforms/SLPVectorizer/alternate-non-profitable.ll
index c6e2cf5543e1..287b623f6369 100644
--- a/llvm/test/Transforms/SLPVectorizer/alternate-non-profitable.ll
+++ b/llvm/test/Transforms/SLPVectorizer/alternate-non-profitable.ll
@@ -33,11 +33,10 @@ define <2 x float> @replace_through_casts(i16 %inp) {
; CHECK-LABEL: define <2 x float> @replace_through_casts(
; CHECK-SAME: i16 [[INP:%.*]]) {
; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[INP]], -10
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i16> poison, i16 [[INP]], i32 0
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i16> [[TMP1]], i16 [[ADD]], i32 1
-; CHECK-NEXT: [[TMP3:%.*]] = uitofp <2 x i16> [[TMP2]] to <2 x float>
-; CHECK-NEXT: [[TMP4:%.*]] = sitofp <2 x i16> [[TMP2]] to <2 x float>
-; CHECK-NEXT: [[R:%.*]] = shufflevector <2 x float> [[TMP3]], <2 x float> [[TMP4]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = uitofp i16 [[INP]] to float
+; CHECK-NEXT: [[TMP2:%.*]] = sitofp i16 [[ADD]] to float
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x float> poison, float [[TMP1]], i64 0
+; CHECK-NEXT: [[R:%.*]] = insertelement <2 x float> [[TMP3]], float [[TMP2]], i64 1
; CHECK-NEXT: ret <2 x float> [[R]]
;
%add = add nsw i16 %inp, -10
@@ -118,11 +117,10 @@ define <2 x i32> @replace_through_int_casts(i16 %inp, <2 x i16> %dead) {
; CHECK-LABEL: define <2 x i32> @replace_through_int_casts(
; CHECK-SAME: i16 [[INP:%.*]], <2 x i16> [[DEAD:%.*]]) {
; CHECK-NEXT: [[ADD:%.*]] = add nsw i16 [[INP]], -10
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i16> poison, i16 [[INP]], i32 0
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i16> [[TMP1]], i16 [[ADD]], i32 1
-; CHECK-NEXT: [[TMP3:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32>
-; CHECK-NEXT: [[TMP4:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32>
-; CHECK-NEXT: [[R:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> [[TMP4]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = zext i16 [[INP]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = sext i16 [[ADD]] to i32
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x i32> poison, i32 [[TMP1]], i64 0
+; CHECK-NEXT: [[R:%.*]] = insertelement <2 x i32> [[TMP3]], i32 [[TMP2]], i64 1
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%add = add nsw i16 %inp, -10
@@ -136,11 +134,10 @@ define <2 x i32> @replace_through_int_casts(i16 %inp, <2 x i16> %dead) {
define <2 x i32> @replace_through_int_casts_ele0_only(i16 %inp, <2 x i16> %dead) {
; CHECK-LABEL: define <2 x i32> @replace_through_int_casts_ele0_only(
; CHECK-SAME: i16 [[INP:%.*]], <2 x i16> [[DEAD:%.*]]) {
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i16> poison, i16 [[INP]], i32 0
-; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <2 x i16> [[TMP1]], <2 x i16> poison, <2 x i32> zeroinitializer
-; CHECK-NEXT: [[TMP3:%.*]] = zext <2 x i16> [[TMP2]] to <2 x i32>
-; CHECK-NEXT: [[TMP4:%.*]] = sext <2 x i16> [[TMP2]] to <2 x i32>
-; CHECK-NEXT: [[R:%.*]] = shufflevector <2 x i32> [[TMP3]], <2 x i32> [[TMP4]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = sext i16 [[INP]] to i32
+; CHECK-NEXT: [[TMP2:%.*]] = zext i16 [[INP]] to i32
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x i32> poison, i32 [[TMP2]], i64 0
+; CHECK-NEXT: [[R:%.*]] = insertelement <2 x i32> [[TMP3]], i32 [[TMP1]], i64 1
; CHECK-NEXT: ret <2 x i32> [[R]]
;
%2 = sext i16 %inp to i32
@@ -174,11 +171,10 @@ define <2 x i8> @replace_through_binop_preserve_flags(i8 %inp, <2 x i8> %d, <2 x
; CHECK-LABEL: define <2 x i8> @replace_through_binop_preserve_flags(
; CHECK-SAME: i8 [[INP:%.*]], <2 x i8> [[D:%.*]], <2 x i8> [[ANY:%.*]]) {
; CHECK-NEXT: [[ADD:%.*]] = xor i8 [[INP]], 5
-; CHECK-NEXT: [[TMP1:%.*]] = insertelement <2 x i8> poison, i8 [[INP]], i32 0
-; CHECK-NEXT: [[TMP2:%.*]] = insertelement <2 x i8> [[TMP1]], i8 [[ADD]], i32 1
-; CHECK-NEXT: [[TMP3:%.*]] = xor <2 x i8> [[TMP2]], <i8 123, i8 1>
-; CHECK-NEXT: [[TMP4:%.*]] = add nsw <2 x i8> [[TMP2]], <i8 123, i8 1>
-; CHECK-NEXT: [[R:%.*]] = shufflevector <2 x i8> [[TMP3]], <2 x i8> [[TMP4]], <2 x i32> <i32 0, i32 3>
+; CHECK-NEXT: [[TMP1:%.*]] = xor i8 [[INP]], 123
+; CHECK-NEXT: [[TMP2:%.*]] = add nsw i8 [[ADD]], 1
+; CHECK-NEXT: [[TMP3:%.*]] = insertelement <2 x i8> poison, i8 [[TMP1]], i64 0
+; CHECK-NEXT: [[R:%.*]] = insertelement <2 x i8> [[TMP3]], i8 [[TMP2]], i64 1
; CHECK-NEXT: ret <2 x i8> [[R]]
;
%add = xor i8 %inp, 5
diff --git a/llvm/test/Transforms/Util/add-TLI-mappings.ll b/llvm/test/Transforms/Util/add-TLI-mappings.ll
index d86e44f199b3..0e005ae75ef5 100644
--- a/llvm/test/Transforms/Util/add-TLI-mappings.ll
+++ b/llvm/test/Transforms/Util/add-TLI-mappings.ll
@@ -46,15 +46,21 @@
; SLEEFGNUABI-SAME: ptr @_ZGVsNxvl4l4_sincospif,
; SLEEFGNUABI_SAME; ptr @_ZGVnN4v_log10f,
; SLEEFGNUABI-SAME: ptr @_ZGVsMxv_log10f
-; ARMPL-SAME: [10 x ptr] [
+; ARMPL-SAME: [16 x ptr] [
; ARMPL-SAME: ptr @armpl_vmodfq_f64,
+; ARMPL-SAME: ptr @armpl_svmodf_f64_x,
; ARMPL-SAME: ptr @armpl_vmodfq_f32,
+; ARMPL-SAME: ptr @armpl_svmodf_f32_x,
; ARMPL-SAME: ptr @armpl_vsinq_f64,
; ARMPL-SAME: ptr @armpl_svsin_f64_x,
; ARMPL-SAME: ptr @armpl_vsincosq_f64,
+; ARMPL-SAME: ptr @armpl_svsincos_f64_x,
; ARMPL-SAME: ptr @armpl_vsincosq_f32,
+; ARMPL-SAME: ptr @armpl_svsincos_f32_x,
; ARMPL-SAME: ptr @armpl_vsincospiq_f64,
+; ARMPL-SAME: ptr @armpl_svsincospi_f64_x,
; ARMPL-SAME: ptr @armpl_vsincospiq_f32,
+; ARMPL-SAME: ptr @armpl_svsincospi_f32_x,
; ARMPL-SAME: ptr @armpl_vlog10q_f32,
; ARMPL-SAME: ptr @armpl_svlog10_f32_x
; COMMON-SAME: ], section "llvm.metadata"
@@ -195,13 +201,19 @@ declare float @llvm.log10.f32(float) #0
; SLEEFGNUABI: declare <vscale x 4 x float> @_ZGVsMxv_log10f(<vscale x 4 x float>, <vscale x 4 x i1>)
; ARMPL: declare <2 x double> @armpl_vmodfq_f64(<2 x double>, ptr)
+; ARMPL: declare <vscale x 2 x double> @armpl_svmodf_f64_x(<vscale x 2 x double>, ptr, <vscale x 2 x i1>)
; ARMPL: declare <4 x float> @armpl_vmodfq_f32(<4 x float>, ptr)
+; ARMPL: declare <vscale x 4 x float> @armpl_svmodf_f32_x(<vscale x 4 x float>, ptr, <vscale x 4 x i1>)
; ARMPL: declare <2 x double> @armpl_vsinq_f64(<2 x double>)
; ARMPL: declare <vscale x 2 x double> @armpl_svsin_f64_x(<vscale x 2 x double>, <vscale x 2 x i1>)
; ARMPL: declare void @armpl_vsincosq_f64(<2 x double>, ptr, ptr)
+; ARMPL: declare void @armpl_svsincos_f64_x(<vscale x 2 x double>, ptr, ptr, <vscale x 2 x i1>)
; ARMPL: declare void @armpl_vsincosq_f32(<4 x float>, ptr, ptr)
+; ARMPL: declare void @armpl_svsincos_f32_x(<vscale x 4 x float>, ptr, ptr, <vscale x 4 x i1>)
; ARMPL: declare void @armpl_vsincospiq_f64(<2 x double>, ptr, ptr)
+; ARMPL: declare void @armpl_svsincospi_f64_x(<vscale x 2 x double>, ptr, ptr, <vscale x 2 x i1>)
; ARMPL: declare void @armpl_vsincospiq_f32(<4 x float>, ptr, ptr)
+; ARMPL: declare void @armpl_svsincospi_f32_x(<vscale x 4 x float>, ptr, ptr, <vscale x 4 x i1>)
; ARMPL: declare <4 x float> @armpl_vlog10q_f32(<4 x float>)
; ARMPL: declare <vscale x 4 x float> @armpl_svlog10_f32_x(<vscale x 4 x float>, <vscale x 4 x i1>)
@@ -255,20 +267,26 @@ attributes #0 = { nounwind readnone }
; SLEEFGNUABI-SAME: _ZGVsMxv_llvm.log10.f32(_ZGVsMxv_log10f)" }
; ARMPL: attributes #[[MODF]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N2vl8_modf(armpl_vmodfq_f64)" }
+; ARMPL-SAME: "_ZGV_LLVM_N2vl8_modf(armpl_vmodfq_f64),
+; ARMPL-SAME: _ZGVsMxvl8_modf(armpl_svmodf_f64_x)" }
; ARMPL: attributes #[[MODFF]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N4vl4_modff(armpl_vmodfq_f32)" }
+; ARMPL-SAME: "_ZGV_LLVM_N4vl4_modff(armpl_vmodfq_f32),
+; ARMPL-SAME: _ZGVsMxvl4_modff(armpl_svmodf_f32_x)" }
; ARMPL: attributes #[[SIN]] = { "vector-function-abi-variant"=
; ARMPL-SAME: "_ZGV_LLVM_N2v_sin(armpl_vsinq_f64),
; ARMPL-SAME _ZGVsMxv_sin(armpl_svsin_f64_x)" }
; ARMPL: attributes #[[SINCOS]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N2vl8l8_sincos(armpl_vsincosq_f64)" }
+; ARMPL-SAME: "_ZGV_LLVM_N2vl8l8_sincos(armpl_vsincosq_f64),
+; ARMPL-SAME: _ZGVsMxvl8l8_sincos(armpl_svsincos_f64_x)" }
; ARMPL: attributes #[[SINCOSF]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N4vl4l4_sincosf(armpl_vsincosq_f32)" }
+; ARMPL-SAME: "_ZGV_LLVM_N4vl4l4_sincosf(armpl_vsincosq_f32),
+; ARMPL-SAME: _ZGVsMxvl4l4_sincosf(armpl_svsincos_f32_x)" }
; ARMPL: attributes #[[SINCOSPI]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N2vl8l8_sincospi(armpl_vsincospiq_f64)" }
+; ARMPL-SAME: "_ZGV_LLVM_N2vl8l8_sincospi(armpl_vsincospiq_f64),
+; ARMPL-SAME: _ZGVsMxvl8l8_sincospi(armpl_svsincospi_f64_x)" }
; ARMPL: attributes #[[SINCOSPIF]] = { "vector-function-abi-variant"=
-; ARMPL-SAME: "_ZGV_LLVM_N4vl4l4_sincospif(armpl_vsincospiq_f32)" }
+; ARMPL-SAME: "_ZGV_LLVM_N4vl4l4_sincospif(armpl_vsincospiq_f32),
+; ARMPL-SAME: _ZGVsMxvl4l4_sincospif(armpl_svsincospi_f32_x)" }
; ARMPL: attributes #[[LOG10]] = { "vector-function-abi-variant"=
; ARMPL-SAME: "_ZGV_LLVM_N4v_llvm.log10.f32(armpl_vlog10q_f32),
; ARMPL-SAME _ZGVsMxv_llvm.log10.f32(armpl_svlog10_f32_x)" }
diff --git a/llvm/test/Transforms/lower-builtin-allow-check-remarks.ll b/llvm/test/Transforms/lower-builtin-allow-check-remarks.ll
new file mode 100644
index 000000000000..3422ab1b56d3
--- /dev/null
+++ b/llvm/test/Transforms/lower-builtin-allow-check-remarks.ll
@@ -0,0 +1,24 @@
+; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-random-rate=1 -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s
+; RUN: opt < %s -passes='require<profile-summary>,function(lower-allow-check)' -lower-allow-check-random-rate=0 -pass-remarks=lower-allow-check -pass-remarks-missed=lower-allow-check -S 2>&1 | FileCheck %s --check-prefixes=REMOVE
+
+; CHECK: remark: <unknown>:0:0: Allowed check: Kind=test_check F=test_runtime BB=entry1
+; CHECK: remark: <unknown>:0:0: Allowed check: Kind=7 F=test_ubsan BB=entry2
+
+; REMOVE: remark: <unknown>:0:0: Removed check: Kind=test_check F=test_runtime BB=entry1
+; REMOVE: remark: <unknown>:0:0: Removed check: Kind=7 F=test_ubsan BB=entry2
+
+target triple = "x86_64-pc-linux-gnu"
+
+define i1 @test_runtime() local_unnamed_addr {
+entry1:
+ %allow = call i1 @llvm.allow.runtime.check(metadata !"test_check")
+ ret i1 %allow
+}
+
+declare i1 @llvm.allow.runtime.check(metadata) nounwind
+
+define i1 @test_ubsan() local_unnamed_addr {
+entry2:
+ %allow = call i1 @llvm.allow.ubsan.check(i8 7)
+ ret i1 %allow
+}
diff --git a/llvm/unittests/Bitcode/BitReaderTest.cpp b/llvm/unittests/Bitcode/BitReaderTest.cpp
index 3e449f905778..22cc5e749280 100644
--- a/llvm/unittests/Bitcode/BitReaderTest.cpp
+++ b/llvm/unittests/Bitcode/BitReaderTest.cpp
@@ -160,7 +160,7 @@ TEST(BitReaderTest, MaterializeConstrainedFPStrictFP) {
LLVMContext Context;
std::unique_ptr<Module> M = getLazyModuleFromAssembly(
Context, Mem,
- "define double @foo(double %a) {\n"
+ "define double @foo(double %a) strictfp {\n"
" %result = call double @llvm.experimental.constrained.sqrt.f64(double "
"%a, metadata !\"round.tonearest\", metadata !\"fpexcept.strict\") "
"strictfp\n"
diff --git a/llvm/unittests/Support/raw_socket_stream_test.cpp b/llvm/unittests/Support/raw_socket_stream_test.cpp
index 6903862e5403..a8536228666d 100644
--- a/llvm/unittests/Support/raw_socket_stream_test.cpp
+++ b/llvm/unittests/Support/raw_socket_stream_test.cpp
@@ -9,6 +9,7 @@
#include <future>
#include <iostream>
#include <stdlib.h>
+#include <thread>
#ifdef _WIN32
#include "llvm/Support/Windows/WindowsSupport.h"
@@ -32,10 +33,10 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
GTEST_SKIP();
SmallString<100> SocketPath;
- llvm::sys::fs::createUniquePath("test_raw_socket_stream.sock", SocketPath,
- true);
+ llvm::sys::fs::createUniquePath("client_server_comms.sock", SocketPath, true);
- char Bytes[8];
+ // Make sure socket file does not exist. May still be there from the last test
+ std::remove(SocketPath.c_str());
Expected<ListeningSocket> MaybeServerListener =
ListeningSocket::createUnix(SocketPath);
@@ -58,6 +59,7 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
Client << "01234567";
Client.flush();
+ char Bytes[8];
ssize_t BytesRead = Server.read(Bytes, 8);
std::string string(Bytes, 8);
@@ -65,4 +67,67 @@ TEST(raw_socket_streamTest, CLIENT_TO_SERVER_AND_SERVER_TO_CLIENT) {
ASSERT_EQ(8, BytesRead);
ASSERT_EQ("01234567", string);
}
-} // namespace \ No newline at end of file
+
+TEST(raw_socket_streamTest, TIMEOUT_PROVIDED) {
+ if (!hasUnixSocketSupport())
+ GTEST_SKIP();
+
+ SmallString<100> SocketPath;
+ llvm::sys::fs::createUniquePath("timout_provided.sock", SocketPath, true);
+
+ // Make sure socket file does not exist. May still be there from the last test
+ std::remove(SocketPath.c_str());
+
+ Expected<ListeningSocket> MaybeServerListener =
+ ListeningSocket::createUnix(SocketPath);
+ ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
+ ListeningSocket ServerListener = std::move(*MaybeServerListener);
+
+ std::chrono::milliseconds Timeout = std::chrono::milliseconds(100);
+ Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
+ ServerListener.accept(Timeout);
+
+ ASSERT_THAT_EXPECTED(MaybeServer, Failed());
+ llvm::Error Err = MaybeServer.takeError();
+ llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
+ std::error_code EC = SE.convertToErrorCode();
+ ASSERT_EQ(EC, std::errc::timed_out);
+ });
+}
+
+TEST(raw_socket_streamTest, FILE_DESCRIPTOR_CLOSED) {
+ if (!hasUnixSocketSupport())
+ GTEST_SKIP();
+
+ SmallString<100> SocketPath;
+ llvm::sys::fs::createUniquePath("fd_closed.sock", SocketPath, true);
+
+ // Make sure socket file does not exist. May still be there from the last test
+ std::remove(SocketPath.c_str());
+
+ Expected<ListeningSocket> MaybeServerListener =
+ ListeningSocket::createUnix(SocketPath);
+ ASSERT_THAT_EXPECTED(MaybeServerListener, llvm::Succeeded());
+ ListeningSocket ServerListener = std::move(*MaybeServerListener);
+
+ // Create a separate thread to close the socket after a delay. Simulates a
+ // signal handler calling ServerListener::shutdown
+ std::thread CloseThread([&]() {
+ std::this_thread::sleep_for(std::chrono::milliseconds(500));
+ ServerListener.shutdown();
+ });
+
+ Expected<std::unique_ptr<raw_socket_stream>> MaybeServer =
+ ServerListener.accept();
+
+ // Wait for the CloseThread to finish
+ CloseThread.join();
+
+ ASSERT_THAT_EXPECTED(MaybeServer, Failed());
+ llvm::Error Err = MaybeServer.takeError();
+ llvm::handleAllErrors(std::move(Err), [&](const llvm::StringError &SE) {
+ std::error_code EC = SE.convertToErrorCode();
+ ASSERT_EQ(EC, std::errc::operation_canceled);
+ });
+}
+} // namespace
diff --git a/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp b/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
index 8554d1a33cad..dbc1e2152785 100644
--- a/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
+++ b/llvm/unittests/Transforms/Utils/CodeMoverUtilsTest.cpp
@@ -673,6 +673,11 @@ TEST(CodeMoverUtils, IsSafeToMoveTest4) {
// Can move as %add2 and %sub2 are control flow equivalent,
// although %add2 does not strictly dominate %sub2.
EXPECT_TRUE(isSafeToMoveBefore(*SubInst2, *AddInst2, DT, &PDT, &DI));
+
+ BasicBlock *BB0 = getBasicBlockByName(F, "if.then.first");
+ BasicBlock *BB1 = getBasicBlockByName(F, "if.then.second");
+ EXPECT_TRUE(
+ isSafeToMoveBefore(*BB0, *BB1->getTerminator(), DT, &PDT, &DI));
});
}
diff --git a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorOps.td b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorOps.td
index 5df8a176459b..0cfc64f9988a 100644
--- a/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorOps.td
+++ b/mlir/include/mlir/Dialect/SparseTensor/IR/SparseTensorOps.td
@@ -58,37 +58,35 @@ def SparseTensor_AssembleOp : SparseTensor_Op<"assemble", [Pure]>,
Arguments<(ins Variadic<TensorOf<[AnySignlessIntegerOrIndex]>>:$levels,
TensorOf<[AnyType]>:$values)>,
Results<(outs AnySparseTensor: $result)> {
- let summary = "Returns a sparse tensor assembled from the given values and levels";
+ let summary = "Returns a sparse tensor assembled from the given levels and values";
let description = [{
- Assembles the values and per-level coordinate or postion arrays into a sparse tensor.
- The order and types of provided levels must be consistent with the actual storage
- layout of the returned sparse tensor described below.
+ Assembles the per-level position and coordinate arrays together with
+ the values arrays into a sparse tensor. The order and types of the
+ provided levels must be consistent with the actual storage layout of
+ the returned sparse tensor described below.
- - `values : tensor<? x V>`
- supplies the value for each stored element in the sparse tensor.
- `levels: [tensor<? x iType>, ...]`
- each supplies the sparse tensor coordinates scheme in the sparse tensor for
- the corresponding level as specifed by `sparse_tensor::StorageLayout`.
-
- This operation can be used to assemble a sparse tensor from external
- sources; e.g., when passing two numpy arrays from Python.
-
- Disclaimer: This is the user's responsibility to provide input that can be
- correctly interpreted by the sparsifier, which does not perform
- any sanity test during runtime to verify data integrity.
+ supplies the sparse tensor position and coordinate arrays
+ of the sparse tensor for the corresponding level as specifed by
+ `sparse_tensor::StorageLayout`.
+ - `values : tensor<? x V>`
+ supplies the values array for the stored elements in the sparse tensor.
- TODO: The returned tensor is allowed (in principle) to have non-identity
- dimOrdering/higherOrdering mappings. However, the current implementation
- does not yet support them.
+ This operation can be used to assemble a sparse tensor from an
+ external source; e.g., by passing numpy arrays from Python. It
+ is the user's responsibility to provide input that can be correctly
+ interpreted by the sparsifier, which does not perform any sanity
+ test to verify data integrity.
Example:
```mlir
- %values = arith.constant dense<[ 1.1, 2.2, 3.3 ]> : tensor<3xf64>
- %coordinates = arith.constant dense<[[0,0], [1,2], [1,3]]> : tensor<3x2xindex>
- %st = sparse_tensor.assemble %values, %coordinates
- : tensor<3xf64>, tensor<3x2xindex> to tensor<3x4xf64, #COO>
+ %pos = arith.constant dense<[0, 3]> : tensor<2xindex>
+ %index = arith.constant dense<[[0,0], [1,2], [1,3]]> : tensor<3x2xindex>
+ %values = arith.constant dense<[ 1.1, 2.2, 3.3 ]> : tensor<3xf64>
+ %s = sparse_tensor.assemble (%pos, %index), %values
+ : (tensor<2xindex>, tensor<3x2xindex>), tensor<3xf64> to tensor<3x4xf64, #COO>
// yields COO format |1.1, 0.0, 0.0, 0.0|
// of 3x4 matrix |0.0, 0.0, 2.2, 3.3|
// |0.0, 0.0, 0.0, 0.0|
@@ -96,8 +94,8 @@ def SparseTensor_AssembleOp : SparseTensor_Op<"assemble", [Pure]>,
}];
let assemblyFormat =
- "` ` `(` $levels `)` `,` $values attr-dict"
- " `:` `(` type($levels) `)` `,` type($values) `to` type($result)";
+ "` ` `(` $levels `)` `,` $values attr-dict `:`"
+ " `(` type($levels) `)` `,` type($values) `to` type($result)";
let hasVerifier = 1;
}
@@ -110,21 +108,20 @@ def SparseTensor_DisassembleOp : SparseTensor_Op<"disassemble", [Pure, SameVaria
TensorOf<[AnyType]>:$ret_values,
Variadic<AnyIndexingScalarLike>:$lvl_lens,
AnyIndexingScalarLike:$val_len)> {
- let summary = "Returns the (values, coordinates) pair disassembled from the input tensor";
+ let summary = "Copies the levels and values of the given sparse tensor";
let description = [{
The disassemble operation is the inverse of `sparse_tensor::assemble`.
- It returns the values and per-level position and coordinate array to the
- user from the sparse tensor along with the actual length of the memory used
- in each returned buffer. This operation can be used for returning an
- disassembled MLIR sparse tensor to frontend; e.g., returning two numpy arrays
- to Python.
-
- Disclaimer: This is the user's responsibility to allocate large enough buffers
- to hold the sparse tensor. The sparsifier simply copies each fields
- of the sparse tensor into the user-supplied buffer without bound checking.
+ It copies the per-level position and coordinate arrays together with
+ the values array of the given sparse tensor into the user-supplied buffers
+ along with the actual length of the memory used in each returned buffer.
- TODO: the current implementation does not yet support non-identity mappings.
+ This operation can be used for returning a disassembled MLIR sparse tensor;
+ e.g., copying the sparse tensor contents into pre-allocated numpy arrays
+ back to Python. It is the user's responsibility to allocate large enough
+ buffers of the appropriate types to hold the sparse tensor contents.
+ The sparsifier simply copies all fields of the sparse tensor into the
+ user-supplied buffers without any sanity test to verify data integrity.
Example:
@@ -132,26 +129,26 @@ def SparseTensor_DisassembleOp : SparseTensor_Op<"disassemble", [Pure, SameVaria
// input COO format |1.1, 0.0, 0.0, 0.0|
// of 3x4 matrix |0.0, 0.0, 2.2, 3.3|
// |0.0, 0.0, 0.0, 0.0|
- %v, %p, %c, %v_len, %p_len, %c_len =
- sparse_tensor.disassemble %sp : tensor<3x4xf64, #COO>
- out_lvls(%op, %oi) : tensor<2xindex>, tensor<3x2xindex>,
- out_vals(%od) : tensor<3xf64> ->
- tensor<3xf64>, (tensor<2xindex>, tensor<3x2xindex>), index, (index, index)
- // %v = arith.constant dense<[ 1.1, 2.2, 3.3 ]> : tensor<3xf64>
+ %p, %c, %v, %p_len, %c_len, %v_len =
+ sparse_tensor.disassemble %s : tensor<3x4xf64, #COO>
+ out_lvls(%op, %oi : tensor<2xindex>, tensor<3x2xindex>)
+ out_vals(%od : tensor<3xf64>) ->
+ (tensor<2xindex>, tensor<3x2xindex>), tensor<3xf64>, (index, index), index
// %p = arith.constant dense<[ 0, 3 ]> : tensor<2xindex>
// %c = arith.constant dense<[[0,0], [1,2], [1,3]]> : tensor<3x2xindex>
- // %v_len = 3
+ // %v = arith.constant dense<[ 1.1, 2.2, 3.3 ]> : tensor<3xf64>
// %p_len = 2
// %c_len = 6 (3x2)
+ // %v_len = 3
```
}];
let assemblyFormat =
- "$tensor `:` type($tensor) "
+ "$tensor attr-dict `:` type($tensor)"
"`out_lvls` `(` $out_levels `:` type($out_levels) `)` "
- "`out_vals` `(` $out_values `:` type($out_values) `)` attr-dict"
- "`->` `(` type($ret_levels) `)` `,` type($ret_values) `,` "
- "`(` type($lvl_lens) `)` `,` type($val_len)";
+ "`out_vals` `(` $out_values `:` type($out_values) `)` `->`"
+ "`(` type($ret_levels) `)` `,` type($ret_values) `,` "
+ "`(` type($lvl_lens) `)` `,` type($val_len)";
let hasVerifier = 1;
}
diff --git a/mlir/include/mlir/IR/OpDefinition.h b/mlir/include/mlir/IR/OpDefinition.h
index c177ae3594d1..2d1dee2303e8 100644
--- a/mlir/include/mlir/IR/OpDefinition.h
+++ b/mlir/include/mlir/IR/OpDefinition.h
@@ -1965,7 +1965,7 @@ public:
if constexpr (!hasProperties())
return getEmptyProperties();
return *getOperation()
- ->getPropertiesStorage()
+ ->getPropertiesStorageUnsafe()
.template as<InferredProperties<T> *>();
}
diff --git a/mlir/include/mlir/IR/Operation.h b/mlir/include/mlir/IR/Operation.h
index 3ffd3517fe5a..c52a6fcac10c 100644
--- a/mlir/include/mlir/IR/Operation.h
+++ b/mlir/include/mlir/IR/Operation.h
@@ -895,8 +895,7 @@ public:
/// Returns the properties storage.
OpaqueProperties getPropertiesStorage() {
if (propertiesStorageSize)
- return {
- reinterpret_cast<void *>(getTrailingObjects<detail::OpProperties>())};
+ return getPropertiesStorageUnsafe();
return {nullptr};
}
OpaqueProperties getPropertiesStorage() const {
@@ -905,6 +904,12 @@ public:
getTrailingObjects<detail::OpProperties>()))};
return {nullptr};
}
+ /// Returns the properties storage without checking whether properties are
+ /// present.
+ OpaqueProperties getPropertiesStorageUnsafe() {
+ return {
+ reinterpret_cast<void *>(getTrailingObjects<detail::OpProperties>())};
+ }
/// Return the properties converted to an attribute.
/// This is expensive, and mostly useful when dealing with unregistered
diff --git a/mlir/lib/Bytecode/Writer/IRNumbering.cpp b/mlir/lib/Bytecode/Writer/IRNumbering.cpp
index f36c9ef060b6..d2144dd7f334 100644
--- a/mlir/lib/Bytecode/Writer/IRNumbering.cpp
+++ b/mlir/lib/Bytecode/Writer/IRNumbering.cpp
@@ -424,22 +424,22 @@ void IRNumberingState::number(Operation &op) {
number(result.getType());
}
- // Only number the operation's dictionary if it isn't empty.
- DictionaryAttr dictAttr = op.getDiscardableAttrDictionary();
// Prior to a version with native property encoding, or when properties are
// not used, we need to number also the merged dictionary containing both the
// inherent and discardable attribute.
- if (config.getDesiredBytecodeVersion() <
- bytecode::kNativePropertiesEncoding ||
- !op.getPropertiesStorage()) {
+ DictionaryAttr dictAttr;
+ if (config.getDesiredBytecodeVersion() >= bytecode::kNativePropertiesEncoding)
+ dictAttr = op.getRawDictionaryAttrs();
+ else
dictAttr = op.getAttrDictionary();
- }
+ // Only number the operation's dictionary if it isn't empty.
if (!dictAttr.empty())
number(dictAttr);
// Visit the operation properties (if any) to make sure referenced attributes
// are numbered.
- if (config.getDesiredBytecodeVersion() >= bytecode::kNativePropertiesEncoding &&
+ if (config.getDesiredBytecodeVersion() >=
+ bytecode::kNativePropertiesEncoding &&
op.getPropertiesStorageSize()) {
if (op.isRegistered()) {
// Operation that have properties *must* implement this interface.
diff --git a/mlir/lib/Dialect/ArmNeon/Transforms/LowerContractionToSMMLAPattern.cpp b/mlir/lib/Dialect/ArmNeon/Transforms/LowerContractionToSMMLAPattern.cpp
index 13740225749e..3ae894692089 100644
--- a/mlir/lib/Dialect/ArmNeon/Transforms/LowerContractionToSMMLAPattern.cpp
+++ b/mlir/lib/Dialect/ArmNeon/Transforms/LowerContractionToSMMLAPattern.cpp
@@ -54,6 +54,9 @@ public:
// Note: RHS is not transposed.
mlir::VectorType lhsType = op.getLhsType();
mlir::VectorType rhsType = op.getRhsType();
+ // Avoid 0-D vectors and 1-D rhs:
+ if (!lhsType.hasRank() || !rhsType.hasRank() || rhsType.getRank() < 2)
+ return failure();
auto dimM = lhsType.getRank() == 1 ? 1 : lhsType.getDimSize(0);
auto dimN = rhsType.getDimSize(0);
auto dimK = rhsType.getDimSize(1);
diff --git a/mlir/test/Dialect/ArmNeon/lower-to-arm-neon.mlir b/mlir/test/Dialect/ArmNeon/lower-to-arm-neon.mlir
index 46c4026d13b6..c276a5b0c2a1 100644
--- a/mlir/test/Dialect/ArmNeon/lower-to-arm-neon.mlir
+++ b/mlir/test/Dialect/ArmNeon/lower-to-arm-neon.mlir
@@ -258,3 +258,14 @@ func.func @test_lower_vector_arm_neon_vecmat_unroll_leading_dim(%lhs: vector<1x8
%res = vector.contract {indexing_maps = [affine_map<(d0, d1, d2) -> (d0, d2)>, affine_map<(d0, d1, d2) -> (d1, d2)>, affine_map<(d0, d1, d2) -> (d0, d1)>], iterator_types = ["parallel", "parallel", "reduction"], kind = #vector.kind<add>} %lhs_extsi, %rhs_extsi, %acc : vector<1x8xi32>, vector<8x8xi32> into vector<1x8xi32>
return %res : vector<1x8xi32>
}
+
+// -----
+
+// CHECK-LABEL: func.func @test_lower_vector_arm_neon_matvec
+// CHECK-NOT: arm_neon.intr.smmla
+func.func @test_lower_vector_arm_neon_matvec(%lhs: vector<8x8xi8>, %rhs: vector<8xi8>, %acc : vector<8xi32>) -> vector<8xi32> {
+ %rhs_extsi= arith.extsi %rhs : vector<8xi8> to vector<8xi32>
+ %lhs_extsi = arith.extsi %lhs : vector<8x8xi8> to vector<8x8xi32>
+ %res = vector.contract {indexing_maps = [affine_map<(d0, d1) -> (d0, d1)>,affine_map<(d0, d1) -> (d1)>, affine_map<(d0, d1) -> (d0)>], iterator_types = ["parallel", "reduction"], kind = #vector.kind<add>} %lhs_extsi, %rhs_extsi, %acc : vector<8x8xi32>, vector<8xi32> into vector<8xi32>
+ return %res : vector<8xi32>
+}
diff --git a/mlir/test/Dialect/SparseTensor/invalid.mlir b/mlir/test/Dialect/SparseTensor/invalid.mlir
index 18851f29d8ea..7f5c05190fc9 100644
--- a/mlir/test/Dialect/SparseTensor/invalid.mlir
+++ b/mlir/test/Dialect/SparseTensor/invalid.mlir
@@ -60,7 +60,7 @@ func.func @invalid_pack_mis_position(%values: tensor<6xf64>, %coordinates: tenso
func.func @invalid_unpack_type(%sp: tensor<100xf32, #SparseVector>, %values: tensor<6xf64>, %pos: tensor<2xi32>, %coordinates: tensor<6x1xi32>) {
// expected-error@+1 {{input/output element-types don't match}}
- %rv, %rp, %rc, %vl, %pl, %cl = sparse_tensor.disassemble %sp : tensor<100xf32, #SparseVector>
+ %rp, %rc, %rv, %pl, %cl, %vl = sparse_tensor.disassemble %sp : tensor<100xf32, #SparseVector>
out_lvls(%pos, %coordinates : tensor<2xi32>, tensor<6x1xi32>)
out_vals(%values : tensor<6xf64>)
-> (tensor<2xi32>, tensor<6x1xi32>), tensor<6xf64>, (index, index), index
@@ -73,7 +73,7 @@ func.func @invalid_unpack_type(%sp: tensor<100xf32, #SparseVector>, %values: ten
func.func @invalid_unpack_type(%sp: tensor<100x2xf64, #SparseVector>, %values: tensor<6xf64>, %pos: tensor<2xi32>, %coordinates: tensor<6x3xi32>) {
// expected-error@+1 {{input/output trailing COO level-ranks don't match}}
- %rv, %rp, %rc, %vl, %pl, %cl = sparse_tensor.disassemble %sp : tensor<100x2xf64, #SparseVector>
+ %rp, %rc, %rv, %pl, %cl, %vl = sparse_tensor.disassemble %sp : tensor<100x2xf64, #SparseVector>
out_lvls(%pos, %coordinates : tensor<2xi32>, tensor<6x3xi32> )
out_vals(%values : tensor<6xf64>)
-> (tensor<2xi32>, tensor<6x3xi32>), tensor<6xf64>, (index, index), index
@@ -86,7 +86,7 @@ func.func @invalid_unpack_type(%sp: tensor<100x2xf64, #SparseVector>, %values: t
func.func @invalid_unpack_mis_position(%sp: tensor<2x100xf64, #CSR>, %values: tensor<6xf64>, %coordinates: tensor<6xi32>) {
// expected-error@+1 {{inconsistent number of fields between input/output}}
- %rv, %rc, %vl, %pl = sparse_tensor.disassemble %sp : tensor<2x100xf64, #CSR>
+ %rc, %rv, %cl, %vl = sparse_tensor.disassemble %sp : tensor<2x100xf64, #CSR>
out_lvls(%coordinates : tensor<6xi32>)
out_vals(%values : tensor<6xf64>)
-> (tensor<6xi32>), tensor<6xf64>, (index), index
diff --git a/mlir/test/Dialect/SparseTensor/roundtrip.mlir b/mlir/test/Dialect/SparseTensor/roundtrip.mlir
index a47a3d5119f9..12f69c1d37b9 100644
--- a/mlir/test/Dialect/SparseTensor/roundtrip.mlir
+++ b/mlir/test/Dialect/SparseTensor/roundtrip.mlir
@@ -33,21 +33,21 @@ func.func @sparse_pack(%pos: tensor<2xi32>, %index: tensor<6x1xi32>, %data: tens
#SparseVector = #sparse_tensor.encoding<{map = (d0) -> (d0 : compressed), crdWidth=32}>
// CHECK-LABEL: func @sparse_unpack(
// CHECK-SAME: %[[T:.*]]: tensor<100xf64, #
-// CHECK-SAME: %[[OD:.*]]: tensor<6xf64>
-// CHECK-SAME: %[[OP:.*]]: tensor<2xindex>
-// CHECK-SAME: %[[OI:.*]]: tensor<6x1xi32>
+// CHECK-SAME: %[[OP:.*]]: tensor<2xindex>,
+// CHECK-SAME: %[[OI:.*]]: tensor<6x1xi32>,
+// CHECK-SAME: %[[OD:.*]]: tensor<6xf64>)
// CHECK: %[[P:.*]]:2, %[[D:.*]], %[[PL:.*]]:2, %[[DL:.*]] = sparse_tensor.disassemble %[[T]]
// CHECK: return %[[P]]#0, %[[P]]#1, %[[D]]
func.func @sparse_unpack(%sp : tensor<100xf64, #SparseVector>,
- %od : tensor<6xf64>,
%op : tensor<2xindex>,
- %oi : tensor<6x1xi32>)
+ %oi : tensor<6x1xi32>,
+ %od : tensor<6xf64>)
-> (tensor<2xindex>, tensor<6x1xi32>, tensor<6xf64>) {
- %rp, %ri, %rd, %vl, %pl, %cl = sparse_tensor.disassemble %sp : tensor<100xf64, #SparseVector>
+ %rp, %ri, %d, %rpl, %ril, %dl = sparse_tensor.disassemble %sp : tensor<100xf64, #SparseVector>
out_lvls(%op, %oi : tensor<2xindex>, tensor<6x1xi32>)
out_vals(%od : tensor<6xf64>)
-> (tensor<2xindex>, tensor<6x1xi32>), tensor<6xf64>, (index, index), index
- return %rp, %ri, %rd : tensor<2xindex>, tensor<6x1xi32>, tensor<6xf64>
+ return %rp, %ri, %d : tensor<2xindex>, tensor<6x1xi32>, tensor<6xf64>
}
// -----
diff --git a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_pack.mlir b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_pack.mlir
index 7ecccad212cd..5415625ff05d 100644
--- a/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_pack.mlir
+++ b/mlir/test/Integration/Dialect/SparseTensor/CPU/sparse_pack.mlir
@@ -231,7 +231,7 @@ module {
%od = tensor.empty() : tensor<3xf64>
%op = tensor.empty() : tensor<2xi32>
%oi = tensor.empty() : tensor<3x2xi32>
- %p, %i, %d, %dl, %pl, %il = sparse_tensor.disassemble %s5 : tensor<10x10xf64, #SortedCOOI32>
+ %p, %i, %d, %pl, %il, %dl = sparse_tensor.disassemble %s5 : tensor<10x10xf64, #SortedCOOI32>
out_lvls(%op, %oi : tensor<2xi32>, tensor<3x2xi32>)
out_vals(%od : tensor<3xf64>)
-> (tensor<2xi32>, tensor<3x2xi32>), tensor<3xf64>, (i32, i64), index
@@ -244,10 +244,13 @@ module {
%vi = vector.transfer_read %i[%c0, %c0], %i0 : tensor<3x2xi32>, vector<3x2xi32>
vector.print %vi : vector<3x2xi32>
+ // CHECK-NEXT: 3
+ vector.print %dl : index
+
%d_csr = tensor.empty() : tensor<4xf64>
%p_csr = tensor.empty() : tensor<3xi32>
%i_csr = tensor.empty() : tensor<3xi32>
- %rp_csr, %ri_csr, %rd_csr, %ld_csr, %lp_csr, %li_csr = sparse_tensor.disassemble %csr : tensor<2x2xf64, #CSR>
+ %rp_csr, %ri_csr, %rd_csr, %lp_csr, %li_csr, %ld_csr = sparse_tensor.disassemble %csr : tensor<2x2xf64, #CSR>
out_lvls(%p_csr, %i_csr : tensor<3xi32>, tensor<3xi32>)
out_vals(%d_csr : tensor<4xf64>)
-> (tensor<3xi32>, tensor<3xi32>), tensor<4xf64>, (i32, i64), index
@@ -256,6 +259,9 @@ module {
%vd_csr = vector.transfer_read %rd_csr[%c0], %f0 : tensor<4xf64>, vector<3xf64>
vector.print %vd_csr : vector<3xf64>
+ // CHECK-NEXT: 3
+ vector.print %ld_csr : index
+
%bod = tensor.empty() : tensor<6xf64>
%bop = tensor.empty() : tensor<4xindex>
%boi = tensor.empty() : tensor<6x2xindex>
diff --git a/openmp/libomptarget/DeviceRTL/CMakeLists.txt b/openmp/libomptarget/DeviceRTL/CMakeLists.txt
index 2509f1276cce..2e7f28df24d6 100644
--- a/openmp/libomptarget/DeviceRTL/CMakeLists.txt
+++ b/openmp/libomptarget/DeviceRTL/CMakeLists.txt
@@ -122,6 +122,11 @@ set(clang_opt_flags -O3 -mllvm -openmp-opt-disable -DSHARED_SCRATCHPAD_SIZE=512
set(link_opt_flags -O3 -openmp-opt-disable -attributor-enable=module -vectorize-slp=false )
set(link_export_flag -passes=internalize -internalize-public-api-file=${source_directory}/exports)
+# If the user built with the GPU C library enabled we will use that instead.
+if(${LIBOMPTARGET_GPU_LIBC_SUPPORT})
+ list(APPEND clang_opt_flags -DOMPTARGET_HAS_LIBC)
+endif()
+
# Prepend -I to each list element
set (LIBOMPTARGET_LLVM_INCLUDE_DIRS_DEVICERTL "${LIBOMPTARGET_LLVM_INCLUDE_DIRS}")
list(TRANSFORM LIBOMPTARGET_LLVM_INCLUDE_DIRS_DEVICERTL PREPEND "-I")
diff --git a/openmp/libomptarget/DeviceRTL/src/LibC.cpp b/openmp/libomptarget/DeviceRTL/src/LibC.cpp
index af675b97256f..e587c3057f5b 100644
--- a/openmp/libomptarget/DeviceRTL/src/LibC.cpp
+++ b/openmp/libomptarget/DeviceRTL/src/LibC.cpp
@@ -25,13 +25,26 @@ int32_t omp_vprintf(const char *Format, void *Arguments, uint32_t) {
} // namespace impl
#pragma omp end declare variant
-// We do not have a vprintf implementation for AMD GPU yet so we use a stub.
#pragma omp begin declare variant match(device = {arch(amdgcn)})
+
+#ifdef OMPTARGET_HAS_LIBC
+// TODO: Remove this handling once we have varargs support.
+extern "C" struct FILE *stdout;
+extern "C" int32_t rpc_fprintf(FILE *, const char *, void *, uint64_t);
+
+namespace impl {
+int32_t omp_vprintf(const char *Format, void *Arguments, uint32_t Size) {
+ return rpc_fprintf(stdout, Format, Arguments, Size);
+}
+} // namespace impl
+#else
+// We do not have a vprintf implementation for AMD GPU so we use a stub.
namespace impl {
int32_t omp_vprintf(const char *Format, void *Arguments, uint32_t) {
return -1;
}
} // namespace impl
+#endif
#pragma omp end declare variant
extern "C" {
diff --git a/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp b/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
index a0fdde951b74..00650b801b42 100644
--- a/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
+++ b/openmp/libomptarget/plugins-nextgen/amdgpu/src/rtl.cpp
@@ -1885,8 +1885,8 @@ struct AMDGPUDeviceTy : public GenericDeviceTy, AMDGenericDeviceTy {
// Get the frequency of the steady clock. If the attribute is missing
// assume running on an older libhsa and default to 0, omp_get_wtime
// will be inaccurate but otherwise programs can still run.
- if (auto Err = getDeviceAttrRaw(HSA_AMD_AGENT_INFO_TIMESTAMP_FREQUENCY,
- ClockFrequency))
+ if (getDeviceAttrRaw(HSA_AMD_AGENT_INFO_TIMESTAMP_FREQUENCY,
+ ClockFrequency) != HSA_STATUS_SUCCESS)
ClockFrequency = 0;
// Load the grid values dependending on the wavefront.
diff --git a/openmp/libomptarget/src/interface.cpp b/openmp/libomptarget/src/interface.cpp
index b562ba8818c3..557703632c62 100644
--- a/openmp/libomptarget/src/interface.cpp
+++ b/openmp/libomptarget/src/interface.cpp
@@ -495,7 +495,7 @@ EXTERN void __tgt_target_nowait_query(void **AsyncHandle) {
if (QueryCounter.isAboveThreshold())
AsyncInfo->SyncType = AsyncInfoTy::SyncTy::BLOCKING;
- if (const int Rc = AsyncInfo->synchronize())
+ if (AsyncInfo->synchronize())
FATAL_MESSAGE0(1, "Error while querying the async queue for completion.\n");
// If there are device operations still pending, return immediately without
// deallocating the handle and increase the current thread query count.
diff --git a/openmp/runtime/test/lit.cfg b/openmp/runtime/test/lit.cfg
index e27e52bb4289..e8f7f3470580 100644
--- a/openmp/runtime/test/lit.cfg
+++ b/openmp/runtime/test/lit.cfg
@@ -112,13 +112,15 @@ if config.operating_system == 'AIX':
config.available_features.add("aix")
object_mode = os.environ.get('OBJECT_MODE', '32')
if object_mode == '64':
- config.test_flags += " -m64"
+ # Set OBJECT_MODE to 64 for LIT test if it is explicitly set.
+ config.environment['OBJECT_MODE'] = os.environ['OBJECT_MODE']
elif object_mode == '32':
# Set user data area to 2GB since the default size 256MB in 32-bit mode
# is not sufficient to run LIT tests on systems that have a lot of
# CPUs when creating one worker thread for each CPU and each worker
# thread uses 4MB stack size.
config.test_flags += " -Wl,-bmaxdata:0x80000000"
+ config.test_openmp_flags += " -Wl,-bmaxdata:0x80000000"
if 'Linux' in config.operating_system:
config.available_features.add("linux")
diff --git a/polly/lib/Analysis/ScopDetectionDiagnostic.cpp b/polly/lib/Analysis/ScopDetectionDiagnostic.cpp
index 30fbd17c78bf..d2fbcf731985 100644
--- a/polly/lib/Analysis/ScopDetectionDiagnostic.cpp
+++ b/polly/lib/Analysis/ScopDetectionDiagnostic.cpp
@@ -45,7 +45,7 @@ using namespace llvm;
#define DEBUG_TYPE "polly-detect"
#define SCOP_STAT(NAME, DESC) \
- { "polly-detect", "NAME", "Number of rejected regions: " DESC }
+ {"polly-detect", "NAME", "Number of rejected regions: " DESC}
static Statistic RejectStatistics[] = {
SCOP_STAT(CFG, ""),
diff --git a/polly/lib/Support/GICHelper.cpp b/polly/lib/Support/GICHelper.cpp
index 0e491944c162..04d422cf9946 100644
--- a/polly/lib/Support/GICHelper.cpp
+++ b/polly/lib/Support/GICHelper.cpp
@@ -83,10 +83,10 @@ APInt polly::APIntFromVal(__isl_take isl_val *Val) {
}
template <typename ISLTy, typename ISL_CTX_GETTER, typename ISL_PRINTER>
-static inline std::string stringFromIslObjInternal(__isl_keep ISLTy *isl_obj,
- ISL_CTX_GETTER ctx_getter_fn,
- ISL_PRINTER printer_fn,
- std::string DefaultValue) {
+static inline std::string
+stringFromIslObjInternal(__isl_keep ISLTy *isl_obj,
+ ISL_CTX_GETTER ctx_getter_fn, ISL_PRINTER printer_fn,
+ const std::string &DefaultValue) {
if (!isl_obj)
return DefaultValue;
isl_ctx *ctx = ctx_getter_fn(isl_obj);
@@ -134,12 +134,11 @@ ISL_C_OBJECT_TO_STRING(union_map)
ISL_C_OBJECT_TO_STRING(union_pw_aff)
ISL_C_OBJECT_TO_STRING(union_pw_multi_aff)
-static void replace(std::string &str, const std::string &find,
- const std::string &replace) {
+static void replace(std::string &str, StringRef find, StringRef replace) {
size_t pos = 0;
while ((pos = str.find(find, pos)) != std::string::npos) {
- str.replace(pos, find.length(), replace);
- pos += replace.length();
+ str.replace(pos, find.size(), replace);
+ pos += replace.size();
}
}
diff --git a/polly/lib/Transform/MatmulOptimizer.cpp b/polly/lib/Transform/MatmulOptimizer.cpp
index 51ae5a778e4f..ff1683b2d63c 100644
--- a/polly/lib/Transform/MatmulOptimizer.cpp
+++ b/polly/lib/Transform/MatmulOptimizer.cpp
@@ -598,7 +598,7 @@ createMacroKernel(isl::schedule_node Node,
/// @param MMI Parameters of the matrix multiplication operands.
/// @return The size of the widest type of the matrix multiplication operands
/// in bytes, including alignment padding.
-static uint64_t getMatMulAlignTypeSize(MatMulInfoTy MMI) {
+static uint64_t getMatMulAlignTypeSize(const MatMulInfoTy &MMI) {
auto *S = MMI.A->getStatement()->getParent();
auto &DL = S->getFunction().getParent()->getDataLayout();
auto ElementSizeA = DL.getTypeAllocSize(MMI.A->getElementType());
@@ -613,7 +613,7 @@ static uint64_t getMatMulAlignTypeSize(MatMulInfoTy MMI) {
/// @param MMI Parameters of the matrix multiplication operands.
/// @return The size of the widest type of the matrix multiplication operands
/// in bits.
-static uint64_t getMatMulTypeSize(MatMulInfoTy MMI) {
+static uint64_t getMatMulTypeSize(const MatMulInfoTy &MMI) {
auto *S = MMI.A->getStatement()->getParent();
auto &DL = S->getFunction().getParent()->getDataLayout();
auto ElementSizeA = DL.getTypeSizeInBits(MMI.A->getElementType());
@@ -635,7 +635,7 @@ static uint64_t getMatMulTypeSize(MatMulInfoTy MMI) {
/// @return The structure of type MicroKernelParamsTy.
/// @see MicroKernelParamsTy
static MicroKernelParamsTy getMicroKernelParams(const TargetTransformInfo *TTI,
- MatMulInfoTy MMI) {
+ const MatMulInfoTy &MMI) {
assert(TTI && "The target transform info should be provided.");
// Nvec - Number of double-precision floating-point numbers that can be hold
@@ -712,7 +712,7 @@ static void getTargetCacheParameters(const llvm::TargetTransformInfo *TTI) {
static MacroKernelParamsTy
getMacroKernelParams(const llvm::TargetTransformInfo *TTI,
const MicroKernelParamsTy &MicroKernelParams,
- MatMulInfoTy MMI) {
+ const MatMulInfoTy &MMI) {
getTargetCacheParameters(TTI);
// According to www.cs.utexas.edu/users/flame/pubs/TOMS-BLIS-Analytical.pdf,
// it requires information about the first two levels of a cache to determine
diff --git a/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel b/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
index 3c43c604316f..e30c8bf023cf 100644
--- a/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/libc/test/src/math/BUILD.bazel
@@ -379,6 +379,7 @@ libc_support_library(
deps = [
"//libc:__support_fputil_fenv_impl",
"//libc:__support_fputil_fp_bits",
+ "//libc:hdr_fenv_macros",
"//libc:hdr_math_macros",
"//libc/test/UnitTest:LibcUnitTest",
"//libc/test/UnitTest:fp_test_helpers",