https://github.com/RiverDave created https://github.com/llvm/llvm-project/pull/179084
None >From a51d3a2a92f958a4925e58206a1c89802de5145b Mon Sep 17 00:00:00 2001 From: David Rivera <[email protected]> Date: Sat, 31 Jan 2026 22:51:23 -0500 Subject: [PATCH] [CIR][AMDGPU] Lower Language specific address spaces and implement AMDGPU target --- clang/lib/CIR/CodeGen/CIRGenModule.cpp | 3 + clang/lib/CIR/CodeGen/TargetInfo.cpp | 46 +++++++++++++++ clang/lib/CIR/CodeGen/TargetInfo.h | 3 + .../Transforms/TargetLowering/CMakeLists.txt | 1 + .../Transforms/TargetLowering/LowerModule.cpp | 11 +++- .../TargetLowering/TargetLoweringInfo.h | 9 +++ .../TargetLowering/Targets/AMDGPU.cpp | 47 +++++++++++++++ .../CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp | 25 +++++--- .../CIR/CodeGen/amdgpu-address-spaces.cpp | 51 +++++++++++++++++ .../CIR/Lowering/global-address-space.cir | 57 ++++++++++++++++--- 10 files changed, 234 insertions(+), 19 deletions(-) create mode 100644 clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AMDGPU.cpp create mode 100644 clang/test/CIR/CodeGen/amdgpu-address-spaces.cpp diff --git a/clang/lib/CIR/CodeGen/CIRGenModule.cpp b/clang/lib/CIR/CodeGen/CIRGenModule.cpp index c5b4cfc39b6c1..f856407536688 100644 --- a/clang/lib/CIR/CodeGen/CIRGenModule.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenModule.cpp @@ -244,6 +244,9 @@ const TargetCIRGenInfo &CIRGenModule::getTargetCIRGenInfo() { return *theTargetCIRGenInfo; } } + case llvm::Triple::amdgcn: { + return *(theTargetCIRGenInfo = createAMDGPUTargetCIRGenInfo(genTypes)); + } } } diff --git a/clang/lib/CIR/CodeGen/TargetInfo.cpp b/clang/lib/CIR/CodeGen/TargetInfo.cpp index 50b973591d925..dd34c7e541a21 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.cpp +++ b/clang/lib/CIR/CodeGen/TargetInfo.cpp @@ -54,9 +54,55 @@ class X8664TargetCIRGenInfo : public TargetCIRGenInfo { X8664TargetCIRGenInfo(CIRGenTypes &cgt) : TargetCIRGenInfo(std::make_unique<X8664ABIInfo>(cgt)) {} }; +class AMDGPUABIInfo : public ABIInfo { +public: + AMDGPUABIInfo(CIRGenTypes &cgt) : ABIInfo(cgt) {} +}; + +class AMDGPUTargetCIRGenInfo : public TargetCIRGenInfo { +public: + AMDGPUTargetCIRGenInfo(CIRGenTypes &cgt) + : TargetCIRGenInfo(std::make_unique<AMDGPUABIInfo>(cgt)) {} + + clang::LangAS + getGlobalVarAddressSpace(CIRGenModule &cgm, + const clang::VarDecl *decl) const override { + using clang::LangAS; + assert(!cgm.getLangOpts().OpenCL && + !(cgm.getLangOpts().CUDA && cgm.getLangOpts().CUDAIsDevice) && + "Address space agnostic languages only"); + LangAS defaultGlobalAS = LangAS::opencl_global; + if (!decl) + return defaultGlobalAS; + + LangAS addrSpace = decl->getType().getAddressSpace(); + if (addrSpace != LangAS::Default) + return addrSpace; + + // Only promote to address space 4 if VarDecl has constant initialization. + if (decl->getType().isConstantStorage(cgm.getASTContext(), false, false) && + decl->hasConstantInitialization()) { + if (auto constAS = cgm.getTarget().getConstantAddressSpace()) + return *constAS; + } + + return defaultGlobalAS; + } + mlir::ptr::MemorySpaceAttrInterface + getCIRAllocaAddressSpace() const override { + return cir::LangAddressSpaceAttr::get( + &getABIInfo().cgt.getMLIRContext(), + cir::LangAddressSpace::OffloadPrivate); + } +}; } // namespace +std::unique_ptr<TargetCIRGenInfo> +clang::CIRGen::createAMDGPUTargetCIRGenInfo(CIRGenTypes &cgt) { + return std::make_unique<AMDGPUTargetCIRGenInfo>(cgt); +} + std::unique_ptr<TargetCIRGenInfo> clang::CIRGen::createX8664TargetCIRGenInfo(CIRGenTypes &cgt) { return std::make_unique<X8664TargetCIRGenInfo>(cgt); diff --git a/clang/lib/CIR/CodeGen/TargetInfo.h b/clang/lib/CIR/CodeGen/TargetInfo.h index 6108fa456b2c7..752ecb4445b6a 100644 --- a/clang/lib/CIR/CodeGen/TargetInfo.h +++ b/clang/lib/CIR/CodeGen/TargetInfo.h @@ -130,6 +130,9 @@ class TargetCIRGenInfo { } }; +std::unique_ptr<TargetCIRGenInfo> +createAMDGPUTargetCIRGenInfo(CIRGenTypes &cgt); + std::unique_ptr<TargetCIRGenInfo> createX8664TargetCIRGenInfo(CIRGenTypes &cgt); } // namespace clang::CIRGen diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt index 92148127424e9..07e3a67f97859 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/CMakeLists.txt @@ -3,6 +3,7 @@ add_clang_library(MLIRCIRTargetLowering LowerModule.cpp LowerItaniumCXXABI.cpp TargetLoweringInfo.cpp + Targets/AMDGPU.cpp DEPENDS clangBasic diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp index e39b764f6a838..844efcb633f94 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/LowerModule.cpp @@ -46,8 +46,15 @@ static std::unique_ptr<CIRCXXABI> createCXXABI(LowerModule &lm) { static std::unique_ptr<TargetLoweringInfo> createTargetLoweringInfo(LowerModule &lm) { - assert(!cir::MissingFeatures::targetLoweringInfo()); - return std::make_unique<TargetLoweringInfo>(); + const llvm::Triple &triple = lm.getTarget().getTriple(); + + switch (triple.getArch()) { + case llvm::Triple::amdgcn: + return createAMDGPUTargetLoweringInfo(); + default: + assert(!cir::MissingFeatures::targetLoweringInfo()); + return std::make_unique<TargetLoweringInfo>(); + } } LowerModule::LowerModule(clang::LangOptions langOpts, diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h b/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h index 91e7eb79ec83e..80f03283134a9 100644 --- a/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/TargetLoweringInfo.h @@ -15,6 +15,7 @@ #define LLVM_CLANG_LIB_CIR_DIALECT_TRANSFORMS_TARGETLOWERING_TARGETLOWERINGINFO_H #include "clang/CIR/Dialect/IR/CIROpsEnums.h" +#include <memory> #include <string> namespace cir { @@ -24,8 +25,16 @@ class TargetLoweringInfo { virtual ~TargetLoweringInfo(); virtual std::string getLLVMSyncScope(cir::SyncScopeKind syncScope) const; + + virtual unsigned + getTargetAddrSpaceFromCIRAddrSpace(cir::LangAddressSpace addrSpace) const { + return 0; + }; }; +// Target-specific factory functions. +std::unique_ptr<TargetLoweringInfo> createAMDGPUTargetLoweringInfo(); + } // namespace cir #endif diff --git a/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AMDGPU.cpp b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AMDGPU.cpp new file mode 100644 index 0000000000000..058c1200531e5 --- /dev/null +++ b/clang/lib/CIR/Dialect/Transforms/TargetLowering/Targets/AMDGPU.cpp @@ -0,0 +1,47 @@ +//===- AMDGPU.cpp - Emit CIR for AMDGPU -----------------------------------===// +// +// 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 +// +//===----------------------------------------------------------------------===// + +#include "../TargetLoweringInfo.h" +#include "clang/CIR/Dialect/IR/CIROpsEnums.h" +#include "llvm/Support/ErrorHandling.h" + +namespace cir { + +namespace { + +class AMDGPUTargetLoweringInfo : public TargetLoweringInfo { +public: + // Address space mapping from: + // https://llvm.org/docs/AMDGPUUsage.html#address-spaces + unsigned getTargetAddrSpaceFromCIRAddrSpace( + cir::LangAddressSpace addrSpace) const override { + switch (addrSpace) { + case cir::LangAddressSpace::Default: + return 0; + case cir::LangAddressSpace::OffloadPrivate: + return 5; + case cir::LangAddressSpace::OffloadLocal: + return 3; + case cir::LangAddressSpace::OffloadGlobal: + return 1; + case cir::LangAddressSpace::OffloadConstant: + return 4; + case cir::LangAddressSpace::OffloadGeneric: + return 0; + } + llvm_unreachable("Unknown CIR address space for AMDGPU target"); + } +}; + +} // namespace + +std::unique_ptr<TargetLoweringInfo> createAMDGPUTargetLoweringInfo() { + return std::make_unique<AMDGPUTargetLoweringInfo>(); +} + +} // namespace cir diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index c5d6e06b219ce..9adca0fb3e275 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -102,6 +102,13 @@ static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src, return mlir::LLVM::BitcastOp::create(bld, loc, dstTy, src); } +static unsigned convertCIRAddrSpaceToTarget(cir::LangAddressSpaceAttr addrSpace, + cir::LowerModule *lowerModule) { + assert(lowerModule && "CIR AS map is not available"); + return lowerModule->getTargetLoweringInfo() + .getTargetAddrSpaceFromCIRAddrSpace(addrSpace.getValue()); +} + static unsigned getNumericASFromCIRAS(mlir::ptr::MemorySpaceAttrInterface asAttr, [[maybe_unused]] cir::LowerModule *lowerModule) { @@ -111,10 +118,11 @@ getNumericASFromCIRAS(mlir::ptr::MemorySpaceAttrInterface asAttr, mlir::dyn_cast_if_present<cir::TargetAddressSpaceAttr>(asAttr)) return targetAddrSpaceAttr.getValue(); - if (mlir::isa_and_present<cir::LangAddressSpaceAttr>(asAttr)) - llvm_unreachable("lowering LangAddressSpaceAttr NYI"); + if (auto langAddressSpaceAttr = + mlir::dyn_cast<cir::LangAddressSpaceAttr>(asAttr)) + return convertCIRAddrSpaceToTarget(langAddressSpaceAttr, lowerModule); - llvm_unreachable("unexpected address Space attribute kindI"); + llvm_unreachable("unexpected address space attribute kind"); } static mlir::LLVM::Visibility @@ -2973,11 +2981,12 @@ std::unique_ptr<cir::LowerModule> prepareLowerModule(mlir::ModuleOp module) { static void prepareTypeConverter(mlir::LLVMTypeConverter &converter, mlir::DataLayout &dataLayout, cir::LowerModule *lowerModule) { - converter.addConversion([&](cir::PointerType type) -> mlir::Type { - mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr = type.getAddrSpace(); - unsigned numericAS = getNumericASFromCIRAS(addrSpaceAttr, lowerModule); - return mlir::LLVM::LLVMPointerType::get(type.getContext(), numericAS); - }); + converter.addConversion( + [&, lowerModule](cir::PointerType type) -> mlir::Type { + mlir::ptr::MemorySpaceAttrInterface addrSpaceAttr = type.getAddrSpace(); + unsigned numericAS = getNumericASFromCIRAS(addrSpaceAttr, lowerModule); + return mlir::LLVM::LLVMPointerType::get(type.getContext(), numericAS); + }); converter.addConversion([&](cir::VPtrType type) -> mlir::Type { assert(!cir::MissingFeatures::addressSpace()); return mlir::LLVM::LLVMPointerType::get(type.getContext()); diff --git a/clang/test/CIR/CodeGen/amdgpu-address-spaces.cpp b/clang/test/CIR/CodeGen/amdgpu-address-spaces.cpp new file mode 100644 index 0000000000000..35ceed46189dc --- /dev/null +++ b/clang/test/CIR/CodeGen/amdgpu-address-spaces.cpp @@ -0,0 +1,51 @@ +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --check-prefix=CIR --input-file=%t.cir %s + +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -fclangir -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=LLVM --input-file=%t.ll %s + +// RUN: %clang_cc1 -triple amdgcn-amd-amdhsa -emit-llvm %s -o %t.ll +// RUN: FileCheck --check-prefix=OGCG --input-file=%t.ll %s + +// Test address space handling for AMDGPU target in C++ mode (non-OpenCL/HIP). +// This exercises getGlobalVarAddressSpace. + +// Test default address space for globals without explicit AS. +// For AMDGPU in non-OpenCL/HIP mode, globals default to AS 1 (global). +int globalVar = 123; + +// CIR-DAG: cir.global external lang_address_space(offload_global) @globalVar = #cir.int<123> : !s32i +// LLVM-DAG: @globalVar = addrspace(1) global i32 123, align 4 +// OGCG-DAG: @globalVar = addrspace(1) global i32 123, align 4 + +// Test non-const global array goes to global AS. +int globalArray[4] = {1, 2, 3, 4}; + +// CIR-DAG: cir.global external lang_address_space(offload_global) @globalArray = #cir.const_array<[#cir.int<1> : !s32i, #cir.int<2> : !s32i, #cir.int<3> : !s32i, #cir.int<4> : !s32i]> : !cir.array<!s32i x 4> +// LLVM-DAG: @globalArray = addrspace(1) global [4 x i32] [i32 1, i32 2, i32 3, i32 4], align 4 +// OGCG-DAG: @globalArray = addrspace(1) global [4 x i32] [i32 1, i32 2, i32 3, i32 4], align 4 + +// Test static global goes to global AS. +static int staticGlobal = 555; + +// CIR-DAG: cir.global "private" internal{{.*}}lang_address_space(offload_global) @_ZL12staticGlobal = #cir.int<555> : !s32i +// LLVM-DAG: @_ZL12staticGlobal = internal addrspace(1) global i32 555, align 4 +// OGCG-DAG: @_ZL12staticGlobal = internal addrspace(1) global i32 555, align 4 + +// Test constant initialization promotion to AS 4 (constant). +// Use extern to force emission since const globals are otherwise optimized away. +extern const int constGlobal = 456; + +// CIR-DAG: cir.global constant external target_address_space(4) @constGlobal = #cir.int<456> : !s32i +// LLVM-DAG: @constGlobal = addrspace(4) constant i32 456, align 4 +// OGCG-DAG: @constGlobal = addrspace(4) constant i32 456, align 4 + +// Test extern const array goes to constant AS. +extern const int constArray[3] = {10, 20, 30}; + +// CIR-DAG: cir.global constant external target_address_space(4) @constArray = #cir.const_array<[#cir.int<10> : !s32i, #cir.int<20> : !s32i, #cir.int<30> : !s32i]> : !cir.array<!s32i x 3> +// LLVM-DAG: @constArray = addrspace(4) constant [3 x i32] [i32 10, i32 20, i32 30], align 4 +// OGCG-DAG: @constArray = addrspace(4) constant [3 x i32] [i32 10, i32 20, i32 30], align 4 + +// Use the static variable to ensure it's emitted. +int getStaticGlobal() { return staticGlobal; } diff --git a/clang/test/CIR/Lowering/global-address-space.cir b/clang/test/CIR/Lowering/global-address-space.cir index c9f25e1126098..7161d6852acb2 100644 --- a/clang/test/CIR/Lowering/global-address-space.cir +++ b/clang/test/CIR/Lowering/global-address-space.cir @@ -3,12 +3,13 @@ !s32i = !cir.int<s, 32> -module { - cir.global external target_address_space(1) @global_as1 = #cir.int<42> : !s32i - // CHECK: llvm.mlir.global external @global_as1(42 : i32) {addr_space = 1 : i32} : i32 +module attributes { cir.triple = "amdgcn-amd-amdhsa" } { + // Target address space lowering (passthrough) + cir.global external target_address_space(1) @global_target_as1 = #cir.int<42> : !s32i + // CHECK: llvm.mlir.global external @global_target_as1(42 : i32) {addr_space = 1 : i32} : i32 - cir.global external target_address_space(3) @global_as3 = #cir.int<100> : !s32i - // CHECK: llvm.mlir.global external @global_as3(100 : i32) {addr_space = 3 : i32} : i32 + cir.global external target_address_space(3) @global_target_as3 = #cir.int<100> : !s32i + // CHECK: llvm.mlir.global external @global_target_as3(100 : i32) {addr_space = 3 : i32} : i32 cir.global external @global_default = #cir.int<0> : !s32i // CHECK: llvm.mlir.global external @global_default(0 : i32) {addr_space = 0 : i32} : i32 @@ -16,20 +17,20 @@ module { // Test cir.get_global with address space produces correct llvm.mlir.addressof type // CHECK-LABEL: llvm.func @test_get_global_as1 cir.func @test_get_global_as1() -> !s32i { - // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @global_as1 : !llvm.ptr<1> + // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @global_target_as1 : !llvm.ptr<1> // CHECK: %[[VAL:.*]] = llvm.load %[[ADDR]] {{.*}} : !llvm.ptr<1> -> i32 // CHECK: llvm.return %[[VAL]] : i32 - %0 = cir.get_global @global_as1 : !cir.ptr<!s32i, target_address_space(1)> + %0 = cir.get_global @global_target_as1 : !cir.ptr<!s32i, target_address_space(1)> %1 = cir.load %0 : !cir.ptr<!s32i, target_address_space(1)>, !s32i cir.return %1 : !s32i } // CHECK-LABEL: llvm.func @test_get_global_as3 cir.func @test_get_global_as3() -> !s32i { - // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @global_as3 : !llvm.ptr<3> + // CHECK: %[[ADDR:.*]] = llvm.mlir.addressof @global_target_as3 : !llvm.ptr<3> // CHECK: %[[VAL:.*]] = llvm.load %[[ADDR]] {{.*}} : !llvm.ptr<3> -> i32 // CHECK: llvm.return %[[VAL]] : i32 - %0 = cir.get_global @global_as3 : !cir.ptr<!s32i, target_address_space(3)> + %0 = cir.get_global @global_target_as3 : !cir.ptr<!s32i, target_address_space(3)> %1 = cir.load %0 : !cir.ptr<!s32i, target_address_space(3)>, !s32i cir.return %1 : !s32i } @@ -43,4 +44,42 @@ module { %1 = cir.load %0 : !cir.ptr<!s32i>, !s32i cir.return %1 : !s32i } + + // Language address space lowering (AMDGPU mapping) + // See: https://llvm.org/docs/AMDGPUUsage.html#address-spaces + // OffloadGlobal -> 1 + cir.global external lang_address_space(offload_global) @global_lang_global = #cir.int<1> : !s32i + // CHECK: llvm.mlir.global external @global_lang_global(1 : i32) {addr_space = 1 : i32} : i32 + + // OffloadLocal -> 3 + cir.global "private" internal lang_address_space(offload_local) @global_lang_local : !s32i + // CHECK: llvm.mlir.global internal @global_lang_local() {addr_space = 3 : i32} : i32 + + // OffloadConstant -> 4 + cir.global external lang_address_space(offload_constant) @global_lang_constant = #cir.int<2> : !s32i + // CHECK: llvm.mlir.global external @global_lang_constant(2 : i32) {addr_space = 4 : i32} : i32 + + // OffloadPrivate -> 5 + cir.global "private" internal lang_address_space(offload_private) @global_lang_private : !s32i + // CHECK: llvm.mlir.global internal @global_lang_private() {addr_space = 5 : i32} : i32 + + // OffloadGeneric -> 0 + cir.global external lang_address_space(offload_generic) @global_lang_generic = #cir.int<3> : !s32i + // CHECK: llvm.mlir.global external @global_lang_generic(3 : i32) {addr_space = 0 : i32} : i32 + + // Pointer type lowering with lang_address_space + // CHECK: llvm.func @test_ptr_lang_as(%arg0: !llvm.ptr<1>) + cir.func @test_ptr_lang_as(%arg0: !cir.ptr<!s32i, lang_address_space(offload_global)>) { + // The alloca stores a pointer to address space 1, but the alloca itself is on the stack (default AS) + // CHECK: llvm.alloca {{.*}} x !llvm.ptr<1> {{.*}} : (i64) -> !llvm.ptr + %0 = cir.alloca !cir.ptr<!s32i, lang_address_space(offload_global)>, !cir.ptr<!cir.ptr<!s32i, lang_address_space(offload_global)>>, ["arg", init] {alignment = 8 : i64} + cir.return + } + + // CHECK: llvm.func @test_ptr_target_as(%arg0: !llvm.ptr<5>) + cir.func @test_ptr_target_as(%arg0: !cir.ptr<!s32i, target_address_space(5)>) { + // CHECK: llvm.alloca {{.*}} x !llvm.ptr<5> {{.*}} : (i64) -> !llvm.ptr + %0 = cir.alloca !cir.ptr<!s32i, target_address_space(5)>, !cir.ptr<!cir.ptr<!s32i, target_address_space(5)>>, ["arg", init] {alignment = 8 : i64} + cir.return + } } _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
