brintos

brintos / llvm-project-archived public Read only

0
0
Text · 17.7 KiB · 1518ead Raw
488 lines · cpp
1//===-- IntrinsicLowering.cpp - Intrinsic Lowering default implementation -===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the IntrinsicLowering class.10//11//===----------------------------------------------------------------------===//12 13#include "llvm/CodeGen/IntrinsicLowering.h"14#include "llvm/ADT/SmallVector.h"15#include "llvm/IR/Constants.h"16#include "llvm/IR/DataLayout.h"17#include "llvm/IR/DerivedTypes.h"18#include "llvm/IR/IRBuilder.h"19#include "llvm/IR/Module.h"20#include "llvm/IR/Type.h"21#include "llvm/Support/ErrorHandling.h"22#include "llvm/Support/raw_ostream.h"23using namespace llvm;24 25/// This function is used when we want to lower an intrinsic call to a call of26/// an external function. This handles hard cases such as when there was already27/// a prototype for the external function, but that prototype doesn't match the28/// arguments we expect to pass in.29template <class ArgIt>30static CallInst *ReplaceCallWith(const char *NewFn, CallInst *CI,31                                 ArgIt ArgBegin, ArgIt ArgEnd,32                                 Type *RetTy) {33  // If we haven't already looked up this function, check to see if the34  // program already contains a function with this name.35  Module *M = CI->getModule();36  // Get or insert the definition now.37  std::vector<Type *> ParamTys;38  for (ArgIt I = ArgBegin; I != ArgEnd; ++I)39    ParamTys.push_back((*I)->getType());40  FunctionCallee FCache =41      M->getOrInsertFunction(NewFn, FunctionType::get(RetTy, ParamTys, false));42 43  IRBuilder<> Builder(CI->getParent(), CI->getIterator());44  SmallVector<Value *, 8> Args(ArgBegin, ArgEnd);45  CallInst *NewCI = Builder.CreateCall(FCache, Args);46  NewCI->setName(CI->getName());47  if (!CI->use_empty())48    CI->replaceAllUsesWith(NewCI);49  return NewCI;50}51 52/// Emit the code to lower bswap of V before the specified instruction IP.53static Value *LowerBSWAP(LLVMContext &Context, Value *V, Instruction *IP) {54  assert(V->getType()->isIntOrIntVectorTy() && "Can't bswap a non-integer type!");55 56  unsigned BitSize = V->getType()->getScalarSizeInBits();57 58  IRBuilder<> Builder(IP);59 60  switch(BitSize) {61  default: llvm_unreachable("Unhandled type size of value to byteswap!");62  case 16: {63    Value *Tmp1 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 8),64                                    "bswap.2");65    Value *Tmp2 = Builder.CreateLShr(V, ConstantInt::get(V->getType(), 8),66                                     "bswap.1");67    V = Builder.CreateOr(Tmp1, Tmp2, "bswap.i16");68    break;69  }70  case 32: {71    Value *Tmp4 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 24),72                                    "bswap.4");73    Value *Tmp3 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 8),74                                    "bswap.3");75    Value *Tmp2 = Builder.CreateLShr(V, ConstantInt::get(V->getType(), 8),76                                     "bswap.2");77    Value *Tmp1 = Builder.CreateLShr(V,ConstantInt::get(V->getType(), 24),78                                     "bswap.1");79    Tmp3 = Builder.CreateAnd(Tmp3,80                         ConstantInt::get(V->getType(), 0xFF0000),81                             "bswap.and3");82    Tmp2 = Builder.CreateAnd(Tmp2,83                           ConstantInt::get(V->getType(), 0xFF00),84                             "bswap.and2");85    Tmp4 = Builder.CreateOr(Tmp4, Tmp3, "bswap.or1");86    Tmp2 = Builder.CreateOr(Tmp2, Tmp1, "bswap.or2");87    V = Builder.CreateOr(Tmp4, Tmp2, "bswap.i32");88    break;89  }90  case 64: {91    Value *Tmp8 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 56),92                                    "bswap.8");93    Value *Tmp7 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 40),94                                    "bswap.7");95    Value *Tmp6 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 24),96                                    "bswap.6");97    Value *Tmp5 = Builder.CreateShl(V, ConstantInt::get(V->getType(), 8),98                                    "bswap.5");99    Value* Tmp4 = Builder.CreateLShr(V, ConstantInt::get(V->getType(), 8),100                                     "bswap.4");101    Value* Tmp3 = Builder.CreateLShr(V,102                                     ConstantInt::get(V->getType(), 24),103                                     "bswap.3");104    Value* Tmp2 = Builder.CreateLShr(V,105                                     ConstantInt::get(V->getType(), 40),106                                     "bswap.2");107    Value* Tmp1 = Builder.CreateLShr(V,108                                     ConstantInt::get(V->getType(), 56),109                                     "bswap.1");110    Tmp7 = Builder.CreateAnd(Tmp7,111                             ConstantInt::get(V->getType(),112                                              0xFF000000000000ULL),113                             "bswap.and7");114    Tmp6 = Builder.CreateAnd(Tmp6,115                             ConstantInt::get(V->getType(),116                                              0xFF0000000000ULL),117                             "bswap.and6");118    Tmp5 = Builder.CreateAnd(Tmp5,119                        ConstantInt::get(V->getType(),120                             0xFF00000000ULL),121                             "bswap.and5");122    Tmp4 = Builder.CreateAnd(Tmp4,123                        ConstantInt::get(V->getType(),124                             0xFF000000ULL),125                             "bswap.and4");126    Tmp3 = Builder.CreateAnd(Tmp3,127                             ConstantInt::get(V->getType(),128                             0xFF0000ULL),129                             "bswap.and3");130    Tmp2 = Builder.CreateAnd(Tmp2,131                             ConstantInt::get(V->getType(),132                             0xFF00ULL),133                             "bswap.and2");134    Tmp8 = Builder.CreateOr(Tmp8, Tmp7, "bswap.or1");135    Tmp6 = Builder.CreateOr(Tmp6, Tmp5, "bswap.or2");136    Tmp4 = Builder.CreateOr(Tmp4, Tmp3, "bswap.or3");137    Tmp2 = Builder.CreateOr(Tmp2, Tmp1, "bswap.or4");138    Tmp8 = Builder.CreateOr(Tmp8, Tmp6, "bswap.or5");139    Tmp4 = Builder.CreateOr(Tmp4, Tmp2, "bswap.or6");140    V = Builder.CreateOr(Tmp8, Tmp4, "bswap.i64");141    break;142  }143  }144  return V;145}146 147/// Emit the code to lower ctpop of V before the specified instruction IP.148static Value *LowerCTPOP(LLVMContext &Context, Value *V, Instruction *IP) {149  assert(V->getType()->isIntegerTy() && "Can't ctpop a non-integer type!");150 151  static const uint64_t MaskValues[6] = {152    0x5555555555555555ULL, 0x3333333333333333ULL,153    0x0F0F0F0F0F0F0F0FULL, 0x00FF00FF00FF00FFULL,154    0x0000FFFF0000FFFFULL, 0x00000000FFFFFFFFULL155  };156 157  IRBuilder<> Builder(IP);158 159  unsigned BitSize = V->getType()->getPrimitiveSizeInBits();160  unsigned WordSize = (BitSize + 63) / 64;161  Value *Count = ConstantInt::get(V->getType(), 0);162 163  for (unsigned n = 0; n < WordSize; ++n) {164    Value *PartValue = V;165    for (unsigned i = 1, ct = 0; i < (BitSize>64 ? 64 : BitSize);166         i <<= 1, ++ct) {167      Value *MaskCst = ConstantInt::get(V->getType(), MaskValues[ct]);168      Value *LHS = Builder.CreateAnd(PartValue, MaskCst, "cppop.and1");169      Value *VShift = Builder.CreateLShr(PartValue,170                                        ConstantInt::get(V->getType(), i),171                                         "ctpop.sh");172      Value *RHS = Builder.CreateAnd(VShift, MaskCst, "cppop.and2");173      PartValue = Builder.CreateAdd(LHS, RHS, "ctpop.step");174    }175    Count = Builder.CreateAdd(PartValue, Count, "ctpop.part");176    if (BitSize > 64) {177      V = Builder.CreateLShr(V, ConstantInt::get(V->getType(), 64),178                             "ctpop.part.sh");179      BitSize -= 64;180    }181  }182 183  return Count;184}185 186/// Emit the code to lower ctlz of V before the specified instruction IP.187static Value *LowerCTLZ(LLVMContext &Context, Value *V, Instruction *IP) {188 189  IRBuilder<> Builder(IP);190 191  unsigned BitSize = V->getType()->getPrimitiveSizeInBits();192  for (unsigned i = 1; i < BitSize; i <<= 1) {193    Value *ShVal = ConstantInt::get(V->getType(), i);194    ShVal = Builder.CreateLShr(V, ShVal, "ctlz.sh");195    V = Builder.CreateOr(V, ShVal, "ctlz.step");196  }197 198  V = Builder.CreateNot(V);199  return LowerCTPOP(Context, V, IP);200}201 202static void ReplaceFPIntrinsicWithCall(CallInst *CI, const char *Fname,203                                       const char *Dname,204                                       const char *LDname) {205  switch (CI->getArgOperand(0)->getType()->getTypeID()) {206  default: llvm_unreachable("Invalid type in intrinsic");207  case Type::FloatTyID:208    ReplaceCallWith(Fname, CI, CI->arg_begin(), CI->arg_end(),209                    Type::getFloatTy(CI->getContext()));210    break;211  case Type::DoubleTyID:212    ReplaceCallWith(Dname, CI, CI->arg_begin(), CI->arg_end(),213                    Type::getDoubleTy(CI->getContext()));214    break;215  case Type::X86_FP80TyID:216  case Type::FP128TyID:217  case Type::PPC_FP128TyID:218    ReplaceCallWith(LDname, CI, CI->arg_begin(), CI->arg_end(),219                    CI->getArgOperand(0)->getType());220    break;221  }222}223 224void IntrinsicLowering::LowerIntrinsicCall(CallInst *CI) {225  IRBuilder<> Builder(CI);226  LLVMContext &Context = CI->getContext();227 228  const Function *Callee = CI->getCalledFunction();229  assert(Callee && "Cannot lower an indirect call!");230 231  switch (Callee->getIntrinsicID()) {232  case Intrinsic::not_intrinsic:233    report_fatal_error("Cannot lower a call to a non-intrinsic function '"+234                      Callee->getName() + "'!");235  default:236    report_fatal_error("Code generator does not support intrinsic function '"+237                      Callee->getName()+"'!");238 239  case Intrinsic::expect:240  case Intrinsic::expect_with_probability: {241    // Just replace __builtin_expect(exp, c) and242    // __builtin_expect_with_probability(exp, c, p) with EXP.243    Value *V = CI->getArgOperand(0);244    CI->replaceAllUsesWith(V);245    break;246  }247 248  case Intrinsic::allow_runtime_check:249  case Intrinsic::allow_ubsan_check:250    CI->replaceAllUsesWith(ConstantInt::getTrue(CI->getType()));251    return;252 253  case Intrinsic::ctpop:254    CI->replaceAllUsesWith(LowerCTPOP(Context, CI->getArgOperand(0), CI));255    break;256 257  case Intrinsic::bswap:258    CI->replaceAllUsesWith(LowerBSWAP(Context, CI->getArgOperand(0), CI));259    break;260 261  case Intrinsic::ctlz:262    CI->replaceAllUsesWith(LowerCTLZ(Context, CI->getArgOperand(0), CI));263    break;264 265  case Intrinsic::cttz: {266    // cttz(x) -> ctpop(~X & (X-1))267    Value *Src = CI->getArgOperand(0);268    Value *NotSrc = Builder.CreateNot(Src);269    NotSrc->setName(Src->getName() + ".not");270    Value *SrcM1 = ConstantInt::get(Src->getType(), 1);271    SrcM1 = Builder.CreateSub(Src, SrcM1);272    Src = LowerCTPOP(Context, Builder.CreateAnd(NotSrc, SrcM1), CI);273    CI->replaceAllUsesWith(Src);274    break;275  }276 277  case Intrinsic::stacksave:278  case Intrinsic::stackrestore: {279    if (!Warned)280      errs() << "WARNING: this target does not support the llvm.stack"281             << (Callee->getIntrinsicID() == Intrinsic::stacksave ?282               "save" : "restore") << " intrinsic.\n";283    Warned = true;284    if (Callee->getIntrinsicID() == Intrinsic::stacksave)285      CI->replaceAllUsesWith(Constant::getNullValue(CI->getType()));286    break;287  }288 289  case Intrinsic::get_dynamic_area_offset:290    errs() << "WARNING: this target does not support the custom llvm.get."291              "dynamic.area.offset.  It is being lowered to a constant 0\n";292    // Just lower it to a constant 0 because for most targets293    // @llvm.get.dynamic.area.offset is lowered to zero.294    CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 0));295    break;296  case Intrinsic::returnaddress:297  case Intrinsic::frameaddress:298    errs() << "WARNING: this target does not support the llvm."299           << (Callee->getIntrinsicID() == Intrinsic::returnaddress ?300             "return" : "frame") << "address intrinsic.\n";301    CI->replaceAllUsesWith(302        ConstantPointerNull::get(cast<PointerType>(CI->getType())));303    break;304  case Intrinsic::addressofreturnaddress:305    errs() << "WARNING: this target does not support the "306              "llvm.addressofreturnaddress intrinsic.\n";307    CI->replaceAllUsesWith(308        ConstantPointerNull::get(cast<PointerType>(CI->getType())));309    break;310 311  case Intrinsic::prefetch:312    break;    // Simply strip out prefetches on unsupported architectures313 314  case Intrinsic::pcmarker:315    break;    // Simply strip out pcmarker on unsupported architectures316  case Intrinsic::readcyclecounter: {317    errs() << "WARNING: this target does not support the llvm.readcyclecoun"318           << "ter intrinsic.  It is being lowered to a constant 0\n";319    CI->replaceAllUsesWith(ConstantInt::get(Type::getInt64Ty(Context), 0));320    break;321  }322  case Intrinsic::readsteadycounter: {323    errs() << "WARNING: this target does not support the llvm.readsteadycounter"324           << " intrinsic.  It is being lowered to a constant 0\n";325    CI->replaceAllUsesWith(ConstantInt::get(Type::getInt64Ty(Context), 0));326    break;327  }328 329  case Intrinsic::dbg_declare:330  case Intrinsic::dbg_label:331    break;    // Simply strip out debugging intrinsics332 333  case Intrinsic::eh_typeid_for:334    // Return something different to eh_selector.335    CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 1));336    break;337 338  case Intrinsic::annotation:339  case Intrinsic::ptr_annotation:340    // Just drop the annotation, but forward the value341    CI->replaceAllUsesWith(CI->getOperand(0));342    break;343 344  case Intrinsic::assume:345  case Intrinsic::experimental_noalias_scope_decl:346  case Intrinsic::var_annotation:347    break;   // Strip out these intrinsics348 349  case Intrinsic::memcpy: {350    Type *IntPtr = DL.getIntPtrType(Context);351    Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr,352                                        /* isSigned */ false);353    Value *Ops[3];354    Ops[0] = CI->getArgOperand(0);355    Ops[1] = CI->getArgOperand(1);356    Ops[2] = Size;357    ReplaceCallWith("memcpy", CI, Ops, Ops+3, CI->getArgOperand(0)->getType());358    break;359  }360  case Intrinsic::memmove: {361    Type *IntPtr = DL.getIntPtrType(Context);362    Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr,363                                        /* isSigned */ false);364    Value *Ops[3];365    Ops[0] = CI->getArgOperand(0);366    Ops[1] = CI->getArgOperand(1);367    Ops[2] = Size;368    ReplaceCallWith("memmove", CI, Ops, Ops+3, CI->getArgOperand(0)->getType());369    break;370  }371  case Intrinsic::memset: {372    Value *Op0 = CI->getArgOperand(0);373    Type *IntPtr = DL.getIntPtrType(Op0->getType());374    Value *Size = Builder.CreateIntCast(CI->getArgOperand(2), IntPtr,375                                        /* isSigned */ false);376    Value *Ops[3];377    Ops[0] = Op0;378    // Extend the amount to i32.379    Ops[1] = Builder.CreateIntCast(CI->getArgOperand(1),380                                   Type::getInt32Ty(Context),381                                   /* isSigned */ false);382    Ops[2] = Size;383    ReplaceCallWith("memset", CI, Ops, Ops+3, CI->getArgOperand(0)->getType());384    break;385  }386  case Intrinsic::sqrt: {387    ReplaceFPIntrinsicWithCall(CI, "sqrtf", "sqrt", "sqrtl");388    break;389  }390  case Intrinsic::log: {391    ReplaceFPIntrinsicWithCall(CI, "logf", "log", "logl");392    break;393  }394  case Intrinsic::log2: {395    ReplaceFPIntrinsicWithCall(CI, "log2f", "log2", "log2l");396    break;397  }398  case Intrinsic::log10: {399    ReplaceFPIntrinsicWithCall(CI, "log10f", "log10", "log10l");400    break;401  }402  case Intrinsic::exp: {403    ReplaceFPIntrinsicWithCall(CI, "expf", "exp", "expl");404    break;405  }406  case Intrinsic::exp2: {407    ReplaceFPIntrinsicWithCall(CI, "exp2f", "exp2", "exp2l");408    break;409  }410  case Intrinsic::pow: {411    ReplaceFPIntrinsicWithCall(CI, "powf", "pow", "powl");412    break;413  }414  case Intrinsic::sin: {415    ReplaceFPIntrinsicWithCall(CI, "sinf", "sin", "sinl");416    break;417  }418  case Intrinsic::cos: {419    ReplaceFPIntrinsicWithCall(CI, "cosf", "cos", "cosl");420    break;421  }422  case Intrinsic::floor: {423    ReplaceFPIntrinsicWithCall(CI, "floorf", "floor", "floorl");424    break;425  }426  case Intrinsic::ceil: {427    ReplaceFPIntrinsicWithCall(CI, "ceilf", "ceil", "ceill");428    break;429  }430  case Intrinsic::trunc: {431    ReplaceFPIntrinsicWithCall(CI, "truncf", "trunc", "truncl");432    break;433  }434  case Intrinsic::round: {435    ReplaceFPIntrinsicWithCall(CI, "roundf", "round", "roundl");436    break;437  }438  case Intrinsic::roundeven: {439    ReplaceFPIntrinsicWithCall(CI, "roundevenf", "roundeven", "roundevenl");440    break;441  }442  case Intrinsic::copysign: {443    ReplaceFPIntrinsicWithCall(CI, "copysignf", "copysign", "copysignl");444    break;445  }446  case Intrinsic::get_rounding:447     // Lower to "round to the nearest"448     if (!CI->getType()->isVoidTy())449       CI->replaceAllUsesWith(ConstantInt::get(CI->getType(), 1));450     break;451  case Intrinsic::invariant_start:452  case Intrinsic::lifetime_start:453    // Discard region information.454    CI->replaceAllUsesWith(PoisonValue::get(CI->getType()));455    break;456  case Intrinsic::invariant_end:457  case Intrinsic::lifetime_end:458    // Discard region information.459    break;460  }461 462  assert(CI->use_empty() &&463         "Lowering should have eliminated any uses of the intrinsic call!");464  CI->eraseFromParent();465}466 467bool IntrinsicLowering::LowerToByteSwap(CallInst *CI) {468  // Verify this is a simple bswap.469  if (CI->arg_size() != 1 || CI->getType() != CI->getArgOperand(0)->getType() ||470      !CI->getType()->isIntegerTy())471    return false;472 473  IntegerType *Ty = dyn_cast<IntegerType>(CI->getType());474  if (!Ty)475    return false;476 477  // Okay, we can do this xform, do so now.478  Module *M = CI->getModule();479  Function *Int = Intrinsic::getOrInsertDeclaration(M, Intrinsic::bswap, Ty);480 481  Value *Op = CI->getArgOperand(0);482  Op = CallInst::Create(Int, Op, CI->getName(), CI->getIterator());483 484  CI->replaceAllUsesWith(Op);485  CI->eraseFromParent();486  return true;487}488