Skip to content

Commit 126b56a

Browse files
authored
[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.
1 parent 6c189ea commit 126b56a

File tree

4 files changed

+61
-31
lines changed

4 files changed

+61
-31
lines changed

clang/lib/CodeGen/CGBuiltin.cpp

Lines changed: 49 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -14439,33 +14439,59 @@ Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
1443914439
if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
1444014440
return Builder.getFalse();
1444114441

14442-
// Note: We are making an unchecked assumption that the size of the
14443-
// feature array is >= 1. This holds for any version of compiler-rt
14444-
// which defines this interface.
14445-
llvm::ArrayType *ArrayOfInt64Ty = llvm::ArrayType::get(Int64Ty, 1);
14442+
return EmitRISCVCpuSupports(ArrayRef<StringRef>(FeatureStr));
14443+
}
14444+
14445+
static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder,
14446+
CodeGenModule &CGM) {
14447+
llvm::Type *Int32Ty = Builder.getInt32Ty();
14448+
llvm::Type *Int64Ty = Builder.getInt64Ty();
14449+
llvm::ArrayType *ArrayOfInt64Ty =
14450+
llvm::ArrayType::get(Int64Ty, llvm::RISCVISAInfo::FeatureBitSize);
1444614451
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
1444714452
llvm::Constant *RISCVFeaturesBits =
1444814453
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
14449-
auto *GV = cast<llvm::GlobalValue>(RISCVFeaturesBits);
14450-
GV->setDSOLocal(true);
14451-
14452-
auto LoadFeatureBit = [&](unsigned Index) {
14453-
// Create GEP then load.
14454-
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
14455-
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
14456-
IndexVal};
14457-
Value *Ptr =
14458-
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14459-
Value *FeaturesBit =
14460-
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14461-
return FeaturesBit;
14462-
};
14454+
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
14455+
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
14456+
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
14457+
IndexVal};
14458+
Value *Ptr =
14459+
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
14460+
Value *FeaturesBit =
14461+
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
14462+
return FeaturesBit;
14463+
}
14464+
14465+
Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) {
14466+
const unsigned RISCVFeatureLength = llvm::RISCVISAInfo::FeatureBitSize;
14467+
uint64_t RequireBitMasks[RISCVFeatureLength] = {0};
14468+
14469+
for (auto Feat : FeaturesStrs) {
14470+
auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(Feat);
14471+
14472+
// If there isn't BitPos for this feature, skip this version.
14473+
// It also report the warning to user during compilation.
14474+
if (BitPos == -1)
14475+
return Builder.getFalse();
1446314476

14464-
auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(FeatureStr);
14465-
assert(BitPos != -1 && "validation should have rejected this feature");
14466-
Value *MaskV = Builder.getInt64(1ULL << BitPos);
14467-
Value *Bitset = Builder.CreateAnd(LoadFeatureBit(GroupID), MaskV);
14468-
return Builder.CreateICmpEQ(Bitset, MaskV);
14477+
RequireBitMasks[GroupID] |= (1ULL << BitPos);
14478+
}
14479+
14480+
Value *Result = nullptr;
14481+
for (unsigned Idx = 0; Idx < RISCVFeatureLength; Idx++) {
14482+
if (RequireBitMasks[Idx] == 0)
14483+
continue;
14484+
14485+
Value *Mask = Builder.getInt64(RequireBitMasks[Idx]);
14486+
Value *Bitset =
14487+
Builder.CreateAnd(loadRISCVFeatureBits(Idx, Builder, CGM), Mask);
14488+
Value *CmpV = Builder.CreateICmpEQ(Bitset, Mask);
14489+
Result = (!Result) ? CmpV : Builder.CreateAnd(Result, CmpV);
14490+
}
14491+
14492+
assert(Result && "Should have value here.");
14493+
14494+
return Result;
1446914495
}
1447014496

1447114497
Value *CodeGenFunction::EmitX86BuiltinExpr(unsigned BuiltinID,

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4704,6 +4704,7 @@ class CodeGenFunction : public CodeGenTypeCache {
47044704
ReturnValueSlot ReturnValue);
47054705

47064706
llvm::Value *EmitRISCVCpuSupports(const CallExpr *E);
4707+
llvm::Value *EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs);
47074708
llvm::Value *EmitRISCVCpuInit();
47084709

