diff options
Diffstat (limited to 'clang/lib/CodeGen/CodeGenFunction.cpp')
-rw-r--r-- | clang/lib/CodeGen/CodeGenFunction.cpp | 134 |
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( |