[PATCH] D108424: [NFC][clang] Move multiversion resolver code generation to llvm/ subdirectory
a.elovikov added a comment. ping. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108424/new/ https://reviews.llvm.org/D108424 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[PATCH] D108424: [NFC][clang] Move multiversion resolver code generation to llvm/ subdirectory
a.elovikov updated this revision to Diff 369485. a.elovikov added a comment. Rebase + ping Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108424/new/ https://reviews.llvm.org/D108424 Files: clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenModule.cpp llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h llvm/lib/Transforms/Utils/CMakeLists.txt llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp Index: llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp === --- /dev/null +++ llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp @@ -0,0 +1,227 @@ +//===-- X86EmitMultiVersionResolver -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// This file implements utitlities to generate code used for CPU dispatch code. +// +//===--===// + +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/X86TargetParser.h" + +using namespace llvm; +using namespace llvm::X86; + +Value *llvm::formResolverCondition(IRBuilderBase &Builder, + const MultiVersionResolverOption &RO) { + llvm::Value *Condition = nullptr; + + if (!RO.Conditions.Architecture.empty()) +Condition = llvm::X86::emitCpuIs(Builder, RO.Conditions.Architecture); + if (!RO.Conditions.Features.empty()) { +llvm::Value *FeatureCond = +llvm::X86::emitCpuSupports(Builder, RO.Conditions.Features); +Condition = +Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond; + } + return Condition; +} + +static void CreateMultiVersionResolverReturn(Function *Resolver, + IRBuilderBase &Builder, + Function *FuncToReturn, + bool UseIFunc) { + if (UseIFunc) { +Builder.CreateRet(FuncToReturn); +return; + } + + SmallVector Args; + for_each(Resolver->args(), [&](Argument &Arg) { Args.push_back(&Arg); }); + + CallInst *Result = Builder.CreateCall(FuncToReturn, Args); + Result->setTailCallKind(CallInst::TCK_MustTail); + + if (Resolver->getReturnType()->isVoidTy()) +Builder.CreateRetVoid(); + else +Builder.CreateRet(Result); +} + +void llvm::emitMultiVersionResolver( +Function *Resolver, ArrayRef Options, +bool UseIFunc) { + assert(Triple(Resolver->getParent()->getTargetTriple()).isX86() && + "Only implemented for x86 targets"); + + auto &Ctx = Resolver->getContext(); + // Main function's basic block. + BasicBlock *CurBlock = BasicBlock::Create(Ctx, "resolver_entry", Resolver); + + IRBuilder<> Builder(CurBlock, CurBlock->begin()); + llvm::X86::emitCPUInit(Builder); + + for (const MultiVersionResolverOption &RO : Options) { +Builder.SetInsertPoint(CurBlock); +llvm::Value *Condition = formResolverCondition(Builder, RO); + +// The 'default' or 'generic' case. +if (!Condition) { + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); + return; +} + +llvm::BasicBlock *RetBlock = +BasicBlock::Create(Ctx, "resolver_return", Resolver); +{ + IRBuilderBase::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(RetBlock); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); +} +CurBlock = BasicBlock::Create(Ctx, "resolver_else", Resolver); +Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + + // If no generic/default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + CallInst *TrapCall = Builder.CreateIntrinsic(Intrinsic::trap, {}, {}); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); +} + +static Type *getCpuModelType(IRBuilderBase &Builder) { + Type *Int32Ty = Builder.getInt32Ty(); + + // Matching the struct layout from the compiler-rt/libgcc structure that is + // filled in: + // unsigned int __cpu_vendor; + // unsigned int __cpu_type; + // unsigned int __cpu_subtype; + // unsigned int __cpu_features[1]; + Type *STy = + StructType::get(Int32Ty, Int32Ty, Int32Ty, ArrayType::get(Int32Ty, 1)); + return STy; +} + +static Value *getOrCreateGlobal(IRBuilderBase &Builder, StringRef Name, +
[PATCH] D108424: [NFC][clang] Move multiversion resolver code generation to llvm/ subdirectory
a.elovikov updated this revision to Diff 367890. a.elovikov added a comment. Fix a bug with not saving builder's insertion point. Repository: rG LLVM Github Monorepo CHANGES SINCE LAST ACTION https://reviews.llvm.org/D108424/new/ https://reviews.llvm.org/D108424 Files: clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenModule.cpp llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h llvm/lib/Transforms/Utils/CMakeLists.txt llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp Index: llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp === --- /dev/null +++ llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp @@ -0,0 +1,227 @@ +//===-- X86EmitMultiVersionResolver -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// This file implements utitlities to generate code used for CPU dispatch code. +// +//===--===// + +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/X86TargetParser.h" + +using namespace llvm; +using namespace llvm::X86; + +Value *llvm::formResolverCondition(IRBuilderBase &Builder, + const MultiVersionResolverOption &RO) { + llvm::Value *Condition = nullptr; + + if (!RO.Conditions.Architecture.empty()) +Condition = llvm::X86::emitCpuIs(Builder, RO.Conditions.Architecture); + if (!RO.Conditions.Features.empty()) { +llvm::Value *FeatureCond = +llvm::X86::emitCpuSupports(Builder, RO.Conditions.Features); +Condition = +Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond; + } + return Condition; +} + +static void CreateMultiVersionResolverReturn(Function *Resolver, + IRBuilderBase &Builder, + Function *FuncToReturn, + bool UseIFunc) { + if (UseIFunc) { +Builder.CreateRet(FuncToReturn); +return; + } + + SmallVector Args; + for_each(Resolver->args(), [&](Argument &Arg) { Args.push_back(&Arg); }); + + CallInst *Result = Builder.CreateCall(FuncToReturn, Args); + Result->setTailCallKind(CallInst::TCK_MustTail); + + if (Resolver->getReturnType()->isVoidTy()) +Builder.CreateRetVoid(); + else +Builder.CreateRet(Result); +} + +void llvm::emitMultiVersionResolver( +Function *Resolver, ArrayRef Options, +bool UseIFunc) { + assert(Triple(Resolver->getParent()->getTargetTriple()).isX86() && + "Only implemented for x86 targets"); + + auto &Ctx = Resolver->getContext(); + // Main function's basic block. + BasicBlock *CurBlock = BasicBlock::Create(Ctx, "resolver_entry", Resolver); + + IRBuilder<> Builder(CurBlock, CurBlock->begin()); + llvm::X86::emitCPUInit(Builder); + + for (const MultiVersionResolverOption &RO : Options) { +Builder.SetInsertPoint(CurBlock); +llvm::Value *Condition = formResolverCondition(Builder, RO); + +// The 'default' or 'generic' case. +if (!Condition) { + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); + return; +} + +llvm::BasicBlock *RetBlock = +BasicBlock::Create(Ctx, "resolver_return", Resolver); +{ + IRBuilderBase::InsertPointGuard Guard(Builder); + Builder.SetInsertPoint(RetBlock); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); +} +CurBlock = BasicBlock::Create(Ctx, "resolver_else", Resolver); +Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + + // If no generic/default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + CallInst *TrapCall = Builder.CreateIntrinsic(Intrinsic::trap, {}, {}); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); +} + +static Type *getCpuModelType(IRBuilderBase &Builder) { + Type *Int32Ty = Builder.getInt32Ty(); + + // Matching the struct layout from the compiler-rt/libgcc structure that is + // filled in: + // unsigned int __cpu_vendor; + // unsigned int __cpu_type; + // unsigned int __cpu_subtype; + // unsigned int __cpu_features[1]; + Type *STy = + StructType::get(Int32Ty, Int32Ty, Int32Ty, ArrayType::get(Int32Ty, 1)); + return STy; +} + +static Value *getOrCreateGlobal(IRBuilderBase &Builder, StringRef
[PATCH] D108424: [NFC][clang] Move multiversion resolver code generation to llvm/ subdirectory
a.elovikov created this revision. a.elovikov added reviewers: erichkeane, craig.topper. Herald added subscribers: pengfei, hiraditya, tpr, mgorny. a.elovikov requested review of this revision. Herald added projects: clang, LLVM. Herald added subscribers: llvm-commits, cfe-commits. Some part of the target multiversioning support already resided in llvm/lib/Support/X86TargetParser.cpp. However, the IR generation could not be put there because of the component dependencies. I think Transforms/Utils is a good place to put such kind of utils similar to AmdGPUEmitPrintf functionality there. The change can allow the use of the functionality outside clang as it isn't C/C++-specific. Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D108424 Files: clang/lib/CodeGen/CGBuiltin.cpp clang/lib/CodeGen/CodeGenFunction.cpp clang/lib/CodeGen/CodeGenFunction.h clang/lib/CodeGen/CodeGenModule.cpp llvm/include/llvm/Transforms/Utils/X86EmitMultiVersionResolver.h llvm/lib/Transforms/Utils/CMakeLists.txt llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp Index: llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp === --- /dev/null +++ llvm/lib/Transforms/Utils/X86EmitMultiVersionResolver.cpp @@ -0,0 +1,224 @@ +//===-- X86EmitMultiVersionResolver -*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===--===// +// +// This file implements utitlities to generate code used for CPU dispatch code. +// +//===--===// + +#include "llvm/Transforms/Utils/X86EmitMultiVersionResolver.h" +#include "llvm/ADT/StringSwitch.h" +#include "llvm/IR/Function.h" +#include "llvm/IR/IRBuilder.h" +#include "llvm/IR/Type.h" +#include "llvm/Support/X86TargetParser.h" + +using namespace llvm; +using namespace llvm::X86; + +Value *llvm::formResolverCondition(IRBuilderBase &Builder, +const MultiVersionResolverOption &RO) { + llvm::Value *Condition = nullptr; + + if (!RO.Conditions.Architecture.empty()) +Condition = llvm::X86::emitCpuIs(Builder, RO.Conditions.Architecture); + if (!RO.Conditions.Features.empty()) { +llvm::Value *FeatureCond = +llvm::X86::emitCpuSupports(Builder, RO.Conditions.Features); +Condition = +Condition ? Builder.CreateAnd(Condition, FeatureCond) : FeatureCond; + } + return Condition; +} + +static void CreateMultiVersionResolverReturn(Function *Resolver, + IRBuilderBase &Builder, + Function *FuncToReturn, + bool UseIFunc) { + if (UseIFunc) { +Builder.CreateRet(FuncToReturn); +return; + } + + SmallVector Args; + for_each(Resolver->args(), [&](Argument &Arg) { Args.push_back(&Arg); }); + + CallInst *Result = Builder.CreateCall(FuncToReturn, Args); + Result->setTailCallKind(CallInst::TCK_MustTail); + + if (Resolver->getReturnType()->isVoidTy()) +Builder.CreateRetVoid(); + else +Builder.CreateRet(Result); +} + +void llvm::emitMultiVersionResolver( +Function *Resolver, ArrayRef Options, +bool UseIFunc) { + assert(Triple(Resolver->getParent()->getTargetTriple()).isX86() && + "Only implemented for x86 targets"); + + auto &Ctx = Resolver->getContext(); + // Main function's basic block. + BasicBlock *CurBlock = BasicBlock::Create(Ctx, "resolver_entry", Resolver); + + IRBuilder<> Builder(CurBlock, CurBlock->begin()); + llvm::X86::emitCPUInit(Builder); + + for (const MultiVersionResolverOption &RO : Options) { +Builder.SetInsertPoint(CurBlock); +llvm::Value *Condition = formResolverCondition(Builder, RO); + +// The 'default' or 'generic' case. +if (!Condition) { + assert(&RO == Options.end() - 1 && + "Default or Generic case must be last"); + CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); + return; +} + +llvm::BasicBlock *RetBlock = +BasicBlock::Create(Ctx, "resolver_return", Resolver); +Builder.SetInsertPoint(RetBlock); +CreateMultiVersionResolverReturn(Resolver, Builder, RO.Fn, UseIFunc); +CurBlock = BasicBlock::Create(Ctx, "resolver_else", Resolver); +Builder.CreateCondBr(Condition, RetBlock, CurBlock); + } + + // If no generic/default, emit an unreachable. + Builder.SetInsertPoint(CurBlock); + CallInst *TrapCall = Builder.CreateIntrinsic(Intrinsic::trap, {}, {}); + TrapCall->setDoesNotReturn(); + TrapCall->setDoesNotThrow(); + Builder.CreateUnreachable(); +} + +static Type *getCpuModelType(IRBuilderBase &Builder) { + Type *Int32Ty = Builder.getInt32Ty()