[PATCH] D108424: [NFC][clang] Move multiversion resolver code generation to llvm/ subdirectory

2021-09-03 Thread Andrei Elovikov via Phabricator via cfe-commits
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

2021-08-30 Thread Andrei Elovikov via Phabricator via cfe-commits
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

2021-08-20 Thread Andrei Elovikov via Phabricator via cfe-commits
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

2021-08-19 Thread Andrei Elovikov via Phabricator via cfe-commits
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()