From 126b56a234486a2cd05a8beca78bcf89fe47d167 Mon Sep 17 00:00:00 2001 From: Piyou Chen Date: Wed, 21 Aug 2024 16:46:59 +0800 Subject: [PATCH] [RISCV] Make EmitRISCVCpuSupports accept multiple features (#104917) This patch creates an additional EmitRISCVCpuSupports function to handle situations with multiple features. It also modifies the original EmitRISCVCpuSupports function to invoke the new one. --- clang/lib/CodeGen/CGBuiltin.cpp | 72 ++++++++++++++++++--------- clang/lib/CodeGen/CodeGenFunction.h | 1 + clang/test/CodeGen/builtin-cpu-supports.c | 16 +++--- llvm/include/llvm/TargetParser/RISCVISAInfo.h | 3 ++ 4 files changed, 61 insertions(+), 31 deletions(-) diff --git a/clang/lib/CodeGen/CGBuiltin.cpp b/clang/lib/CodeGen/CGBuiltin.cpp index 3e787cad6e82..3d77b118235c 100644 --- a/clang/lib/CodeGen/CGBuiltin.cpp +++ b/clang/lib/CodeGen/CGBuiltin.cpp @@ -14439,33 +14439,59 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) { if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr)) return Builder.getFalse(); - // Note: We are making an unchecked assumption that the size of the - // feature array is >= 1. This holds for any version of compiler-rt - // which defines this interface. - llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1); + return EmitRISCVCpuSupports(ArrayRef(FeatureStr)); +} + +static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder, + CodeGenModule &CGM) { + llvm::Type *Int32Ty = Builder.getInt32Ty(); + llvm::Type *Int64Ty = Builder.getInt64Ty(); + llvm::ArrayType *ArrayOfInt64Ty = + llvm::ArrayType::get(Int64Ty, llvm::RISCVISAInfo::FeatureBitSize); llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty); llvm::Constant *RISCVFeaturesBits = CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits"); - auto *GV = cast(RISCVFeaturesBits); - GV->setDSOLocal(true); - - auto LoadFeatureBit = [&](unsigned Index) { - // Create GEP then load. - Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index); - llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1), - IndexVal}; - Value *Ptr = - Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices); - Value *FeaturesBit = - Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8)); - return FeaturesBit; - }; + cast(RISCVFeaturesBits)->setDSOLocal(true); + Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index); + llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1), + IndexVal}; + Value *Ptr = + Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices); + Value *FeaturesBit = + Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8)); + return FeaturesBit; +} + +Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef FeaturesStrs) { + const unsigned RISCVFeatureLength = llvm::RISCVISAInfo::FeatureBitSize; + uint64_t RequireBitMasks[RISCVFeatureLength] = {0}; + + for (auto Feat : FeaturesStrs) { + auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(Feat); + + // If there isn't BitPos for this feature, skip this version. + // It also report the warning to user during compilation. + if (BitPos == -1) + return Builder.getFalse(); - auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(FeatureStr); - assert(BitPos != -1 && "validation should have rejected this feature"); - Value *MaskV = Builder.getInt64(1ULL << BitPos); - Value *Bitset = Builder.CreateAnd(LoadFeatureBit(GroupID), MaskV); - return Builder.CreateICmpEQ(Bitset, MaskV); + RequireBitMasks[GroupID] |= (1ULL << BitPos); + } + + Value *Result = nullptr; + for (unsigned Idx = 0; Idx < RISCVFeatureLength; Idx++) { + if (RequireBitMasks[Idx] == 0) + continue; + + Value *Mask = Builder.getInt64(RequireBitMasks[Idx]); + Value *Bitset = + Builder.CreateAnd(loadRISCVFeatureBits(Idx, Builder, CGM), Mask); + Value *CmpV = Builder.CreateICmpEQ(Bitset, Mask); + Result = (!Result) ? CmpV : Builder.CreateAnd(Result, CmpV); + } + + assert(Result && "Should have value here."); + + return Result; } Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID, diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h index 57e0b7f91e9b..e1b9ada3c1e1 100644 --- a/clang/lib/CodeGen/CodeGenFunction.h +++ b/clang/lib/CodeGen/CodeGenFunction.h @@ -4704,6 +4704,7 @@ public: ReturnValueSlot ReturnValue); llvm::Value *EmitRISCVCpuSupports(const CallExpr *E); + llvm::Value *EmitRISCVCpuSupports(ArrayRef FeaturesStrs); llvm::Value *EmitRISCVCpuInit(); void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst, diff --git a/clang/test/CodeGen/builtin-cpu-supports.c b/clang/test/CodeGen/builtin-cpu-supports.c index b252484fc3df..72fc9a433dd6 100644 --- a/clang/test/CodeGen/builtin-cpu-supports.c +++ b/clang/test/CodeGen/builtin-cpu-supports.c @@ -251,7 +251,7 @@ int test_ppc(int a) { // CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-RV32-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 // CHECK-RV32-NEXT: call void @__init_riscv_feature_bits(ptr null) -// CHECK-RV32-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV32-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV32-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1 // CHECK-RV32-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1 // CHECK-RV32-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] @@ -259,7 +259,7 @@ int test_ppc(int a) { // CHECK-RV32-NEXT: store i32 3, ptr [[RETVAL]], align 4 // CHECK-RV32-NEXT: br label [[RETURN:%.*]] // CHECK-RV32: if.else: -// CHECK-RV32-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV32-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV32-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4 // CHECK-RV32-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4 // CHECK-RV32-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]] @@ -267,7 +267,7 @@ int test_ppc(int a) { // CHECK-RV32-NEXT: store i32 7, ptr [[RETVAL]], align 4 // CHECK-RV32-NEXT: br label [[RETURN]] // CHECK-RV32: if.else2: -// CHECK-RV32-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV32-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV32-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152 // CHECK-RV32-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152 // CHECK-RV32-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]] @@ -275,7 +275,7 @@ int test_ppc(int a) { // CHECK-RV32-NEXT: store i32 11, ptr [[RETVAL]], align 4 // CHECK-RV32-NEXT: br label [[RETURN]] // CHECK-RV32: if.else4: -// CHECK-RV32-NEXT: [[TMP9:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 1), align 8 +// CHECK-RV32-NEXT: [[TMP9:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 1), align 8 // CHECK-RV32-NEXT: [[TMP10:%.*]] = and i64 [[TMP9]], 8 // CHECK-RV32-NEXT: [[TMP11:%.*]] = icmp eq i64 [[TMP10]], 8 // CHECK-RV32-NEXT: br i1 [[TMP11]], label [[IF_THEN5:%.*]], label [[IF_END:%.*]] @@ -302,7 +302,7 @@ int test_ppc(int a) { // CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4 // CHECK-RV64-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4 // CHECK-RV64-NEXT: call void @__init_riscv_feature_bits(ptr null) -// CHECK-RV64-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV64-NEXT: [[TMP0:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV64-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1 // CHECK-RV64-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1 // CHECK-RV64-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]] @@ -310,7 +310,7 @@ int test_ppc(int a) { // CHECK-RV64-NEXT: store i32 3, ptr [[RETVAL]], align 4 // CHECK-RV64-NEXT: br label [[RETURN:%.*]] // CHECK-RV64: if.else: -// CHECK-RV64-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV64-NEXT: [[TMP3:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV64-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4 // CHECK-RV64-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4 // CHECK-RV64-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]] @@ -318,7 +318,7 @@ int test_ppc(int a) { // CHECK-RV64-NEXT: store i32 7, ptr [[RETVAL]], align 4 // CHECK-RV64-NEXT: br label [[RETURN]] // CHECK-RV64: if.else2: -// CHECK-RV64-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 +// CHECK-RV64-NEXT: [[TMP6:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 0), align 8 // CHECK-RV64-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152 // CHECK-RV64-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152 // CHECK-RV64-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]] @@ -326,7 +326,7 @@ int test_ppc(int a) { // CHECK-RV64-NEXT: store i32 11, ptr [[RETVAL]], align 4 // CHECK-RV64-NEXT: br label [[RETURN]] // CHECK-RV64: if.else4: -// CHECK-RV64-NEXT: [[TMP9:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [1 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 1), align 8 +// CHECK-RV64-NEXT: [[TMP9:%.*]] = load i64, ptr getelementptr inbounds ({ i32, [2 x i64] }, ptr @__riscv_feature_bits, i32 0, i32 1, i32 1), align 8 // CHECK-RV64-NEXT: [[TMP10:%.*]] = and i64 [[TMP9]], 8 // CHECK-RV64-NEXT: [[TMP11:%.*]] = icmp eq i64 [[TMP10]], 8 // CHECK-RV64-NEXT: br i1 [[TMP11]], label [[IF_THEN5:%.*]], label [[IF_END:%.*]] diff --git a/llvm/include/llvm/TargetParser/RISCVISAInfo.h b/llvm/include/llvm/TargetParser/RISCVISAInfo.h index dd00e12cdf6c..5b2b6f29fd3d 100644 --- a/llvm/include/llvm/TargetParser/RISCVISAInfo.h +++ b/llvm/include/llvm/TargetParser/RISCVISAInfo.h @@ -84,6 +84,9 @@ public: /// <-1, -1> if not supported. static std::pair getRISCVFeaturesBitsInfo(StringRef Ext); + // The maximum value of the group ID obtained from getRISCVFeaturesBitsInfo. + static constexpr unsigned FeatureBitSize = 2; + private: RISCVISAInfo(unsigned XLen) : XLen(XLen) {} -- 2.11.4.GIT