47094710
void AddAMDGPUFenceAddressSpaceMMRA(llvm::Instruction *Inst,

clang/test/CodeGen/builtin-cpu-supports.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -251,31 +251,31 @@ int test_ppc(int a) {
251251
// CHECK-RV32-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
252252
// CHECK-RV32-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
253253
// CHECK-RV32-NEXT: call void @__init_riscv_feature_bits(ptr null)
254-
// 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
254+
// 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
255255
// CHECK-RV32-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1
256256
// CHECK-RV32-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
257257
// CHECK-RV32-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
258258
// CHECK-RV32: if.then:
259259
// CHECK-RV32-NEXT: store i32 3, ptr [[RETVAL]], align 4
260260
// CHECK-RV32-NEXT: br label [[RETURN:%.*]]
261261
// CHECK-RV32: if.else:
262-
// 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
262+
// 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
263263
// CHECK-RV32-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4
264264
// CHECK-RV32-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
265265
// CHECK-RV32-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
266266
// CHECK-RV32: if.then1:
267267
// CHECK-RV32-NEXT: store i32 7, ptr [[RETVAL]], align 4
268268
// CHECK-RV32-NEXT: br label [[RETURN]]
269269
// CHECK-RV32: if.else2:
270-
// 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
270+
// 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
271271
// CHECK-RV32-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
272272
// CHECK-RV32-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
273273
// CHECK-RV32-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]]
274274
// CHECK-RV32: if.then3:
275275
// CHECK-RV32-NEXT: store i32 11, ptr [[RETVAL]], align 4
276276
// CHECK-RV32-NEXT: br label [[RETURN]]
277277
// CHECK-RV32: if.else4:
278-
// 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
278+
// 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
279279
// CHECK-RV32-NEXT: [[TMP10:%.*]] = and i64 [[TMP9]], 8
280280
// CHECK-RV32-NEXT: [[TMP11:%.*]] = icmp eq i64 [[TMP10]], 8
281281
// CHECK-RV32-NEXT: br i1 [[TMP11]], label [[IF_THEN5:%.*]], label [[IF_END:%.*]]
@@ -302,31 +302,31 @@ int test_ppc(int a) {
302302
// CHECK-RV64-NEXT: [[A_ADDR:%.*]] = alloca i32, align 4
303303
// CHECK-RV64-NEXT: store i32 [[A]], ptr [[A_ADDR]], align 4
304304
// CHECK-RV64-NEXT: call void @__init_riscv_feature_bits(ptr null)
305-
// 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
305+
// 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
306306
// CHECK-RV64-NEXT: [[TMP1:%.*]] = and i64 [[TMP0]], 1
307307
// CHECK-RV64-NEXT: [[TMP2:%.*]] = icmp eq i64 [[TMP1]], 1
308308
// CHECK-RV64-NEXT: br i1 [[TMP2]], label [[IF_THEN:%.*]], label [[IF_ELSE:%.*]]
309309
// CHECK-RV64: if.then:
310310
// CHECK-RV64-NEXT: store i32 3, ptr [[RETVAL]], align 4
311311
// CHECK-RV64-NEXT: br label [[RETURN:%.*]]
312312
// CHECK-RV64: if.else:
313-
// 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
313+
// 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
314314
// CHECK-RV64-NEXT: [[TMP4:%.*]] = and i64 [[TMP3]], 4
315315
// CHECK-RV64-NEXT: [[TMP5:%.*]] = icmp eq i64 [[TMP4]], 4
316316
// CHECK-RV64-NEXT: br i1 [[TMP5]], label [[IF_THEN1:%.*]], label [[IF_ELSE2:%.*]]
317317
// CHECK-RV64: if.then1:
318318
// CHECK-RV64-NEXT: store i32 7, ptr [[RETVAL]], align 4
319319
// CHECK-RV64-NEXT: br label [[RETURN]]
320320
// CHECK-RV64: if.else2:
321-
// 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
321+
// 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
322322
// CHECK-RV64-NEXT: [[TMP7:%.*]] = and i64 [[TMP6]], 2097152
323323
// CHECK-RV64-NEXT: [[TMP8:%.*]] = icmp eq i64 [[TMP7]], 2097152
324324
// CHECK-RV64-NEXT: br i1 [[TMP8]], label [[IF_THEN3:%.*]], label [[IF_ELSE4:%.*]]
325325
// CHECK-RV64: if.then3:
326326
// CHECK-RV64-NEXT: store i32 11, ptr [[RETVAL]], align 4
327327
// CHECK-RV64-NEXT: br label [[RETURN]]
328328
// CHECK-RV64: if.else4:
329-
// 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
329+
// 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
330330
// CHECK-RV64-NEXT: [[TMP10:%.*]] = and i64 [[TMP9]], 8
331331
// CHECK-RV64-NEXT: [[TMP11:%.*]] = icmp eq i64 [[TMP10]], 8
332332
// CHECK-RV64-NEXT: br i1 [[TMP11]], label [[IF_THEN5:%.*]], label [[IF_END:%.*]]

llvm/include/llvm/TargetParser/RISCVISAInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,9 @@ class RISCVISAInfo {
8484
/// <-1, -1> if not supported.
8585
static std::pair<int, int> getRISCVFeaturesBitsInfo(StringRef Ext);
8686

87+
// The maximum value of the group ID obtained from getRISCVFeaturesBitsInfo.
88+
static constexpr unsigned FeatureBitSize = 2;
89+
8790
private:
8891
RISCVISAInfo(unsigned XLen) : XLen(XLen) {}
8992

0 commit comments

Comments
 (0)