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-exception 6 // 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 17 using namespace clang; 18 using namespace CodeGen; 19 using namespace llvm; 20 21 static std::pair<Intrinsic::ID, unsigned> 22 getIntrinsicForHexagonNonClangBuiltin(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_MAPPING 64 }; 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 77 Value *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 for 89 // 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), stores 102 // 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 the 116 // 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 base 119 // pointer. It needs to be returned. The result of the load instruction is 120 // 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 expression 125 // 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 as 132 // { 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 needs 141 // 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_128B 151 : 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_128B 157 : 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 update 165 // 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 consume 184 // input carry, only generate carry-out. Since they still produce two 185 // 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 } // switch 261 262 return nullptr; 263 } 264