aboutsummaryrefslogtreecommitdiff
path: root/clang/lib/CodeGen/CodeGenFunction.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'clang/lib/CodeGen/CodeGenFunction.cpp')
-rw-r--r--clang/lib/CodeGen/CodeGenFunction.cpp134
1 files changed, 133 insertions, 1 deletions
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index fae26d1..eda96f3 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -2889,10 +2889,142 @@ void CodeGenFunction::EmitMultiVersionResolver(
case llvm::Triple::aarch64:
EmitAArch64MultiVersionResolver(Resolver, Options);
return;
+ case llvm::Triple::riscv32:
+ case llvm::Triple::riscv64:
+ EmitRISCVMultiVersionResolver(Resolver, Options);
+ return;
default:
- assert(false && "Only implemented for x86 and AArch64 targets");
+ assert(false && "Only implemented for x86, AArch64 and RISC-V targets");
+ }
+}
+
+static int getPriorityFromAttrString(StringRef AttrStr) {
+ SmallVector<StringRef, 8> Attrs;
+
+ AttrStr.split(Attrs, ';');
+
+ // Default Priority is zero.
+ int Priority = 0;
+ for (auto Attr : Attrs) {
+ if (Attr.consume_front("priority=")) {
+ int Result;
+ if (!Attr.getAsInteger(0, Result)) {
+ Priority = Result;
+ }
+ }
+ }
+
+ return Priority;
+}
+
+void CodeGenFunction::EmitRISCVMultiVersionResolver(
+ llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
+
+ if (getContext().getTargetInfo().getTriple().getOS() !=
+ llvm::Triple::OSType::Linux) {
+ CGM.getDiags().Report(diag::err_os_unsupport_riscv_fmv);
+ return;
}
+
+ llvm::BasicBlock *CurBlock = createBasicBlock("resolver_entry", Resolver);
+ Builder.SetInsertPoint(CurBlock);
+ EmitRISCVCpuInit();
+
+ bool SupportsIFunc = getContext().getTargetInfo().supportsIFunc();
+ bool HasDefault = false;
+ unsigned DefaultIndex = 0;
+
+ SmallVector<CodeGenFunction::MultiVersionResolverOption, 10> CurrOptions(
+ Options);
+
+ llvm::stable_sort(
+ CurrOptions, [](const CodeGenFunction::MultiVersionResolverOption &LHS,
+ const CodeGenFunction::MultiVersionResolverOption &RHS) {
+ return getPriorityFromAttrString(LHS.Conditions.Features[0]) >
+ getPriorityFromAttrString(RHS.Conditions.Features[0]);
+ });
+
+ // Check the each candidate function.
+ for (unsigned Index = 0; Index < CurrOptions.size(); Index++) {
+
+ if (CurrOptions[Index].Conditions.Features[0].starts_with("default")) {
+ HasDefault = true;
+ DefaultIndex = Index;
+ continue;
+ }
+
+ Builder.SetInsertPoint(CurBlock);
+
+ std::vector<std::string> TargetAttrFeats =
+ getContext()
+ .getTargetInfo()
+ .parseTargetAttr(CurrOptions[Index].Conditions.Features[0])
+ .Features;
+
+ if (TargetAttrFeats.empty())
+ continue;
+
+ // FeaturesCondition: The bitmask of the required extension has been
+ // enabled by the runtime object.
+ // (__riscv_feature_bits.features[i] & REQUIRED_BITMASK) ==
+ // REQUIRED_BITMASK
+ //
+ // When condition is met, return this version of the function.
+ // Otherwise, try the next version.
+ //
+ // if (FeaturesConditionVersion1)
+ // return Version1;
+ // else if (FeaturesConditionVersion2)
+ // return Version2;
+ // else if (FeaturesConditionVersion3)
+ // return Version3;
+ // ...
+ // else
+ // return DefaultVersion;
+
+ // TODO: Add a condition to check the length before accessing elements.
+ // Without checking the length first, we may access an incorrect memory
+ // address when using different versions.
+ llvm::SmallVector<StringRef, 8> CurrTargetAttrFeats;
+
+ for (auto &Feat : TargetAttrFeats) {
+ StringRef CurrFeat = Feat;
+ if (CurrFeat.starts_with('+'))
+ CurrTargetAttrFeats.push_back(CurrFeat.substr(1));
+ }
+
+ Builder.SetInsertPoint(CurBlock);
+ llvm::Value *FeatsCondition = EmitRISCVCpuSupports(CurrTargetAttrFeats);
+
+ llvm::BasicBlock *RetBlock = createBasicBlock("resolver_return", Resolver);
+ CGBuilderTy RetBuilder(*this, RetBlock);
+ CreateMultiVersionResolverReturn(
+ CGM, Resolver, RetBuilder, CurrOptions[Index].Function, SupportsIFunc);
+ llvm::BasicBlock *ElseBlock = createBasicBlock("resolver_else", Resolver);
+
+ Builder.SetInsertPoint(CurBlock);
+ Builder.CreateCondBr(FeatsCondition, RetBlock, ElseBlock);
+
+ CurBlock = ElseBlock;
+ }
+
+ // Finally, emit the default one.
+ if (HasDefault) {
+ Builder.SetInsertPoint(CurBlock);
+ CreateMultiVersionResolverReturn(CGM, Resolver, Builder,
+ CurrOptions[DefaultIndex].Function,
+ SupportsIFunc);
+ return;
+ }
+
+ // If no generic/default, emit an unreachable.
+ Builder.SetInsertPoint(CurBlock);
+ llvm::CallInst *TrapCall = EmitTrapCall(llvm::Intrinsic::trap);
+ TrapCall->setDoesNotReturn();
+ TrapCall->setDoesNotThrow();
+ Builder.CreateUnreachable();
+ Builder.ClearInsertionPoint();
}
void CodeGenFunction::EmitAArch64MultiVersionResolver(