[NFC][clang] Split clang/lib/CodeGen/CGBuiltin.cpp into target-specific files (#132252)
clang/lib/CodeGen/CGBuiltin.cpp is over 1MB long (>23k LoC), and can take minutes to recompile (depending on compiler and host system) when modified, and 5 seconds for clangd to update for every edit. Splitting this file was discussed in this thread: https://discourse.llvm.org/t/splitting-clang-s-cgbuiltin-cpp-over-23k-lines-long-takes-1min-to-compile/ and the idea has received a number of +1 votes, hence this change.
This commit is contained in:
committed by
GitHub
parent
3757ecf5f1
commit
7f920e2e5f
File diff suppressed because it is too large
Load Diff
105
clang/lib/CodeGen/CGBuiltin.h
Normal file
105
clang/lib/CodeGen/CGBuiltin.h
Normal file
@@ -0,0 +1,105 @@
|
||||
//===------ CGBuiltin.h - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_CLANG_LIB_CODEGEN_CGBUILTIN_H
|
||||
#define LLVM_CLANG_LIB_CODEGEN_CGBUILTIN_H
|
||||
|
||||
#include "CodeGenFunction.h"
|
||||
|
||||
// Many of MSVC builtins are on x64, ARM and AArch64; to avoid repeating code,
|
||||
// we handle them here.
|
||||
enum class clang::CodeGen::CodeGenFunction::MSVCIntrin {
|
||||
_BitScanForward,
|
||||
_BitScanReverse,
|
||||
_InterlockedAnd,
|
||||
_InterlockedCompareExchange,
|
||||
_InterlockedDecrement,
|
||||
_InterlockedExchange,
|
||||
_InterlockedExchangeAdd,
|
||||
_InterlockedExchangeSub,
|
||||
_InterlockedIncrement,
|
||||
_InterlockedOr,
|
||||
_InterlockedXor,
|
||||
_InterlockedExchangeAdd_acq,
|
||||
_InterlockedExchangeAdd_rel,
|
||||
_InterlockedExchangeAdd_nf,
|
||||
_InterlockedExchange_acq,
|
||||
_InterlockedExchange_rel,
|
||||
_InterlockedExchange_nf,
|
||||
_InterlockedCompareExchange_acq,
|
||||
_InterlockedCompareExchange_rel,
|
||||
_InterlockedCompareExchange_nf,
|
||||
_InterlockedCompareExchange128,
|
||||
_InterlockedCompareExchange128_acq,
|
||||
_InterlockedCompareExchange128_rel,
|
||||
_InterlockedCompareExchange128_nf,
|
||||
_InterlockedOr_acq,
|
||||
_InterlockedOr_rel,
|
||||
_InterlockedOr_nf,
|
||||
_InterlockedXor_acq,
|
||||
_InterlockedXor_rel,
|
||||
_InterlockedXor_nf,
|
||||
_InterlockedAnd_acq,
|
||||
_InterlockedAnd_rel,
|
||||
_InterlockedAnd_nf,
|
||||
_InterlockedIncrement_acq,
|
||||
_InterlockedIncrement_rel,
|
||||
_InterlockedIncrement_nf,
|
||||
_InterlockedDecrement_acq,
|
||||
_InterlockedDecrement_rel,
|
||||
_InterlockedDecrement_nf,
|
||||
__fastfail,
|
||||
};
|
||||
|
||||
// Emit a simple intrinsic that has N scalar arguments and a return type
|
||||
// matching the argument type. It is assumed that only the first argument is
|
||||
// overloaded.
|
||||
template <unsigned N>
|
||||
llvm::Value *emitBuiltinWithOneOverloadedType(clang::CodeGen::CodeGenFunction &CGF,
|
||||
const clang::CallExpr *E,
|
||||
unsigned IntrinsicID,
|
||||
llvm::StringRef Name = "") {
|
||||
static_assert(N, "expect non-empty argument");
|
||||
clang::SmallVector<llvm::Value *, N> Args;
|
||||
for (unsigned I = 0; I < N; ++I)
|
||||
Args.push_back(CGF.EmitScalarExpr(E->getArg(I)));
|
||||
llvm::Function *F = CGF.CGM.getIntrinsic(IntrinsicID, Args[0]->getType());
|
||||
return CGF.Builder.CreateCall(F, Args, Name);
|
||||
}
|
||||
|
||||
llvm::Value *emitUnaryMaybeConstrainedFPBuiltin(clang::CodeGen::CodeGenFunction &CGF,
|
||||
const clang::CallExpr *E,
|
||||
unsigned IntrinsicID,
|
||||
unsigned ConstrainedIntrinsicID);
|
||||
|
||||
llvm::Value *EmitToInt(clang::CodeGen::CodeGenFunction &CGF, llvm::Value *V,
|
||||
clang::QualType T, llvm::IntegerType *IntType);
|
||||
|
||||
llvm::Value *EmitFromInt(clang::CodeGen::CodeGenFunction &CGF, llvm::Value *V,
|
||||
clang::QualType T, llvm::Type *ResultType);
|
||||
|
||||
clang::CodeGen::Address CheckAtomicAlignment(clang::CodeGen::CodeGenFunction &CGF,
|
||||
const clang::CallExpr *E);
|
||||
|
||||
llvm::Value *MakeBinaryAtomicValue(clang::CodeGen::CodeGenFunction &CGF,
|
||||
llvm::AtomicRMWInst::BinOp Kind,
|
||||
const clang::CallExpr *E,
|
||||
llvm::AtomicOrdering Ordering =
|
||||
llvm::AtomicOrdering::SequentiallyConsistent);
|
||||
|
||||
llvm::Value *EmitOverflowIntrinsic(clang::CodeGen::CodeGenFunction &CGF,
|
||||
const llvm::Intrinsic::ID IntrinsicID,
|
||||
llvm::Value *X,
|
||||
llvm::Value *Y,
|
||||
llvm::Value *&Carry);
|
||||
|
||||
llvm::Value *MakeAtomicCmpXchgValue(clang::CodeGen::CodeGenFunction &CGF,
|
||||
const clang::CallExpr *E,
|
||||
bool ReturnBool);
|
||||
|
||||
#endif
|
||||
@@ -115,6 +115,16 @@ add_clang_library(clangCodeGen
|
||||
PatternInit.cpp
|
||||
SanitizerMetadata.cpp
|
||||
SwiftCallingConv.cpp
|
||||
TargetBuiltins/ARM.cpp
|
||||
TargetBuiltins/AMDGPU.cpp
|
||||
TargetBuiltins/Hexagon.cpp
|
||||
TargetBuiltins/NVPTX.cpp
|
||||
TargetBuiltins/PPC.cpp
|
||||
TargetBuiltins/RISCV.cpp
|
||||
TargetBuiltins/SPIR.cpp
|
||||
TargetBuiltins/SystemZ.cpp
|
||||
TargetBuiltins/WebAssembly.cpp
|
||||
TargetBuiltins/X86.cpp
|
||||
TargetInfo.cpp
|
||||
Targets/AArch64.cpp
|
||||
Targets/AMDGPU.cpp
|
||||
|
||||
1882
clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp
Normal file
1882
clang/lib/CodeGen/TargetBuiltins/AMDGPU.cpp
Normal file
File diff suppressed because it is too large
Load Diff
8040
clang/lib/CodeGen/TargetBuiltins/ARM.cpp
Normal file
8040
clang/lib/CodeGen/TargetBuiltins/ARM.cpp
Normal file
File diff suppressed because it is too large
Load Diff
267
clang/lib/CodeGen/TargetBuiltins/Hexagon.cpp
Normal file
267
clang/lib/CodeGen/TargetBuiltins/Hexagon.cpp
Normal file
@@ -0,0 +1,267 @@
|
||||
//===------ Hexagon.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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 contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "TargetInfo.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsHexagon.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
static std::pair<Intrinsic::ID, unsigned>
|
||||
getIntrinsicForHexagonNonClangBuiltin(unsigned BuiltinID) {
|
||||
struct Info {
|
||||
unsigned BuiltinID;
|
||||
Intrinsic::ID IntrinsicID;
|
||||
unsigned VecLen;
|
||||
};
|
||||
static Info Infos[] = {
|
||||
#define CUSTOM_BUILTIN_MAPPING(x,s) \
|
||||
{ Hexagon::BI__builtin_HEXAGON_##x, Intrinsic::hexagon_##x, s },
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrub_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrb_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadruh_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrh_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadri_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrd_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrub_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrb_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadruh_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrh_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadri_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(L2_loadrd_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerb_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerh_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerf_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storeri_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerd_pci, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerb_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerh_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerf_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storeri_pcr, 0)
|
||||
CUSTOM_BUILTIN_MAPPING(S2_storerd_pcr, 0)
|
||||
// Legacy builtins that take a vector in place of a vector predicate.
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq, 64)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq, 64)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq, 64)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq, 64)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstoreq_128B, 128)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorenq_128B, 128)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentq_128B, 128)
|
||||
CUSTOM_BUILTIN_MAPPING(V6_vmaskedstorentnq_128B, 128)
|
||||
#include "clang/Basic/BuiltinsHexagonMapCustomDep.def"
|
||||
#undef CUSTOM_BUILTIN_MAPPING
|
||||
};
|
||||
|
||||
auto CmpInfo = [] (Info A, Info B) { return A.BuiltinID < B.BuiltinID; };
|
||||
static const bool SortOnce = (llvm::sort(Infos, CmpInfo), true);
|
||||
(void)SortOnce;
|
||||
|
||||
const Info *F = llvm::lower_bound(Infos, Info{BuiltinID, 0, 0}, CmpInfo);
|
||||
if (F == std::end(Infos) || F->BuiltinID != BuiltinID)
|
||||
return {Intrinsic::not_intrinsic, 0};
|
||||
|
||||
return {F->IntrinsicID, F->VecLen};
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitHexagonBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
Intrinsic::ID ID;
|
||||
unsigned VecLen;
|
||||
std::tie(ID, VecLen) = getIntrinsicForHexagonNonClangBuiltin(BuiltinID);
|
||||
|
||||
auto MakeCircOp = [this, E](unsigned IntID, bool IsLoad) {
|
||||
// The base pointer is passed by address, so it needs to be loaded.
|
||||
Address A = EmitPointerWithAlignment(E->getArg(0));
|
||||
Address BP = Address(A.emitRawPointer(*this), Int8PtrTy, A.getAlignment());
|
||||
llvm::Value *Base = Builder.CreateLoad(BP);
|
||||
// The treatment of both loads and stores is the same: the arguments for
|
||||
// the builtin are the same as the arguments for the intrinsic.
|
||||
// Load:
|
||||
// builtin(Base, Inc, Mod, Start) -> intr(Base, Inc, Mod, Start)
|
||||
// builtin(Base, Mod, Start) -> intr(Base, Mod, Start)
|
||||
// Store:
|
||||
// builtin(Base, Inc, Mod, Val, Start) -> intr(Base, Inc, Mod, Val, Start)
|
||||
// builtin(Base, Mod, Val, Start) -> intr(Base, Mod, Val, Start)
|
||||
SmallVector<llvm::Value*,5> Ops = { Base };
|
||||
for (unsigned i = 1, e = E->getNumArgs(); i != e; ++i)
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
||||
|
||||
llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(IntID), Ops);
|
||||
// The load intrinsics generate two results (Value, NewBase), stores
|
||||
// generate one (NewBase). The new base address needs to be stored.
|
||||
llvm::Value *NewBase = IsLoad ? Builder.CreateExtractValue(Result, 1)
|
||||
: Result;
|
||||
llvm::Value *LV = EmitScalarExpr(E->getArg(0));
|
||||
Address Dest = EmitPointerWithAlignment(E->getArg(0));
|
||||
llvm::Value *RetVal =
|
||||
Builder.CreateAlignedStore(NewBase, LV, Dest.getAlignment());
|
||||
if (IsLoad)
|
||||
RetVal = Builder.CreateExtractValue(Result, 0);
|
||||
return RetVal;
|
||||
};
|
||||
|
||||
// Handle the conversion of bit-reverse load intrinsics to bit code.
|
||||
// The intrinsic call after this function only reads from memory and the
|
||||
// write to memory is dealt by the store instruction.
|
||||
auto MakeBrevLd = [this, E](unsigned IntID, llvm::Type *DestTy) {
|
||||
// The intrinsic generates one result, which is the new value for the base
|
||||
// pointer. It needs to be returned. The result of the load instruction is
|
||||
// passed to intrinsic by address, so the value needs to be stored.
|
||||
llvm::Value *BaseAddress = EmitScalarExpr(E->getArg(0));
|
||||
|
||||
// Expressions like &(*pt++) will be incremented per evaluation.
|
||||
// EmitPointerWithAlignment and EmitScalarExpr evaluates the expression
|
||||
// per call.
|
||||
Address DestAddr = EmitPointerWithAlignment(E->getArg(1));
|
||||
DestAddr = DestAddr.withElementType(Int8Ty);
|
||||
llvm::Value *DestAddress = DestAddr.emitRawPointer(*this);
|
||||
|
||||
// Operands are Base, Dest, Modifier.
|
||||
// The intrinsic format in LLVM IR is defined as
|
||||
// { ValueType, i8* } (i8*, i32).
|
||||
llvm::Value *Result = Builder.CreateCall(
|
||||
CGM.getIntrinsic(IntID), {BaseAddress, EmitScalarExpr(E->getArg(2))});
|
||||
|
||||
// The value needs to be stored as the variable is passed by reference.
|
||||
llvm::Value *DestVal = Builder.CreateExtractValue(Result, 0);
|
||||
|
||||
// The store needs to be truncated to fit the destination type.
|
||||
// While i32 and i64 are natively supported on Hexagon, i8 and i16 needs
|
||||
// to be handled with stores of respective destination type.
|
||||
DestVal = Builder.CreateTrunc(DestVal, DestTy);
|
||||
|
||||
Builder.CreateAlignedStore(DestVal, DestAddress, DestAddr.getAlignment());
|
||||
// The updated value of the base pointer is returned.
|
||||
return Builder.CreateExtractValue(Result, 1);
|
||||
};
|
||||
|
||||
auto V2Q = [this, VecLen] (llvm::Value *Vec) {
|
||||
Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandvrt_128B
|
||||
: Intrinsic::hexagon_V6_vandvrt;
|
||||
return Builder.CreateCall(CGM.getIntrinsic(ID),
|
||||
{Vec, Builder.getInt32(-1)});
|
||||
};
|
||||
auto Q2V = [this, VecLen] (llvm::Value *Pred) {
|
||||
Intrinsic::ID ID = VecLen == 128 ? Intrinsic::hexagon_V6_vandqrt_128B
|
||||
: Intrinsic::hexagon_V6_vandqrt;
|
||||
return Builder.CreateCall(CGM.getIntrinsic(ID),
|
||||
{Pred, Builder.getInt32(-1)});
|
||||
};
|
||||
|
||||
switch (BuiltinID) {
|
||||
// These intrinsics return a tuple {Vector, VectorPred} in LLVM IR,
|
||||
// and the corresponding C/C++ builtins use loads/stores to update
|
||||
// the predicate.
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vaddcarry_128B:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vsubcarry_128B: {
|
||||
// Get the type from the 0-th argument.
|
||||
llvm::Type *VecType = ConvertType(E->getArg(0)->getType());
|
||||
Address PredAddr =
|
||||
EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);
|
||||
llvm::Value *PredIn = V2Q(Builder.CreateLoad(PredAddr));
|
||||
llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),
|
||||
{EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1)), PredIn});
|
||||
|
||||
llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);
|
||||
Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),
|
||||
PredAddr.getAlignment());
|
||||
return Builder.CreateExtractValue(Result, 0);
|
||||
}
|
||||
// These are identical to the builtins above, except they don't consume
|
||||
// input carry, only generate carry-out. Since they still produce two
|
||||
// outputs, generate the store of the predicate, but no load.
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vaddcarryo_128B:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vsubcarryo_128B: {
|
||||
// Get the type from the 0-th argument.
|
||||
llvm::Type *VecType = ConvertType(E->getArg(0)->getType());
|
||||
Address PredAddr =
|
||||
EmitPointerWithAlignment(E->getArg(2)).withElementType(VecType);
|
||||
llvm::Value *Result = Builder.CreateCall(CGM.getIntrinsic(ID),
|
||||
{EmitScalarExpr(E->getArg(0)), EmitScalarExpr(E->getArg(1))});
|
||||
|
||||
llvm::Value *PredOut = Builder.CreateExtractValue(Result, 1);
|
||||
Builder.CreateAlignedStore(Q2V(PredOut), PredAddr.emitRawPointer(*this),
|
||||
PredAddr.getAlignment());
|
||||
return Builder.CreateExtractValue(Result, 0);
|
||||
}
|
||||
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstoreq_128B:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorenq_128B:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentq_128B:
|
||||
case Hexagon::BI__builtin_HEXAGON_V6_vmaskedstorentnq_128B: {
|
||||
SmallVector<llvm::Value*,4> Ops;
|
||||
const Expr *PredOp = E->getArg(0);
|
||||
// There will be an implicit cast to a boolean vector. Strip it.
|
||||
if (auto *Cast = dyn_cast<ImplicitCastExpr>(PredOp)) {
|
||||
if (Cast->getCastKind() == CK_BitCast)
|
||||
PredOp = Cast->getSubExpr();
|
||||
Ops.push_back(V2Q(EmitScalarExpr(PredOp)));
|
||||
}
|
||||
for (int i = 1, e = E->getNumArgs(); i != e; ++i)
|
||||
Ops.push_back(EmitScalarExpr(E->getArg(i)));
|
||||
return Builder.CreateCall(CGM.getIntrinsic(ID), Ops);
|
||||
}
|
||||
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadri_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrub_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrb_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadruh_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrh_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadri_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_L2_loadrd_pcr:
|
||||
return MakeCircOp(ID, /*IsLoad=*/true);
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerb_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerh_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerf_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storeri_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerd_pci:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerb_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerh_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerf_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storeri_pcr:
|
||||
case Hexagon::BI__builtin_HEXAGON_S2_storerd_pcr:
|
||||
return MakeCircOp(ID, /*IsLoad=*/false);
|
||||
case Hexagon::BI__builtin_brev_ldub:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadrub_pbr, Int8Ty);
|
||||
case Hexagon::BI__builtin_brev_ldb:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadrb_pbr, Int8Ty);
|
||||
case Hexagon::BI__builtin_brev_lduh:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadruh_pbr, Int16Ty);
|
||||
case Hexagon::BI__builtin_brev_ldh:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadrh_pbr, Int16Ty);
|
||||
case Hexagon::BI__builtin_brev_ldw:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadri_pbr, Int32Ty);
|
||||
case Hexagon::BI__builtin_brev_ldd:
|
||||
return MakeBrevLd(Intrinsic::hexagon_L2_loadrd_pbr, Int64Ty);
|
||||
} // switch
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
1167
clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
Normal file
1167
clang/lib/CodeGen/TargetBuiltins/NVPTX.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1358
clang/lib/CodeGen/TargetBuiltins/PPC.cpp
Normal file
1358
clang/lib/CodeGen/TargetBuiltins/PPC.cpp
Normal file
File diff suppressed because it is too large
Load Diff
425
clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
Normal file
425
clang/lib/CodeGen/TargetBuiltins/RISCV.cpp
Normal file
@@ -0,0 +1,425 @@
|
||||
//===-------- RISCV.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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 contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "TargetInfo.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsRISCV.h"
|
||||
#include "llvm/TargetParser/RISCVISAInfo.h"
|
||||
#include "llvm/TargetParser/RISCVTargetParser.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVCpuInit() {
|
||||
llvm::FunctionType *FTy = llvm::FunctionType::get(VoidTy, {VoidPtrTy}, false);
|
||||
llvm::FunctionCallee Func =
|
||||
CGM.CreateRuntimeFunction(FTy, "__init_riscv_feature_bits");
|
||||
auto *CalleeGV = cast<llvm::GlobalValue>(Func.getCallee());
|
||||
CalleeGV->setDSOLocal(true);
|
||||
CalleeGV->setDLLStorageClass(llvm::GlobalValue::DefaultStorageClass);
|
||||
return Builder.CreateCall(Func, {llvm::ConstantPointerNull::get(VoidPtrTy)});
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVCpuSupports(const CallExpr *E) {
|
||||
|
||||
const Expr *FeatureExpr = E->getArg(0)->IgnoreParenCasts();
|
||||
StringRef FeatureStr = cast<StringLiteral>(FeatureExpr)->getString();
|
||||
if (!getContext().getTargetInfo().validateCpuSupports(FeatureStr))
|
||||
return Builder.getFalse();
|
||||
|
||||
return EmitRISCVCpuSupports(ArrayRef<StringRef>(FeatureStr));
|
||||
}
|
||||
|
||||
static Value *loadRISCVFeatureBits(unsigned Index, CGBuilderTy &Builder,
|
||||
CodeGenModule &CGM) {
|
||||
llvm::Type *Int32Ty = Builder.getInt32Ty();
|
||||
llvm::Type *Int64Ty = Builder.getInt64Ty();
|
||||
llvm::ArrayType *ArrayOfInt64Ty =
|
||||
llvm::ArrayType::get(Int64Ty, llvm::RISCVISAInfo::FeatureBitSize);
|
||||
llvm::Type *StructTy = llvm::StructType::get(Int32Ty, ArrayOfInt64Ty);
|
||||
llvm::Constant *RISCVFeaturesBits =
|
||||
CGM.CreateRuntimeVariable(StructTy, "__riscv_feature_bits");
|
||||
cast<llvm::GlobalValue>(RISCVFeaturesBits)->setDSOLocal(true);
|
||||
Value *IndexVal = llvm::ConstantInt::get(Int32Ty, Index);
|
||||
llvm::Value *GEPIndices[] = {Builder.getInt32(0), Builder.getInt32(1),
|
||||
IndexVal};
|
||||
Value *Ptr =
|
||||
Builder.CreateInBoundsGEP(StructTy, RISCVFeaturesBits, GEPIndices);
|
||||
Value *FeaturesBit =
|
||||
Builder.CreateAlignedLoad(Int64Ty, Ptr, CharUnits::fromQuantity(8));
|
||||
return FeaturesBit;
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVCpuSupports(ArrayRef<StringRef> FeaturesStrs) {
|
||||
const unsigned RISCVFeatureLength = llvm::RISCVISAInfo::FeatureBitSize;
|
||||
uint64_t RequireBitMasks[RISCVFeatureLength] = {0};
|
||||
|
||||
for (auto Feat : FeaturesStrs) {
|
||||
auto [GroupID, BitPos] = RISCVISAInfo::getRISCVFeaturesBitsInfo(Feat);
|
||||
|
||||
// If there isn't BitPos for this feature, skip this version.
|
||||
// It also report the warning to user during compilation.
|
||||
if (BitPos == -1)
|
||||
return Builder.getFalse();
|
||||
|
||||
RequireBitMasks[GroupID] |= (1ULL << BitPos);
|
||||
}
|
||||
|
||||
Value *Result = nullptr;
|
||||
for (unsigned Idx = 0; Idx < RISCVFeatureLength; Idx++) {
|
||||
if (RequireBitMasks[Idx] == 0)
|
||||
continue;
|
||||
|
||||
Value *Mask = Builder.getInt64(RequireBitMasks[Idx]);
|
||||
Value *Bitset =
|
||||
Builder.CreateAnd(loadRISCVFeatureBits(Idx, Builder, CGM), Mask);
|
||||
Value *CmpV = Builder.CreateICmpEQ(Bitset, Mask);
|
||||
Result = (!Result) ? CmpV : Builder.CreateAnd(Result, CmpV);
|
||||
}
|
||||
|
||||
assert(Result && "Should have value here.");
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVCpuIs(const CallExpr *E) {
|
||||
const Expr *CPUExpr = E->getArg(0)->IgnoreParenCasts();
|
||||
StringRef CPUStr = cast<clang::StringLiteral>(CPUExpr)->getString();
|
||||
return EmitRISCVCpuIs(CPUStr);
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVCpuIs(StringRef CPUStr) {
|
||||
llvm::Type *Int32Ty = Builder.getInt32Ty();
|
||||
llvm::Type *Int64Ty = Builder.getInt64Ty();
|
||||
llvm::StructType *StructTy = llvm::StructType::get(Int32Ty, Int64Ty, Int64Ty);
|
||||
llvm::Constant *RISCVCPUModel =
|
||||
CGM.CreateRuntimeVariable(StructTy, "__riscv_cpu_model");
|
||||
cast<llvm::GlobalValue>(RISCVCPUModel)->setDSOLocal(true);
|
||||
|
||||
auto loadRISCVCPUID = [&](unsigned Index) {
|
||||
Value *Ptr = Builder.CreateStructGEP(StructTy, RISCVCPUModel, Index);
|
||||
Value *CPUID = Builder.CreateAlignedLoad(StructTy->getTypeAtIndex(Index),
|
||||
Ptr, llvm::MaybeAlign());
|
||||
return CPUID;
|
||||
};
|
||||
|
||||
const llvm::RISCV::CPUModel Model = llvm::RISCV::getCPUModel(CPUStr);
|
||||
|
||||
// Compare mvendorid.
|
||||
Value *VendorID = loadRISCVCPUID(0);
|
||||
Value *Result =
|
||||
Builder.CreateICmpEQ(VendorID, Builder.getInt32(Model.MVendorID));
|
||||
|
||||
// Compare marchid.
|
||||
Value *ArchID = loadRISCVCPUID(1);
|
||||
Result = Builder.CreateAnd(
|
||||
Result, Builder.CreateICmpEQ(ArchID, Builder.getInt64(Model.MArchID)));
|
||||
|
||||
// Compare mimpid.
|
||||
Value *ImpID = loadRISCVCPUID(2);
|
||||
Result = Builder.CreateAnd(
|
||||
Result, Builder.CreateICmpEQ(ImpID, Builder.getInt64(Model.MImpID)));
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitRISCVBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E,
|
||||
ReturnValueSlot ReturnValue) {
|
||||
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_supports)
|
||||
return EmitRISCVCpuSupports(E);
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_init)
|
||||
return EmitRISCVCpuInit();
|
||||
if (BuiltinID == Builtin::BI__builtin_cpu_is)
|
||||
return EmitRISCVCpuIs(E);
|
||||
|
||||
SmallVector<Value *, 4> Ops;
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
|
||||
// Find out if any arguments are required to be integer constant expressions.
|
||||
unsigned ICEArguments = 0;
|
||||
ASTContext::GetBuiltinTypeError Error;
|
||||
getContext().GetBuiltinType(BuiltinID, Error, &ICEArguments);
|
||||
if (Error == ASTContext::GE_Missing_type) {
|
||||
// Vector intrinsics don't have a type string.
|
||||
assert(BuiltinID >= clang::RISCV::FirstRVVBuiltin &&
|
||||
BuiltinID <= clang::RISCV::LastRVVBuiltin);
|
||||
ICEArguments = 0;
|
||||
if (BuiltinID == RISCVVector::BI__builtin_rvv_vget_v ||
|
||||
BuiltinID == RISCVVector::BI__builtin_rvv_vset_v)
|
||||
ICEArguments = 1 << 1;
|
||||
} else {
|
||||
assert(Error == ASTContext::GE_None && "Unexpected error");
|
||||
}
|
||||
|
||||
if (BuiltinID == RISCV::BI__builtin_riscv_ntl_load)
|
||||
ICEArguments |= (1 << 1);
|
||||
if (BuiltinID == RISCV::BI__builtin_riscv_ntl_store)
|
||||
ICEArguments |= (1 << 2);
|
||||
|
||||
for (unsigned i = 0, e = E->getNumArgs(); i != e; i++) {
|
||||
// Handle aggregate argument, namely RVV tuple types in segment load/store
|
||||
if (hasAggregateEvaluationKind(E->getArg(i)->getType())) {
|
||||
LValue L = EmitAggExprToLValue(E->getArg(i));
|
||||
llvm::Value *AggValue = Builder.CreateLoad(L.getAddress());
|
||||
Ops.push_back(AggValue);
|
||||
continue;
|
||||
}
|
||||
Ops.push_back(EmitScalarOrConstFoldImmArg(ICEArguments, i, E));
|
||||
}
|
||||
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
// The 0th bit simulates the `vta` of RVV
|
||||
// The 1st bit simulates the `vma` of RVV
|
||||
constexpr unsigned RVV_VTA = 0x1;
|
||||
constexpr unsigned RVV_VMA = 0x2;
|
||||
int PolicyAttrs = 0;
|
||||
bool IsMasked = false;
|
||||
// This is used by segment load/store to determine it's llvm type.
|
||||
unsigned SegInstSEW = 8;
|
||||
|
||||
// Required for overloaded intrinsics.
|
||||
llvm::SmallVector<llvm::Type *, 2> IntrinsicTypes;
|
||||
switch (BuiltinID) {
|
||||
default: llvm_unreachable("unexpected builtin ID");
|
||||
case RISCV::BI__builtin_riscv_orc_b_32:
|
||||
case RISCV::BI__builtin_riscv_orc_b_64:
|
||||
case RISCV::BI__builtin_riscv_clmul_32:
|
||||
case RISCV::BI__builtin_riscv_clmul_64:
|
||||
case RISCV::BI__builtin_riscv_clmulh_32:
|
||||
case RISCV::BI__builtin_riscv_clmulh_64:
|
||||
case RISCV::BI__builtin_riscv_clmulr_32:
|
||||
case RISCV::BI__builtin_riscv_clmulr_64:
|
||||
case RISCV::BI__builtin_riscv_xperm4_32:
|
||||
case RISCV::BI__builtin_riscv_xperm4_64:
|
||||
case RISCV::BI__builtin_riscv_xperm8_32:
|
||||
case RISCV::BI__builtin_riscv_xperm8_64:
|
||||
case RISCV::BI__builtin_riscv_brev8_32:
|
||||
case RISCV::BI__builtin_riscv_brev8_64:
|
||||
case RISCV::BI__builtin_riscv_zip_32:
|
||||
case RISCV::BI__builtin_riscv_unzip_32: {
|
||||
switch (BuiltinID) {
|
||||
default: llvm_unreachable("unexpected builtin ID");
|
||||
// Zbb
|
||||
case RISCV::BI__builtin_riscv_orc_b_32:
|
||||
case RISCV::BI__builtin_riscv_orc_b_64:
|
||||
ID = Intrinsic::riscv_orc_b;
|
||||
break;
|
||||
|
||||
// Zbc
|
||||
case RISCV::BI__builtin_riscv_clmul_32:
|
||||
case RISCV::BI__builtin_riscv_clmul_64:
|
||||
ID = Intrinsic::riscv_clmul;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_clmulh_32:
|
||||
case RISCV::BI__builtin_riscv_clmulh_64:
|
||||
ID = Intrinsic::riscv_clmulh;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_clmulr_32:
|
||||
case RISCV::BI__builtin_riscv_clmulr_64:
|
||||
ID = Intrinsic::riscv_clmulr;
|
||||
break;
|
||||
|
||||
// Zbkx
|
||||
case RISCV::BI__builtin_riscv_xperm8_32:
|
||||
case RISCV::BI__builtin_riscv_xperm8_64:
|
||||
ID = Intrinsic::riscv_xperm8;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_xperm4_32:
|
||||
case RISCV::BI__builtin_riscv_xperm4_64:
|
||||
ID = Intrinsic::riscv_xperm4;
|
||||
break;
|
||||
|
||||
// Zbkb
|
||||
case RISCV::BI__builtin_riscv_brev8_32:
|
||||
case RISCV::BI__builtin_riscv_brev8_64:
|
||||
ID = Intrinsic::riscv_brev8;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_zip_32:
|
||||
ID = Intrinsic::riscv_zip;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_unzip_32:
|
||||
ID = Intrinsic::riscv_unzip;
|
||||
break;
|
||||
}
|
||||
|
||||
IntrinsicTypes = {ResultType};
|
||||
break;
|
||||
}
|
||||
|
||||
// Zk builtins
|
||||
|
||||
// Zknh
|
||||
case RISCV::BI__builtin_riscv_sha256sig0:
|
||||
ID = Intrinsic::riscv_sha256sig0;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_sha256sig1:
|
||||
ID = Intrinsic::riscv_sha256sig1;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_sha256sum0:
|
||||
ID = Intrinsic::riscv_sha256sum0;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_sha256sum1:
|
||||
ID = Intrinsic::riscv_sha256sum1;
|
||||
break;
|
||||
|
||||
// Zksed
|
||||
case RISCV::BI__builtin_riscv_sm4ks:
|
||||
ID = Intrinsic::riscv_sm4ks;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_sm4ed:
|
||||
ID = Intrinsic::riscv_sm4ed;
|
||||
break;
|
||||
|
||||
// Zksh
|
||||
case RISCV::BI__builtin_riscv_sm3p0:
|
||||
ID = Intrinsic::riscv_sm3p0;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_sm3p1:
|
||||
ID = Intrinsic::riscv_sm3p1;
|
||||
break;
|
||||
|
||||
case RISCV::BI__builtin_riscv_clz_32:
|
||||
case RISCV::BI__builtin_riscv_clz_64: {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, Ops[0]->getType());
|
||||
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
|
||||
if (Result->getType() != ResultType)
|
||||
Result =
|
||||
Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
|
||||
return Result;
|
||||
}
|
||||
case RISCV::BI__builtin_riscv_ctz_32:
|
||||
case RISCV::BI__builtin_riscv_ctz_64: {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::cttz, Ops[0]->getType());
|
||||
Value *Result = Builder.CreateCall(F, {Ops[0], Builder.getInt1(false)});
|
||||
if (Result->getType() != ResultType)
|
||||
Result =
|
||||
Builder.CreateIntCast(Result, ResultType, /*isSigned*/ false, "cast");
|
||||
return Result;
|
||||
}
|
||||
|
||||
// Zihintntl
|
||||
case RISCV::BI__builtin_riscv_ntl_load: {
|
||||
llvm::Type *ResTy = ConvertType(E->getType());
|
||||
unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
|
||||
if (Ops.size() == 2)
|
||||
DomainVal = cast<ConstantInt>(Ops[1])->getZExtValue();
|
||||
|
||||
llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
|
||||
getLLVMContext(),
|
||||
llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
|
||||
llvm::MDNode *NontemporalNode = llvm::MDNode::get(
|
||||
getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
|
||||
|
||||
int Width;
|
||||
if(ResTy->isScalableTy()) {
|
||||
const ScalableVectorType *SVTy = cast<ScalableVectorType>(ResTy);
|
||||
llvm::Type *ScalarTy = ResTy->getScalarType();
|
||||
Width = ScalarTy->getPrimitiveSizeInBits() *
|
||||
SVTy->getElementCount().getKnownMinValue();
|
||||
} else
|
||||
Width = ResTy->getPrimitiveSizeInBits();
|
||||
LoadInst *Load = Builder.CreateLoad(
|
||||
Address(Ops[0], ResTy, CharUnits::fromQuantity(Width / 8)));
|
||||
|
||||
Load->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
|
||||
Load->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
|
||||
RISCVDomainNode);
|
||||
|
||||
return Load;
|
||||
}
|
||||
case RISCV::BI__builtin_riscv_ntl_store: {
|
||||
unsigned DomainVal = 5; // Default __RISCV_NTLH_ALL
|
||||
if (Ops.size() == 3)
|
||||
DomainVal = cast<ConstantInt>(Ops[2])->getZExtValue();
|
||||
|
||||
llvm::MDNode *RISCVDomainNode = llvm::MDNode::get(
|
||||
getLLVMContext(),
|
||||
llvm::ConstantAsMetadata::get(Builder.getInt32(DomainVal)));
|
||||
llvm::MDNode *NontemporalNode = llvm::MDNode::get(
|
||||
getLLVMContext(), llvm::ConstantAsMetadata::get(Builder.getInt32(1)));
|
||||
|
||||
StoreInst *Store = Builder.CreateDefaultAlignedStore(Ops[1], Ops[0]);
|
||||
Store->setMetadata(llvm::LLVMContext::MD_nontemporal, NontemporalNode);
|
||||
Store->setMetadata(CGM.getModule().getMDKindID("riscv-nontemporal-domain"),
|
||||
RISCVDomainNode);
|
||||
|
||||
return Store;
|
||||
}
|
||||
// XCValu
|
||||
case RISCV::BI__builtin_riscv_cv_alu_addN:
|
||||
ID = Intrinsic::riscv_cv_alu_addN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_addRN:
|
||||
ID = Intrinsic::riscv_cv_alu_addRN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_adduN:
|
||||
ID = Intrinsic::riscv_cv_alu_adduN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_adduRN:
|
||||
ID = Intrinsic::riscv_cv_alu_adduRN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_clip:
|
||||
ID = Intrinsic::riscv_cv_alu_clip;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_clipu:
|
||||
ID = Intrinsic::riscv_cv_alu_clipu;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_extbs:
|
||||
return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
|
||||
"extbs");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_extbz:
|
||||
return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int8Ty), Int32Ty,
|
||||
"extbz");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_exths:
|
||||
return Builder.CreateSExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
|
||||
"exths");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_exthz:
|
||||
return Builder.CreateZExt(Builder.CreateTrunc(Ops[0], Int16Ty), Int32Ty,
|
||||
"exthz");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_slet:
|
||||
return Builder.CreateZExt(Builder.CreateICmpSLE(Ops[0], Ops[1]), Int32Ty,
|
||||
"sle");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_sletu:
|
||||
return Builder.CreateZExt(Builder.CreateICmpULE(Ops[0], Ops[1]), Int32Ty,
|
||||
"sleu");
|
||||
case RISCV::BI__builtin_riscv_cv_alu_subN:
|
||||
ID = Intrinsic::riscv_cv_alu_subN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_subRN:
|
||||
ID = Intrinsic::riscv_cv_alu_subRN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_subuN:
|
||||
ID = Intrinsic::riscv_cv_alu_subuN;
|
||||
break;
|
||||
case RISCV::BI__builtin_riscv_cv_alu_subuRN:
|
||||
ID = Intrinsic::riscv_cv_alu_subuRN;
|
||||
break;
|
||||
|
||||
// Vector builtins are handled from here.
|
||||
#include "clang/Basic/riscv_vector_builtin_cg.inc"
|
||||
|
||||
// SiFive Vector builtins are handled from here.
|
||||
#include "clang/Basic/riscv_sifive_vector_builtin_cg.inc"
|
||||
}
|
||||
|
||||
assert(ID != Intrinsic::not_intrinsic);
|
||||
|
||||
llvm::Function *F = CGM.getIntrinsic(ID, IntrinsicTypes);
|
||||
return Builder.CreateCall(F, Ops, "");
|
||||
}
|
||||
66
clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
Normal file
66
clang/lib/CodeGen/TargetBuiltins/SPIR.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
//===--------- SPIR.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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 contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CGHLSLRuntime.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "TargetInfo.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
Value *CodeGenFunction::EmitSPIRVBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
switch (BuiltinID) {
|
||||
case SPIRV::BI__builtin_spirv_distance: {
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
|
||||
E->getArg(1)->getType()->hasFloatingRepresentation() &&
|
||||
"Distance operands must have a float representation");
|
||||
assert(E->getArg(0)->getType()->isVectorType() &&
|
||||
E->getArg(1)->getType()->isVectorType() &&
|
||||
"Distance operands must be a vector");
|
||||
return Builder.CreateIntrinsic(
|
||||
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_distance,
|
||||
ArrayRef<Value *>{X, Y}, nullptr, "spv.distance");
|
||||
}
|
||||
case SPIRV::BI__builtin_spirv_length: {
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
|
||||
"length operand must have a float representation");
|
||||
assert(E->getArg(0)->getType()->isVectorType() &&
|
||||
"length operand must be a vector");
|
||||
return Builder.CreateIntrinsic(
|
||||
/*ReturnType=*/X->getType()->getScalarType(), Intrinsic::spv_length,
|
||||
ArrayRef<Value *>{X}, nullptr, "spv.length");
|
||||
}
|
||||
case SPIRV::BI__builtin_spirv_reflect: {
|
||||
Value *I = EmitScalarExpr(E->getArg(0));
|
||||
Value *N = EmitScalarExpr(E->getArg(1));
|
||||
assert(E->getArg(0)->getType()->hasFloatingRepresentation() &&
|
||||
E->getArg(1)->getType()->hasFloatingRepresentation() &&
|
||||
"Reflect operands must have a float representation");
|
||||
assert(E->getArg(0)->getType()->isVectorType() &&
|
||||
E->getArg(1)->getType()->isVectorType() &&
|
||||
"Reflect operands must be a vector");
|
||||
return Builder.CreateIntrinsic(
|
||||
/*ReturnType=*/I->getType(), Intrinsic::spv_reflect,
|
||||
ArrayRef<Value *>{I, N}, nullptr, "spv.reflect");
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
442
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
Normal file
442
clang/lib/CodeGen/TargetBuiltins/SystemZ.cpp
Normal file
@@ -0,0 +1,442 @@
|
||||
//===------ SystemZ.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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 contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "TargetInfo.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsS390.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
/// Handle a SystemZ function in which the final argument is a pointer
|
||||
/// to an int that receives the post-instruction CC value. At the LLVM level
|
||||
/// this is represented as a function that returns a {result, cc} pair.
|
||||
static Value *EmitSystemZIntrinsicWithCC(CodeGenFunction &CGF,
|
||||
unsigned IntrinsicID,
|
||||
const CallExpr *E) {
|
||||
unsigned NumArgs = E->getNumArgs() - 1;
|
||||
SmallVector<Value *, 8> Args(NumArgs);
|
||||
for (unsigned I = 0; I < NumArgs; ++I)
|
||||
Args[I] = CGF.EmitScalarExpr(E->getArg(I));
|
||||
Address CCPtr = CGF.EmitPointerWithAlignment(E->getArg(NumArgs));
|
||||
Function *F = CGF.CGM.getIntrinsic(IntrinsicID);
|
||||
Value *Call = CGF.Builder.CreateCall(F, Args);
|
||||
Value *CC = CGF.Builder.CreateExtractValue(Call, 1);
|
||||
CGF.Builder.CreateStore(CC, CCPtr);
|
||||
return CGF.Builder.CreateExtractValue(Call, 0);
|
||||
}
|
||||
|
||||
Value *CodeGenFunction::EmitSystemZBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
switch (BuiltinID) {
|
||||
case SystemZ::BI__builtin_tbegin: {
|
||||
Value *TDB = EmitScalarExpr(E->getArg(0));
|
||||
Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::s390_tbegin);
|
||||
return Builder.CreateCall(F, {TDB, Control});
|
||||
}
|
||||
case SystemZ::BI__builtin_tbegin_nofloat: {
|
||||
Value *TDB = EmitScalarExpr(E->getArg(0));
|
||||
Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff0c);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::s390_tbegin_nofloat);
|
||||
return Builder.CreateCall(F, {TDB, Control});
|
||||
}
|
||||
case SystemZ::BI__builtin_tbeginc: {
|
||||
Value *TDB = llvm::ConstantPointerNull::get(Int8PtrTy);
|
||||
Value *Control = llvm::ConstantInt::get(Int32Ty, 0xff08);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::s390_tbeginc);
|
||||
return Builder.CreateCall(F, {TDB, Control});
|
||||
}
|
||||
case SystemZ::BI__builtin_tabort: {
|
||||
Value *Data = EmitScalarExpr(E->getArg(0));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::s390_tabort);
|
||||
return Builder.CreateCall(F, Builder.CreateSExt(Data, Int64Ty, "tabort"));
|
||||
}
|
||||
case SystemZ::BI__builtin_non_tx_store: {
|
||||
Value *Address = EmitScalarExpr(E->getArg(0));
|
||||
Value *Data = EmitScalarExpr(E->getArg(1));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::s390_ntstg);
|
||||
return Builder.CreateCall(F, {Data, Address});
|
||||
}
|
||||
|
||||
// Vector builtins. Note that most vector builtins are mapped automatically
|
||||
// to target-specific LLVM intrinsics. The ones handled specially here can
|
||||
// be represented via standard LLVM IR, which is preferable to enable common
|
||||
// LLVM optimizations.
|
||||
|
||||
case SystemZ::BI__builtin_s390_vclzb:
|
||||
case SystemZ::BI__builtin_s390_vclzh:
|
||||
case SystemZ::BI__builtin_s390_vclzf:
|
||||
case SystemZ::BI__builtin_s390_vclzg:
|
||||
case SystemZ::BI__builtin_s390_vclzq: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::ctlz, ResultType);
|
||||
return Builder.CreateCall(F, {X, Undef});
|
||||
}
|
||||
|
||||
case SystemZ::BI__builtin_s390_vctzb:
|
||||
case SystemZ::BI__builtin_s390_vctzh:
|
||||
case SystemZ::BI__builtin_s390_vctzf:
|
||||
case SystemZ::BI__builtin_s390_vctzg:
|
||||
case SystemZ::BI__builtin_s390_vctzq: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Undef = ConstantInt::get(Builder.getInt1Ty(), false);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::cttz, ResultType);
|
||||
return Builder.CreateCall(F, {X, Undef});
|
||||
}
|
||||
|
||||
case SystemZ::BI__builtin_s390_verllb:
|
||||
case SystemZ::BI__builtin_s390_verllh:
|
||||
case SystemZ::BI__builtin_s390_verllf:
|
||||
case SystemZ::BI__builtin_s390_verllg: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
llvm::Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Value *Amt = EmitScalarExpr(E->getArg(1));
|
||||
// Splat scalar rotate amount to vector type.
|
||||
unsigned NumElts = cast<llvm::FixedVectorType>(ResultType)->getNumElements();
|
||||
Amt = Builder.CreateIntCast(Amt, ResultType->getScalarType(), false);
|
||||
Amt = Builder.CreateVectorSplat(NumElts, Amt);
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fshl, ResultType);
|
||||
return Builder.CreateCall(F, { Src, Src, Amt });
|
||||
}
|
||||
|
||||
case SystemZ::BI__builtin_s390_verllvb:
|
||||
case SystemZ::BI__builtin_s390_verllvh:
|
||||
case SystemZ::BI__builtin_s390_verllvf:
|
||||
case SystemZ::BI__builtin_s390_verllvg: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
llvm::Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Value *Amt = EmitScalarExpr(E->getArg(1));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fshl, ResultType);
|
||||
return Builder.CreateCall(F, { Src, Src, Amt });
|
||||
}
|
||||
|
||||
case SystemZ::BI__builtin_s390_vfsqsb:
|
||||
case SystemZ::BI__builtin_s390_vfsqdb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_sqrt, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, { X });
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::sqrt, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfmasb:
|
||||
case SystemZ::BI__builtin_s390_vfmadb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
Value *Z = EmitScalarExpr(E->getArg(2));
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, {X, Y, Z});
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
|
||||
return Builder.CreateCall(F, {X, Y, Z});
|
||||
}
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfmssb:
|
||||
case SystemZ::BI__builtin_s390_vfmsdb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
Value *Z = EmitScalarExpr(E->getArg(2));
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")});
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
|
||||
return Builder.CreateCall(F, {X, Y, Builder.CreateFNeg(Z, "neg")});
|
||||
}
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfnmasb:
|
||||
case SystemZ::BI__builtin_s390_vfnmadb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
Value *Z = EmitScalarExpr(E->getArg(2));
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType);
|
||||
return Builder.CreateFNeg(Builder.CreateConstrainedFPCall(F, {X, Y, Z}), "neg");
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
|
||||
return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, Z}), "neg");
|
||||
}
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfnmssb:
|
||||
case SystemZ::BI__builtin_s390_vfnmsdb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
Value *Z = EmitScalarExpr(E->getArg(2));
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::experimental_constrained_fma, ResultType);
|
||||
Value *NegZ = Builder.CreateFNeg(Z, "sub");
|
||||
return Builder.CreateFNeg(Builder.CreateConstrainedFPCall(F, {X, Y, NegZ}));
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fma, ResultType);
|
||||
Value *NegZ = Builder.CreateFNeg(Z, "neg");
|
||||
return Builder.CreateFNeg(Builder.CreateCall(F, {X, Y, NegZ}));
|
||||
}
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vflpsb:
|
||||
case SystemZ::BI__builtin_s390_vflpdb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vflnsb:
|
||||
case SystemZ::BI__builtin_s390_vflndb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::fabs, ResultType);
|
||||
return Builder.CreateFNeg(Builder.CreateCall(F, X), "neg");
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfisb:
|
||||
case SystemZ::BI__builtin_s390_vfidb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
// Constant-fold the M4 and M5 mask arguments.
|
||||
llvm::APSInt M4 = *E->getArg(1)->getIntegerConstantExpr(getContext());
|
||||
llvm::APSInt M5 = *E->getArg(2)->getIntegerConstantExpr(getContext());
|
||||
// Check whether this instance can be represented via a LLVM standard
|
||||
// intrinsic. We only support some combinations of M4 and M5.
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
Intrinsic::ID CI;
|
||||
switch (M4.getZExtValue()) {
|
||||
default: break;
|
||||
case 0: // IEEE-inexact exception allowed
|
||||
switch (M5.getZExtValue()) {
|
||||
default: break;
|
||||
case 0: ID = Intrinsic::rint;
|
||||
CI = Intrinsic::experimental_constrained_rint; break;
|
||||
}
|
||||
break;
|
||||
case 4: // IEEE-inexact exception suppressed
|
||||
switch (M5.getZExtValue()) {
|
||||
default: break;
|
||||
case 0: ID = Intrinsic::nearbyint;
|
||||
CI = Intrinsic::experimental_constrained_nearbyint; break;
|
||||
case 1: ID = Intrinsic::round;
|
||||
CI = Intrinsic::experimental_constrained_round; break;
|
||||
case 4: ID = Intrinsic::roundeven;
|
||||
CI = Intrinsic::experimental_constrained_roundeven; break;
|
||||
case 5: ID = Intrinsic::trunc;
|
||||
CI = Intrinsic::experimental_constrained_trunc; break;
|
||||
case 6: ID = Intrinsic::ceil;
|
||||
CI = Intrinsic::experimental_constrained_ceil; break;
|
||||
case 7: ID = Intrinsic::floor;
|
||||
CI = Intrinsic::experimental_constrained_floor; break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (ID != Intrinsic::not_intrinsic) {
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(CI, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, X);
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
}
|
||||
switch (BuiltinID) { // FIXME: constrained version?
|
||||
case SystemZ::BI__builtin_s390_vfisb: ID = Intrinsic::s390_vfisb; break;
|
||||
case SystemZ::BI__builtin_s390_vfidb: ID = Intrinsic::s390_vfidb; break;
|
||||
default: llvm_unreachable("Unknown BuiltinID");
|
||||
}
|
||||
Function *F = CGM.getIntrinsic(ID);
|
||||
Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
|
||||
Value *M5Value = llvm::ConstantInt::get(getLLVMContext(), M5);
|
||||
return Builder.CreateCall(F, {X, M4Value, M5Value});
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfmaxsb:
|
||||
case SystemZ::BI__builtin_s390_vfmaxdb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
// Constant-fold the M4 mask argument.
|
||||
llvm::APSInt M4 = *E->getArg(2)->getIntegerConstantExpr(getContext());
|
||||
// Check whether this instance can be represented via a LLVM standard
|
||||
// intrinsic. We only support some values of M4.
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
Intrinsic::ID CI;
|
||||
switch (M4.getZExtValue()) {
|
||||
default: break;
|
||||
case 4: ID = Intrinsic::maxnum;
|
||||
CI = Intrinsic::experimental_constrained_maxnum; break;
|
||||
}
|
||||
if (ID != Intrinsic::not_intrinsic) {
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(CI, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, {X, Y});
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, {X, Y});
|
||||
}
|
||||
}
|
||||
switch (BuiltinID) {
|
||||
case SystemZ::BI__builtin_s390_vfmaxsb: ID = Intrinsic::s390_vfmaxsb; break;
|
||||
case SystemZ::BI__builtin_s390_vfmaxdb: ID = Intrinsic::s390_vfmaxdb; break;
|
||||
default: llvm_unreachable("Unknown BuiltinID");
|
||||
}
|
||||
Function *F = CGM.getIntrinsic(ID);
|
||||
Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
|
||||
return Builder.CreateCall(F, {X, Y, M4Value});
|
||||
}
|
||||
case SystemZ::BI__builtin_s390_vfminsb:
|
||||
case SystemZ::BI__builtin_s390_vfmindb: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Value *Y = EmitScalarExpr(E->getArg(1));
|
||||
// Constant-fold the M4 mask argument.
|
||||
llvm::APSInt M4 = *E->getArg(2)->getIntegerConstantExpr(getContext());
|
||||
// Check whether this instance can be represented via a LLVM standard
|
||||
// intrinsic. We only support some values of M4.
|
||||
Intrinsic::ID ID = Intrinsic::not_intrinsic;
|
||||
Intrinsic::ID CI;
|
||||
switch (M4.getZExtValue()) {
|
||||
default: break;
|
||||
case 4: ID = Intrinsic::minnum;
|
||||
CI = Intrinsic::experimental_constrained_minnum; break;
|
||||
}
|
||||
if (ID != Intrinsic::not_intrinsic) {
|
||||
if (Builder.getIsFPConstrained()) {
|
||||
Function *F = CGM.getIntrinsic(CI, ResultType);
|
||||
return Builder.CreateConstrainedFPCall(F, {X, Y});
|
||||
} else {
|
||||
Function *F = CGM.getIntrinsic(ID, ResultType);
|
||||
return Builder.CreateCall(F, {X, Y});
|
||||
}
|
||||
}
|
||||
switch (BuiltinID) {
|
||||
case SystemZ::BI__builtin_s390_vfminsb: ID = Intrinsic::s390_vfminsb; break;
|
||||
case SystemZ::BI__builtin_s390_vfmindb: ID = Intrinsic::s390_vfmindb; break;
|
||||
default: llvm_unreachable("Unknown BuiltinID");
|
||||
}
|
||||
Function *F = CGM.getIntrinsic(ID);
|
||||
Value *M4Value = llvm::ConstantInt::get(getLLVMContext(), M4);
|
||||
return Builder.CreateCall(F, {X, Y, M4Value});
|
||||
}
|
||||
|
||||
case SystemZ::BI__builtin_s390_vlbrh:
|
||||
case SystemZ::BI__builtin_s390_vlbrf:
|
||||
case SystemZ::BI__builtin_s390_vlbrg:
|
||||
case SystemZ::BI__builtin_s390_vlbrq: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *X = EmitScalarExpr(E->getArg(0));
|
||||
Function *F = CGM.getIntrinsic(Intrinsic::bswap, ResultType);
|
||||
return Builder.CreateCall(F, X);
|
||||
}
|
||||
|
||||
// Vector intrinsics that output the post-instruction CC value.
|
||||
|
||||
#define INTRINSIC_WITH_CC(NAME) \
|
||||
case SystemZ::BI__builtin_##NAME: \
|
||||
return EmitSystemZIntrinsicWithCC(*this, Intrinsic::NAME, E)
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vpkshs);
|
||||
INTRINSIC_WITH_CC(s390_vpksfs);
|
||||
INTRINSIC_WITH_CC(s390_vpksgs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vpklshs);
|
||||
INTRINSIC_WITH_CC(s390_vpklsfs);
|
||||
INTRINSIC_WITH_CC(s390_vpklsgs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vceqbs);
|
||||
INTRINSIC_WITH_CC(s390_vceqhs);
|
||||
INTRINSIC_WITH_CC(s390_vceqfs);
|
||||
INTRINSIC_WITH_CC(s390_vceqgs);
|
||||
INTRINSIC_WITH_CC(s390_vceqqs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vchbs);
|
||||
INTRINSIC_WITH_CC(s390_vchhs);
|
||||
INTRINSIC_WITH_CC(s390_vchfs);
|
||||
INTRINSIC_WITH_CC(s390_vchgs);
|
||||
INTRINSIC_WITH_CC(s390_vchqs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vchlbs);
|
||||
INTRINSIC_WITH_CC(s390_vchlhs);
|
||||
INTRINSIC_WITH_CC(s390_vchlfs);
|
||||
INTRINSIC_WITH_CC(s390_vchlgs);
|
||||
INTRINSIC_WITH_CC(s390_vchlqs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfaebs);
|
||||
INTRINSIC_WITH_CC(s390_vfaehs);
|
||||
INTRINSIC_WITH_CC(s390_vfaefs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfaezbs);
|
||||
INTRINSIC_WITH_CC(s390_vfaezhs);
|
||||
INTRINSIC_WITH_CC(s390_vfaezfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfeebs);
|
||||
INTRINSIC_WITH_CC(s390_vfeehs);
|
||||
INTRINSIC_WITH_CC(s390_vfeefs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfeezbs);
|
||||
INTRINSIC_WITH_CC(s390_vfeezhs);
|
||||
INTRINSIC_WITH_CC(s390_vfeezfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfenebs);
|
||||
INTRINSIC_WITH_CC(s390_vfenehs);
|
||||
INTRINSIC_WITH_CC(s390_vfenefs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfenezbs);
|
||||
INTRINSIC_WITH_CC(s390_vfenezhs);
|
||||
INTRINSIC_WITH_CC(s390_vfenezfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vistrbs);
|
||||
INTRINSIC_WITH_CC(s390_vistrhs);
|
||||
INTRINSIC_WITH_CC(s390_vistrfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vstrcbs);
|
||||
INTRINSIC_WITH_CC(s390_vstrchs);
|
||||
INTRINSIC_WITH_CC(s390_vstrcfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vstrczbs);
|
||||
INTRINSIC_WITH_CC(s390_vstrczhs);
|
||||
INTRINSIC_WITH_CC(s390_vstrczfs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vfcesbs);
|
||||
INTRINSIC_WITH_CC(s390_vfcedbs);
|
||||
INTRINSIC_WITH_CC(s390_vfchsbs);
|
||||
INTRINSIC_WITH_CC(s390_vfchdbs);
|
||||
INTRINSIC_WITH_CC(s390_vfchesbs);
|
||||
INTRINSIC_WITH_CC(s390_vfchedbs);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vftcisb);
|
||||
INTRINSIC_WITH_CC(s390_vftcidb);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vstrsb);
|
||||
INTRINSIC_WITH_CC(s390_vstrsh);
|
||||
INTRINSIC_WITH_CC(s390_vstrsf);
|
||||
|
||||
INTRINSIC_WITH_CC(s390_vstrszb);
|
||||
INTRINSIC_WITH_CC(s390_vstrszh);
|
||||
INTRINSIC_WITH_CC(s390_vstrszf);
|
||||
|
||||
#undef INTRINSIC_WITH_CC
|
||||
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
625
clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
Normal file
625
clang/lib/CodeGen/TargetBuiltins/WebAssembly.cpp
Normal file
@@ -0,0 +1,625 @@
|
||||
//===-- WebAssembly.cpp - Emit LLVM Code for builtins ---------------------===//
|
||||
//
|
||||
// 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 contains code to emit Builtin calls as LLVM code.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "ABIInfo.h"
|
||||
#include "CGBuiltin.h"
|
||||
#include "CodeGenFunction.h"
|
||||
#include "TargetInfo.h"
|
||||
#include "clang/Basic/TargetBuiltins.h"
|
||||
#include "llvm/IR/InlineAsm.h"
|
||||
#include "llvm/IR/Intrinsics.h"
|
||||
#include "llvm/IR/IntrinsicsWebAssembly.h"
|
||||
|
||||
using namespace clang;
|
||||
using namespace CodeGen;
|
||||
using namespace llvm;
|
||||
|
||||
Value *CodeGenFunction::EmitWebAssemblyBuiltinExpr(unsigned BuiltinID,
|
||||
const CallExpr *E) {
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_memory_size: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *I = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_memory_size, ResultType);
|
||||
return Builder.CreateCall(Callee, I);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_memory_grow: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Value *Args[] = {EmitScalarExpr(E->getArg(0)),
|
||||
EmitScalarExpr(E->getArg(1))};
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_memory_grow, ResultType);
|
||||
return Builder.CreateCall(Callee, Args);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_tls_size: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_size, ResultType);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_tls_align: {
|
||||
llvm::Type *ResultType = ConvertType(E->getType());
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_align, ResultType);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_tls_base: {
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_tls_base);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_throw: {
|
||||
Value *Tag = EmitScalarExpr(E->getArg(0));
|
||||
Value *Obj = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_throw);
|
||||
return EmitRuntimeCallOrInvoke(Callee, {Tag, Obj});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_rethrow: {
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_rethrow);
|
||||
return EmitRuntimeCallOrInvoke(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_memory_atomic_wait32: {
|
||||
Value *Addr = EmitScalarExpr(E->getArg(0));
|
||||
Value *Expected = EmitScalarExpr(E->getArg(1));
|
||||
Value *Timeout = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait32);
|
||||
return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_memory_atomic_wait64: {
|
||||
Value *Addr = EmitScalarExpr(E->getArg(0));
|
||||
Value *Expected = EmitScalarExpr(E->getArg(1));
|
||||
Value *Timeout = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_wait64);
|
||||
return Builder.CreateCall(Callee, {Addr, Expected, Timeout});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_memory_atomic_notify: {
|
||||
Value *Addr = EmitScalarExpr(E->getArg(0));
|
||||
Value *Count = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_memory_atomic_notify);
|
||||
return Builder.CreateCall(Callee, {Addr, Count});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_trunc_s_i32_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_s_i32_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_s_i64_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_s_i64_f64: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Type *ResT = ConvertType(E->getType());
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_trunc_signed, {ResT, Src->getType()});
|
||||
return Builder.CreateCall(Callee, {Src});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_trunc_u_i32_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_u_i32_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_u_i64_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_u_i64_f64: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Type *ResT = ConvertType(E->getType());
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_trunc_unsigned,
|
||||
{ResT, Src->getType()});
|
||||
return Builder.CreateCall(Callee, {Src});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i64_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i16x8_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_s_i32x4_f32x4: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Type *ResT = ConvertType(E->getType());
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::fptosi_sat, {ResT, Src->getType()});
|
||||
return Builder.CreateCall(Callee, {Src});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f32:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i64_f64:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i16x8_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_saturate_u_i32x4_f32x4: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
llvm::Type *ResT = ConvertType(E->getType());
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::fptoui_sat, {ResT, Src->getType()});
|
||||
return Builder.CreateCall(Callee, {Src});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_min_f32:
|
||||
case WebAssembly::BI__builtin_wasm_min_f64:
|
||||
case WebAssembly::BI__builtin_wasm_min_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_min_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_min_f64x2: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::minimum, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_max_f32:
|
||||
case WebAssembly::BI__builtin_wasm_max_f64:
|
||||
case WebAssembly::BI__builtin_wasm_max_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_max_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_max_f64x2: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::maximum, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_pmin_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_pmin_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_pmin_f64x2: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_pmin, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_pmax_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_pmax_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_pmax_f64x2: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_pmax, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_floor_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_floor_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_floor_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f64x2: {
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_ceil_f64x2:
|
||||
IntNo = Intrinsic::ceil;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_floor_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_floor_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_floor_f64x2:
|
||||
IntNo = Intrinsic::floor;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_f64x2:
|
||||
IntNo = Intrinsic::trunc;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_nearest_f64x2:
|
||||
IntNo = Intrinsic::nearbyint;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Value *Value = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, Value);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_ref_null_extern: {
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_extern);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_ref_null_func: {
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_ref_null_func);
|
||||
return Builder.CreateCall(Callee);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_swizzle_i8x16: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
Value *Indices = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_swizzle);
|
||||
return Builder.CreateCall(Callee, {Src, Indices});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_abs_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_abs_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_abs_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_abs_i64x2: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
Value *Neg = Builder.CreateNeg(Vec, "neg");
|
||||
Constant *Zero = llvm::Constant::getNullValue(Vec->getType());
|
||||
Value *ICmp = Builder.CreateICmpSLT(Vec, Zero, "abscond");
|
||||
return Builder.CreateSelect(ICmp, Neg, Vec, "abs");
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_avgr_u_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_avgr_u_i16x8: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_avgr_unsigned,
|
||||
ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_q15mulr_sat_s_i16x8: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_q15mulr_sat_signed);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_s_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_s_i32x4:
|
||||
IntNo = Intrinsic::wasm_extadd_pairwise_signed;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i8x16_u_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_extadd_pairwise_i16x8_u_i32x4:
|
||||
IntNo = Intrinsic::wasm_extadd_pairwise_unsigned;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, Vec);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_bitselect: {
|
||||
Value *V1 = EmitScalarExpr(E->getArg(0));
|
||||
Value *V2 = EmitScalarExpr(E->getArg(1));
|
||||
Value *C = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_bitselect, ConvertType(E->getType()));
|
||||
return Builder.CreateCall(Callee, {V1, V2, C});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_dot_s_i32x4_i16x8: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_dot);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_any_true_v128:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i64x2: {
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_any_true_v128:
|
||||
IntNo = Intrinsic::wasm_anytrue;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_all_true_i64x2:
|
||||
IntNo = Intrinsic::wasm_alltrue;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, Vec->getType());
|
||||
return Builder.CreateCall(Callee, {Vec});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_bitmask_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_bitmask_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_bitmask_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_bitmask_i64x2: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_bitmask, Vec->getType());
|
||||
return Builder.CreateCall(Callee, {Vec});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_abs_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_abs_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_abs_f64x2: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::fabs, Vec->getType());
|
||||
return Builder.CreateCall(Callee, {Vec});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_sqrt_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_sqrt_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_sqrt_f64x2: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::sqrt, Vec->getType());
|
||||
return Builder.CreateCall(Callee, {Vec});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4: {
|
||||
Value *Low = EmitScalarExpr(E->getArg(0));
|
||||
Value *High = EmitScalarExpr(E->getArg(1));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_narrow_s_i8x16_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_narrow_s_i16x8_i32x4:
|
||||
IntNo = Intrinsic::wasm_narrow_signed;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_narrow_u_i8x16_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_narrow_u_i16x8_i32x4:
|
||||
IntNo = Intrinsic::wasm_narrow_unsigned;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(IntNo, {ConvertType(E->getType()), Low->getType()});
|
||||
return Builder.CreateCall(Callee, {Low, High});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_trunc_sat_s_zero_f64x2_i32x4:
|
||||
IntNo = Intrinsic::fptosi_sat;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_trunc_sat_u_zero_f64x2_i32x4:
|
||||
IntNo = Intrinsic::fptoui_sat;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
llvm::Type *SrcT = Vec->getType();
|
||||
llvm::Type *TruncT = SrcT->getWithNewType(Builder.getInt32Ty());
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, {TruncT, SrcT});
|
||||
Value *Trunc = Builder.CreateCall(Callee, Vec);
|
||||
Value *Splat = Constant::getNullValue(TruncT);
|
||||
return Builder.CreateShuffleVector(Trunc, Splat, {0, 1, 2, 3});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_shuffle_i8x16: {
|
||||
Value *Ops[18];
|
||||
size_t OpIdx = 0;
|
||||
Ops[OpIdx++] = EmitScalarExpr(E->getArg(0));
|
||||
Ops[OpIdx++] = EmitScalarExpr(E->getArg(1));
|
||||
while (OpIdx < 18) {
|
||||
std::optional<llvm::APSInt> LaneConst =
|
||||
E->getArg(OpIdx)->getIntegerConstantExpr(getContext());
|
||||
assert(LaneConst && "Constant arg isn't actually constant?");
|
||||
Ops[OpIdx++] = llvm::ConstantInt::get(getLLVMContext(), *LaneConst);
|
||||
}
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_shuffle);
|
||||
return Builder.CreateCall(Callee, Ops);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2: {
|
||||
Value *A = EmitScalarExpr(E->getArg(0));
|
||||
Value *B = EmitScalarExpr(E->getArg(1));
|
||||
Value *C = EmitScalarExpr(E->getArg(2));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_madd_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_madd;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f16x8:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_nmadd_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_nmadd;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, A->getType());
|
||||
return Builder.CreateCall(Callee, {A, B, C});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i8x16:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i16x8:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_laneselect_i64x2: {
|
||||
Value *A = EmitScalarExpr(E->getArg(0));
|
||||
Value *B = EmitScalarExpr(E->getArg(1));
|
||||
Value *C = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_relaxed_laneselect, A->getType());
|
||||
return Builder.CreateCall(Callee, {A, B, C});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_swizzle_i8x16: {
|
||||
Value *Src = EmitScalarExpr(E->getArg(0));
|
||||
Value *Indices = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_swizzle);
|
||||
return Builder.CreateCall(Callee, {Src, Indices});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_min_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_min_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_min;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_max_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_max_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_max;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Function *Callee = CGM.getIntrinsic(IntNo, LHS->getType());
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2:
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2: {
|
||||
Value *Vec = EmitScalarExpr(E->getArg(0));
|
||||
unsigned IntNo;
|
||||
switch (BuiltinID) {
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_i32x4_f32x4:
|
||||
IntNo = Intrinsic::wasm_relaxed_trunc_signed;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_i32x4_f32x4:
|
||||
IntNo = Intrinsic::wasm_relaxed_trunc_unsigned;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_s_zero_i32x4_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_trunc_signed_zero;
|
||||
break;
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_trunc_u_zero_i32x4_f64x2:
|
||||
IntNo = Intrinsic::wasm_relaxed_trunc_unsigned_zero;
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("unexpected builtin ID");
|
||||
}
|
||||
Function *Callee = CGM.getIntrinsic(IntNo);
|
||||
return Builder.CreateCall(Callee, {Vec});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_q15mulr_s_i16x8: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_relaxed_q15mulr_signed);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_s_i16x8: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_signed);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_dot_i8x16_i7x16_add_s_i32x4: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Value *Acc = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_i8x16_i7x16_add_signed);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS, Acc});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_relaxed_dot_bf16x8_add_f32_f32x4: {
|
||||
Value *LHS = EmitScalarExpr(E->getArg(0));
|
||||
Value *RHS = EmitScalarExpr(E->getArg(1));
|
||||
Value *Acc = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee =
|
||||
CGM.getIntrinsic(Intrinsic::wasm_relaxed_dot_bf16x8_add_f32);
|
||||
return Builder.CreateCall(Callee, {LHS, RHS, Acc});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_loadf16_f32: {
|
||||
Value *Addr = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_loadf16_f32);
|
||||
return Builder.CreateCall(Callee, {Addr});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_storef16_f32: {
|
||||
Value *Val = EmitScalarExpr(E->getArg(0));
|
||||
Value *Addr = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_storef16_f32);
|
||||
return Builder.CreateCall(Callee, {Val, Addr});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_splat_f16x8: {
|
||||
Value *Val = EmitScalarExpr(E->getArg(0));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_splat_f16x8);
|
||||
return Builder.CreateCall(Callee, {Val});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_extract_lane_f16x8: {
|
||||
Value *Vector = EmitScalarExpr(E->getArg(0));
|
||||
Value *Index = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_extract_lane_f16x8);
|
||||
return Builder.CreateCall(Callee, {Vector, Index});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_replace_lane_f16x8: {
|
||||
Value *Vector = EmitScalarExpr(E->getArg(0));
|
||||
Value *Index = EmitScalarExpr(E->getArg(1));
|
||||
Value *Val = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_replace_lane_f16x8);
|
||||
return Builder.CreateCall(Callee, {Vector, Index, Val});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_get: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Value *Index = EmitScalarExpr(E->getArg(1));
|
||||
Function *Callee;
|
||||
if (E->getType().isWebAssemblyExternrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_externref);
|
||||
else if (E->getType().isWebAssemblyFuncrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_get_funcref);
|
||||
else
|
||||
llvm_unreachable(
|
||||
"Unexpected reference type for __builtin_wasm_table_get");
|
||||
return Builder.CreateCall(Callee, {Table, Index});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_set: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Value *Index = EmitScalarExpr(E->getArg(1));
|
||||
Value *Val = EmitScalarExpr(E->getArg(2));
|
||||
Function *Callee;
|
||||
if (E->getArg(2)->getType().isWebAssemblyExternrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_externref);
|
||||
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_set_funcref);
|
||||
else
|
||||
llvm_unreachable(
|
||||
"Unexpected reference type for __builtin_wasm_table_set");
|
||||
return Builder.CreateCall(Callee, {Table, Index, Val});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_size: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *Value = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_size);
|
||||
return Builder.CreateCall(Callee, Value);
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_grow: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Value *Val = EmitScalarExpr(E->getArg(1));
|
||||
Value *NElems = EmitScalarExpr(E->getArg(2));
|
||||
|
||||
Function *Callee;
|
||||
if (E->getArg(1)->getType().isWebAssemblyExternrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_grow_externref);
|
||||
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
|
||||
else
|
||||
llvm_unreachable(
|
||||
"Unexpected reference type for __builtin_wasm_table_grow");
|
||||
|
||||
return Builder.CreateCall(Callee, {Table, Val, NElems});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_fill: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *Table = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Value *Index = EmitScalarExpr(E->getArg(1));
|
||||
Value *Val = EmitScalarExpr(E->getArg(2));
|
||||
Value *NElems = EmitScalarExpr(E->getArg(3));
|
||||
|
||||
Function *Callee;
|
||||
if (E->getArg(2)->getType().isWebAssemblyExternrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_externref);
|
||||
else if (E->getArg(2)->getType().isWebAssemblyFuncrefType())
|
||||
Callee = CGM.getIntrinsic(Intrinsic::wasm_table_fill_funcref);
|
||||
else
|
||||
llvm_unreachable(
|
||||
"Unexpected reference type for __builtin_wasm_table_fill");
|
||||
|
||||
return Builder.CreateCall(Callee, {Table, Index, Val, NElems});
|
||||
}
|
||||
case WebAssembly::BI__builtin_wasm_table_copy: {
|
||||
assert(E->getArg(0)->getType()->isArrayType());
|
||||
Value *TableX = EmitArrayToPointerDecay(E->getArg(0)).emitRawPointer(*this);
|
||||
Value *TableY = EmitArrayToPointerDecay(E->getArg(1)).emitRawPointer(*this);
|
||||
Value *DstIdx = EmitScalarExpr(E->getArg(2));
|
||||
Value *SrcIdx = EmitScalarExpr(E->getArg(3));
|
||||
Value *NElems = EmitScalarExpr(E->getArg(4));
|
||||
|
||||
Function *Callee = CGM.getIntrinsic(Intrinsic::wasm_table_copy);
|
||||
|
||||
return Builder.CreateCall(Callee, {TableX, TableY, SrcIdx, DstIdx, NElems});
|
||||
}
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
3277
clang/lib/CodeGen/TargetBuiltins/X86.cpp
Normal file
3277
clang/lib/CodeGen/TargetBuiltins/X86.cpp
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user