brintos

brintos / llvm-project-archived public Read only

0
0
Text · 11.9 KiB · 26fe695 Raw
264 lines · cpp
1//===------ Hexagon.cpp - Emit LLVM Code for builtins ---------------------===//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 contains code to emit Builtin calls as LLVM code.10//11//===----------------------------------------------------------------------===//12 13#include "CodeGenFunction.h"14#include "clang/Basic/TargetBuiltins.h"15#include "llvm/IR/IntrinsicsHexagon.h"16 17using namespace clang;18using namespace CodeGen;19using namespace llvm;20 21static std::pair<Intrinsic::ID, unsigned>22getIntrinsicForHexagonNonClangBuiltin(unsigned BuiltinID) {23  struct Info {24    unsigned BuiltinID;25    Intrinsic::ID IntrinsicID;26    unsigned VecLen;27  };28  static Info Infos[] = {29#define CUSTOM_BUILTIN_MAPPING(x,s) \30  { Hexagon::BI__builtin_HEXAGON_##x, Intrinsic::hexagon_##x, s },31    CUSTOM_BUILTIN_MAPPING(L2_loadrub_pci, 0)32    CUSTOM_BUILTIN_MAPPING(L2_loadrb_pci, 0)33    CUSTOM_BUILTIN_MAPPING(L2_loadruh_pci, 0)34    CUSTOM_BUILTIN_MAPPING(L2_loadrh_pci, 0)35    CUSTOM_BUILTIN_MAPPING(L2_loadri_pci, 0)36    CUSTOM_BUILTIN_MAPPING(L2_loadrd_pci, 0)37    CUSTOM_BUILTIN_MAPPING(L2_loadrub_pcr, 0)38    CUSTOM_BUILTIN_MAPPING(L2_loadrb_pcr, 0)39    CUSTOM_BUILTIN_MAPPING(L2_loadruh_pcr, 0)40    CUSTOM_BUILTIN_MAPPING(L2_loadrh_pcr, 0)41    CUSTOM_BUILTIN_MAPPING(L2_loadri_pcr, 0)42    CUSTOM_BUILTIN_MAPPING(L2_loadrd_pcr, 0)43    CUSTOM_BUILTIN_MAPPING(S2_storerb_pci, 0)44    CUSTOM_BUILTIN_MAPPING(S2_storerh_pci, 0)45    CUSTOM_BUILTIN_MAPPING(S2_storerf_pci, 0)46    CUSTOM_BUILTIN_MAPPING(S2_storeri_pci, 0)47    CUSTOM_BUILTIN_MAPPING(S2_storerd_pci, 0)48    CUSTOM_BUILTIN_MAPPING(S2_storerb_pcr, 0)49    CUSTOM_BUILTIN_MAPPING(S2_storerh_pcr, 0)50    CUSTOM_BUILTIN_MAPPING(S2_storerf_pcr, 0)51    CUSTOM_BUILTIN_MAPPING(S2_storeri_pcr, 0)52    CUSTOM_BUILTIN_MAPPING(S2_storerd_pcr, 0)53    // Legacy builtins that take a vector in place of a vector predicate.54    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq, 64)55    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq, 64)56    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq, 64)57    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq, 64)58    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq_128B, 128)59    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq_128B, 128)60    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq_128B, 128)61    CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq_128B, 128)62#include "clang/Basic/BuiltinsHexagonMapCustomDep.def"63#undef CUSTOM_BUILTIN_MAPPING64  };65 66  auto CmpInfo = [] (Info A, Info B) { return A.BuiltinID < B.BuiltinID; };67  static const bool SortOnce = (llvm::sort(Infos, CmpInfo), true);68  (void)SortOnce;69 70  const Info *F = llvm::lower_bound(Infos, Info{BuiltinID, 0, 0}, CmpInfo);71  if (F == std::end(Infos) || F->BuiltinID != BuiltinID)72    return {Intrinsic::not_intrinsic, 0};73 74  return {F->IntrinsicID, F->VecLen};75}76 77Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,78                                               const CallExpr *E) {79  Intrinsic::ID ID;80  unsigned VecLen;81  std::tie(ID, VecLen) = getIntrinsicForHexagonNonClangBuiltin(BuiltinID);82 83  auto MakeCircOp = [this, E](unsigned IntID, bool IsLoad) {84    // The base pointer is passed by address, so it needs to be loaded.85    Address A = EmitPointerWithAlignment(E->getArg(0));86    Address BP = Address(A.emitRawPointer(*this), Int8PtrTy, A.getAlignment());87    llvm::Value *Base = Builder.CreateLoad(BP);88    // The treatment of both loads and stores is the same: the arguments for89    // the builtin are the same as the arguments for the intrinsic.90    // Load:91    //   builtin(Base, Inc, Mod, Start) -> intr(Base, Inc, Mod, Start)92    //   builtin(Base, Mod, Start)      -> intr(Base, Mod, Start)93    // Store:94    //   builtin(Base, Inc, Mod, Val, Start) -> intr(Base, Inc, Mod, Val, Start)95    //   builtin(Base, Mod, Val, Start)      -> intr(Base, Mod, Val, Start)96    SmallVector<llvm::Value*,5> Ops = { Base };97    for (unsigned i = 1, e = E->getNumArgs(); i != e; ++i)98      Ops.push_back(EmitScalarExpr(E->getArg(i)));99 100    llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);101    // The load intrinsics generate two results (Value, NewBase), stores102    // generate one (NewBase). The new base address needs to be stored.103    llvm::Value *NewBase = IsLoad ? Builder.CreateExtractValue(Result, 1)104                                  : Result;105    llvm::Value *LV = EmitScalarExpr(E->getArg(0));106    Address Dest = EmitPointerWithAlignment(E->getArg(0));107    llvm::Value *RetVal =108        Builder.CreateAlignedStore(NewBase, LV, Dest.getAlignment());109    if (IsLoad)110      RetVal = Builder.CreateExtractValue(Result, 0);111    return RetVal;112  };113 114  // Handle the conversion of bit-reverse load intrinsics to bit code.115  // The intrinsic call after this function only reads from memory and the116  // write to memory is dealt by the store instruction.117  auto MakeBrevLd = [this, E](unsigned IntID, llvm::Type *DestTy) {118    // The intrinsic generates one result, which is the new value for the base119    // pointer. It needs to be returned. The result of the load instruction is120    // passed to intrinsic by address, so the value needs to be stored.121    llvm::Value *BaseAddress = EmitScalarExpr(E->getArg(0));122 123    // Expressions like &(*pt++) will be incremented per evaluation.124    // EmitPointerWithAlignment and EmitScalarExpr evaluates the expression125    // per call.126    Address DestAddr = EmitPointerWithAlignment(E->getArg(1));127    DestAddr = DestAddr.withElementType(Int8Ty);128    llvm::Value *DestAddress = DestAddr.emitRawPointer(*this);129 130    // Operands are Base, Dest, Modifier.131    // The intrinsic format in LLVM IR is defined as132    // { ValueType, i8* } (i8*, i32).133    llvm::Value *Result = Builder.CreateCall(134        CGM.getIntrinsic(IntID), {BaseAddress, EmitScalarExpr(E->getArg(2))});135 136    // The value needs to be stored as the variable is passed by reference.137    llvm::Value *DestVal = Builder.CreateExtractValue(Result, 0);138 139    // The store needs to be truncated to fit the destination type.140    // While i32 and i64 are natively supported on Hexagon, i8 and i16 needs141    // to be handled with stores of respective destination type.142    DestVal = Builder.CreateTrunc(DestVal, DestTy);143 144    Builder.CreateAlignedStore(DestVal, DestAddress, DestAddr.getAlignment());145    // The updated value of the base pointer is returned.146    return Builder.CreateExtractValue(Result, 1);147  };148 149  auto V2Q = [this, VecLen] (llvm::Value *Vec) {150    Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandvrt_128B151                                     : Intrinsic::hexagon_V6_vandvrt;152    return Builder.CreateCall(CGM.getIntrinsic(ID),153                              {Vec, Builder.getInt32(-1)});154  };155  auto Q2V = [this, VecLen] (llvm::Value *Pred) {156    Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandqrt_128B157                                     : Intrinsic::hexagon_V6_vandqrt;158    return Builder.CreateCall(CGM.getIntrinsic(ID),159                              {Pred, Builder.getInt32(-1)});160  };161 162  switch (BuiltinID) {163  // These intrinsics return a tuple {Vector, VectorPred} in LLVM IR,164  // and the corresponding C/C++ builtins use loads/stores to update165  // the predicate.166  case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry:167  case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B:168  case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry:169  case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B: {170    // Get the type from the 0-th argument.171    llvm::Type *VecType = ConvertType(E->getArg(0)->getType());172    Address PredAddr =173        EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);174    llvm::Value *PredIn = V2Q(Builder.CreateLoad(PredAddr));175    llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),176        {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), PredIn});177 178    llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);179    Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),180                               PredAddr.getAlignment());181    return Builder.CreateExtractValue(Result, 0);182  }183  // These are identical to the builtins above, except they don't consume184  // input carry, only generate carry-out. Since they still produce two185  // outputs, generate the store of the predicate, but no load.186  case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo:187  case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo_128B:188  case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo:189  case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo_128B: {190    // Get the type from the 0-th argument.191    llvm::Type *VecType = ConvertType(E->getArg(0)->getType());192    Address PredAddr =193        EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);194    llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),195        {EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});196 197    llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);198    Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),199                               PredAddr.getAlignment());200    return Builder.CreateExtractValue(Result, 0);201  }202 203  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq:204  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq:205  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq:206  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq:207  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq_128B:208  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq_128B:209  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq_128B:210  case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq_128B: {211    SmallVector<llvm::Value*,4> Ops;212    const Expr *PredOp = E->getArg(0);213    // There will be an implicit cast to a boolean vector. Strip it.214    if (auto *Cast = dyn_cast<ImplicitCastExpr>(PredOp)) {215      if (Cast->getCastKind() == CK_BitCast)216        PredOp = Cast->getSubExpr();217      Ops.push_back(V2Q(EmitScalarExpr(PredOp)));218    }219    for (int i = 1, e = E->getNumArgs(); i != e; ++i)220      Ops.push_back(EmitScalarExpr(E->getArg(i)));221    return Builder.CreateCall(CGM.getIntrinsic(ID), Ops);222  }223 224  case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci:225  case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci:226  case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci:227  case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci:228  case Hexagon::BI__builtin_HEXAGON_L2_loadri_pci:229  case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci:230  case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pcr:231  case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pcr:232  case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pcr:233  case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pcr:234  case Hexagon::BI__builtin_HEXAGON_L2_loadri_pcr:235  case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pcr:236    return MakeCircOp(ID, /*IsLoad=*/true);237  case Hexagon::BI__builtin_HEXAGON_S2_storerb_pci:238  case Hexagon::BI__builtin_HEXAGON_S2_storerh_pci:239  case Hexagon::BI__builtin_HEXAGON_S2_storerf_pci:240  case Hexagon::BI__builtin_HEXAGON_S2_storeri_pci:241  case Hexagon::BI__builtin_HEXAGON_S2_storerd_pci:242  case Hexagon::BI__builtin_HEXAGON_S2_storerb_pcr:243  case Hexagon::BI__builtin_HEXAGON_S2_storerh_pcr:244  case Hexagon::BI__builtin_HEXAGON_S2_storerf_pcr:245  case Hexagon::BI__builtin_HEXAGON_S2_storeri_pcr:246  case Hexagon::BI__builtin_HEXAGON_S2_storerd_pcr:247    return MakeCircOp(ID, /*IsLoad=*/false);248  case Hexagon::BI__builtin_brev_ldub:249    return MakeBrevLd(Intrinsic::hexagon_L2_loadrub_pbr, Int8Ty);250  case Hexagon::BI__builtin_brev_ldb:251    return MakeBrevLd(Intrinsic::hexagon_L2_loadrb_pbr, Int8Ty);252  case Hexagon::BI__builtin_brev_lduh:253    return MakeBrevLd(Intrinsic::hexagon_L2_loadruh_pbr, Int16Ty);254  case Hexagon::BI__builtin_brev_ldh:255    return MakeBrevLd(Intrinsic::hexagon_L2_loadrh_pbr, Int16Ty);256  case Hexagon::BI__builtin_brev_ldw:257    return MakeBrevLd(Intrinsic::hexagon_L2_loadri_pbr, Int32Ty);258  case Hexagon::BI__builtin_brev_ldd:259    return MakeBrevLd(Intrinsic::hexagon_L2_loadrd_pbr, Int64Ty);260  } // switch261 262  return nullptr;263}264