@@ -2850,10 +2850,121 @@ void CodeGenFunction::EmitMultiVersionResolver(
28502850 case llvm::Triple::aarch64:
28512851 EmitAArch64MultiVersionResolver (Resolver, Options);
28522852 return ;
2853+ case llvm::Triple::riscv32:
2854+ case llvm::Triple::riscv64:
2855+ EmitRISCVMultiVersionResolver (Resolver, Options);
2856+ return ;
28532857
28542858 default :
2855- assert (false && " Only implemented for x86 and AArch64 targets" );
2859+ assert (false && " Only implemented for x86, AArch64 and RISC-V targets" );
2860+ }
2861+ }
2862+
2863+ void CodeGenFunction::EmitRISCVMultiVersionResolver (
2864+ llvm::Function *Resolver, ArrayRef<MultiVersionResolverOption> Options) {
2865+
2866+ if (getContext ().getTargetInfo ().getTriple ().getOS () !=
2867+ llvm::Triple::OSType::Linux) {
2868+ CGM.getDiags ().Report (diag::err_os_unsupport_riscv_target_clones);
2869+ return ;
2870+ }
2871+
2872+ llvm::BasicBlock *EntryBlock = createBasicBlock (" resolver_entry" , Resolver);
2873+ Builder.SetInsertPoint (EntryBlock);
2874+ EmitRISCVCpuInit ();
2875+
2876+ llvm::BasicBlock *CurBlock = createBasicBlock (" resolver_cond" , Resolver);
2877+ llvm::BasicBlock *FirstCond = CurBlock;
2878+
2879+ bool SupportsIFunc = getContext ().getTargetInfo ().supportsIFunc ();
2880+ bool HasDefault = false ;
2881+ int DefaultIndex = 0 ;
2882+ // Check the each candidate function.
2883+ for (unsigned Index = 0 ; Index < Options.size (); Index++) {
2884+
2885+ if (Options[Index].Conditions .Features [0 ].starts_with (" default" )) {
2886+ HasDefault = true ;
2887+ DefaultIndex = Index;
2888+ continue ;
2889+ }
2890+
2891+ Builder.SetInsertPoint (CurBlock);
2892+
2893+ std::vector<std::string> TargetAttrFeats =
2894+ getContext ()
2895+ .getTargetInfo ()
2896+ .parseTargetAttr (Options[Index].Conditions .Features [0 ])
2897+ .Features ;
2898+
2899+ if (!TargetAttrFeats.empty ()) {
2900+ // If this function doens't need override, then merge with module level
2901+ // target features. Otherwise, remain the current target features.
2902+ auto I = llvm::find (TargetAttrFeats, " +__RISCV_TargetAttrNeedOverride" );
2903+ if (I == TargetAttrFeats.end ())
2904+ TargetAttrFeats.insert (TargetAttrFeats.begin (),
2905+ Target.getTargetOpts ().FeaturesAsWritten .begin (),
2906+ Target.getTargetOpts ().FeaturesAsWritten .end ());
2907+ else
2908+ TargetAttrFeats.erase (I);
2909+
2910+ // Only consider +<extension-feature>.
2911+ llvm::SmallVector<StringRef, 8 > PlusTargetAttrFeats;
2912+ for (StringRef Feat : TargetAttrFeats) {
2913+ if (!getContext ().getTargetInfo ().isValidFeatureName (
2914+ Feat.substr (1 ).str ()))
2915+ continue ;
2916+ if (Feat.starts_with (" +" ))
2917+ PlusTargetAttrFeats.push_back (Feat.substr (1 ));
2918+ }
2919+
2920+ llvm::Value *Condition = EmitRISCVCpuSupports (PlusTargetAttrFeats);
2921+ llvm::BasicBlock *RetBlock =
2922+ createBasicBlock (" resolver_return" , Resolver);
2923+ CGBuilderTy RetBuilder (*this , RetBlock);
2924+ CreateMultiVersionResolverReturn (CGM, Resolver, RetBuilder,
2925+ Options[Index].Function , SupportsIFunc);
2926+ CurBlock = createBasicBlock (" resolver_else" , Resolver);
2927+ Builder.CreateCondBr (Condition, RetBlock, CurBlock);
2928+ }
2929+ }
2930+
2931+ // Finally, emit the default one.
2932+ if (HasDefault) {
2933+ Builder.SetInsertPoint (CurBlock);
2934+ CreateMultiVersionResolverReturn (
2935+ CGM, Resolver, Builder, Options[DefaultIndex].Function , SupportsIFunc);
2936+
2937+ Builder.SetInsertPoint (EntryBlock);
2938+ const unsigned FeatureBitSize = 2 ;
2939+ llvm::ArrayType *ArrayOfInt64Ty =
2940+ llvm::ArrayType::get (Int64Ty, FeatureBitSize);
2941+ llvm::Type *StructTy = llvm::StructType::get (Int32Ty, ArrayOfInt64Ty);
2942+ llvm::Constant *RISCVFeaturesBits =
2943+ CGM.CreateRuntimeVariable (StructTy, " __riscv_feature_bits" );
2944+ cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal (true );
2945+ std::vector<llvm::Value *> GEPIndices = {
2946+ llvm::ConstantInt::get (Int32Ty, 0 ), llvm::ConstantInt::get (Int32Ty, 0 )};
2947+ llvm::Value *Ptr =
2948+ Builder.CreateInBoundsGEP (StructTy, RISCVFeaturesBits, GEPIndices);
2949+ llvm::Value *Length =
2950+ Builder.CreateAlignedLoad (Int32Ty, Ptr, CharUnits::fromQuantity (8 ));
2951+
2952+ llvm::Value *FeatureBitSizeVal =
2953+ llvm::ConstantInt::get (Int32Ty, FeatureBitSize);
2954+ llvm::Value *Result = Builder.CreateICmpULE (Length, FeatureBitSizeVal);
2955+
2956+ Builder.CreateCondBr (Result, FirstCond, CurBlock);
2957+
2958+ return ;
28562959 }
2960+
2961+ // If no generic/default, emit an unreachable.
2962+ Builder.SetInsertPoint (CurBlock);
2963+ llvm::CallInst *TrapCall = EmitTrapCall (llvm::Intrinsic::trap);
2964+ TrapCall->setDoesNotReturn ();
2965+ TrapCall->setDoesNotThrow ();
2966+ Builder.CreateUnreachable ();
2967+ Builder.ClearInsertionPoint ();
28572968}
28582969
28592970void CodeGenFunction::EmitAArch64MultiVersionResolver (
0 commit comments