40 changes: 40 additions & 0 deletions clang/lib/Basic/Targets/AArch64.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,34 @@
namespace clang {
namespace targets {

enum AArch64AddrSpace { ptr32_sptr = 270, ptr32_uptr = 271, ptr64 = 272 };

static const unsigned ARM64AddrSpaceMap[] = {
0, // Default
0, // opencl_global
0, // opencl_local
0, // opencl_constant
0, // opencl_private
0, // opencl_generic
0, // opencl_global_device
0, // opencl_global_host
0, // cuda_device
0, // cuda_constant
0, // cuda_shared
0, // sycl_global
0, // sycl_global_device
0, // sycl_global_host
0, // sycl_local
0, // sycl_private
static_cast<unsigned>(AArch64AddrSpace::ptr32_sptr),
static_cast<unsigned>(AArch64AddrSpace::ptr32_uptr),
static_cast<unsigned>(AArch64AddrSpace::ptr64),
0, // hlsl_groupshared
// Wasm address space values for this target are dummy values,
// as it is only enabled for Wasm targets.
20, // wasm_funcref
};

class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {
virtual void setDataLayout() = 0;
static const TargetInfo::GCCRegAlias GCCRegAliases[];
Expand Down Expand Up @@ -207,6 +235,18 @@ class LLVM_LIBRARY_VISIBILITY AArch64TargetInfo : public TargetInfo {

bool validateGlobalRegisterVariable(StringRef RegName, unsigned RegSize,
bool &HasSizeMismatch) const override;

uint64_t getPointerWidthV(LangAS AddrSpace) const override {
if (AddrSpace == LangAS::ptr32_sptr || AddrSpace == LangAS::ptr32_uptr)
return 32;
if (AddrSpace == LangAS::ptr64)
return 64;
return PointerWidth;
}

uint64_t getPointerAlignV(LangAS AddrSpace) const override {
return getPointerWidthV(AddrSpace);
}
};

class LLVM_LIBRARY_VISIBILITY AArch64leTargetInfo : public AArch64TargetInfo {
Expand Down
57 changes: 30 additions & 27 deletions clang/lib/CodeGen/CGBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1288,9 +1288,8 @@ static llvm::Value *EmitBitTestIntrinsic(CodeGenFunction &CGF,
// Bit = BitBaseI8[BitPos >> 3] & (1 << (BitPos & 0x7)) != 0;
Value *ByteIndex = CGF.Builder.CreateAShr(
BitPos, llvm::ConstantInt::get(BitPos->getType(), 3), "bittest.byteidx");
Value *BitBaseI8 = CGF.Builder.CreatePointerCast(BitBase, CGF.Int8PtrTy);
Address ByteAddr(CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, BitBaseI8,
ByteIndex, "bittest.byteaddr"),
Address ByteAddr(CGF.Builder.CreateInBoundsGEP(CGF.Int8Ty, BitBase, ByteIndex,
"bittest.byteaddr"),
CGF.Int8Ty, CharUnits::One());
Value *PosLow =
CGF.Builder.CreateAnd(CGF.Builder.CreateTrunc(BitPos, CGF.Int8Ty),
Expand Down Expand Up @@ -5658,14 +5657,13 @@ RValue CodeGenFunction::EmitBuiltinExpr(const GlobalDecl GD, unsigned BuiltinID,
*Arg3 = EmitScalarExpr(E->getArg(3));
llvm::FunctionType *FTy = llvm::FunctionType::get(
Int32Ty, llvm::ArrayRef<llvm::Type *>(ArgTys), false);
Value *BCast = Builder.CreatePointerCast(Arg3, I8PTy);
// We know the third argument is an integer type, but we may need to cast
// it to i32.
if (Arg2->getType() != Int32Ty)
Arg2 = Builder.CreateZExtOrTrunc(Arg2, Int32Ty);
return RValue::get(
EmitRuntimeCall(CGM.CreateRuntimeFunction(FTy, Name),
{Arg0, Arg1, Arg2, BCast, PacketSize, PacketAlign}));
{Arg0, Arg1, Arg2, Arg3, PacketSize, PacketAlign}));
}
}
// OpenCL v2.0 s6.13.16 ,s9.17.3.5 - Built-in pipe reserve read and write
Expand Down Expand Up @@ -11317,7 +11315,6 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
Value *Dst = EmitScalarExpr(E->getArg(0));
Value *Val = EmitScalarExpr(E->getArg(1));
Value *Size = EmitScalarExpr(E->getArg(2));
Dst = Builder.CreatePointerCast(Dst, Int8PtrTy);
Val = Builder.CreateTrunc(Val, Int8Ty);
Size = Builder.CreateIntCast(Size, Int64Ty, false);
return Builder.CreateCall(
Expand All @@ -11342,34 +11339,27 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
}

if (MTEIntrinsicID != Intrinsic::not_intrinsic) {
llvm::Type *T = ConvertType(E->getType());

if (MTEIntrinsicID == Intrinsic::aarch64_irg) {
Value *Pointer = EmitScalarExpr(E->getArg(0));
Value *Mask = EmitScalarExpr(E->getArg(1));

Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
Mask = Builder.CreateZExt(Mask, Int64Ty);
Value *RV = Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {Pointer, Mask});
return Builder.CreatePointerCast(RV, T);
return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID),
{Pointer, Mask});
}
if (MTEIntrinsicID == Intrinsic::aarch64_addg) {
Value *Pointer = EmitScalarExpr(E->getArg(0));
Value *TagOffset = EmitScalarExpr(E->getArg(1));

Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
TagOffset = Builder.CreateZExt(TagOffset, Int64Ty);
Value *RV = Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {Pointer, TagOffset});
return Builder.CreatePointerCast(RV, T);
return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID),
{Pointer, TagOffset});
}
if (MTEIntrinsicID == Intrinsic::aarch64_gmi) {
Value *Pointer = EmitScalarExpr(E->getArg(0));
Value *ExcludedMask = EmitScalarExpr(E->getArg(1));

ExcludedMask = Builder.CreateZExt(ExcludedMask, Int64Ty);
Pointer = Builder.CreatePointerCast(Pointer, Int8PtrTy);
return Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {Pointer, ExcludedMask});
}
Expand All @@ -11378,25 +11368,20 @@ Value *CodeGenFunction::EmitAArch64BuiltinExpr(unsigned BuiltinID,
// return address same as input address.
if (MTEIntrinsicID == Intrinsic::aarch64_ldg) {
Value *TagAddress = EmitScalarExpr(E->getArg(0));
TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy);
Value *RV = Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress});
return Builder.CreatePointerCast(RV, T);
return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID),
{TagAddress, TagAddress});
}
// Although it is possible to supply a different tag (to set)
// to this intrinsic (as first arg), for now we supply
// the tag that is in input address arg (common use case).
if (MTEIntrinsicID == Intrinsic::aarch64_stg) {
Value *TagAddress = EmitScalarExpr(E->getArg(0));
TagAddress = Builder.CreatePointerCast(TagAddress, Int8PtrTy);
return Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {TagAddress, TagAddress});
Value *TagAddress = EmitScalarExpr(E->getArg(0));
return Builder.CreateCall(CGM.getIntrinsic(MTEIntrinsicID),
{TagAddress, TagAddress});
}
if (MTEIntrinsicID == Intrinsic::aarch64_subp) {
Value *PointerA = EmitScalarExpr(E->getArg(0));
Value *PointerB = EmitScalarExpr(E->getArg(1));
PointerA = Builder.CreatePointerCast(PointerA, Int8PtrTy);
PointerB = Builder.CreatePointerCast(PointerB, Int8PtrTy);
return Builder.CreateCall(
CGM.getIntrinsic(MTEIntrinsicID), {PointerA, PointerB});
}
Expand Down Expand Up @@ -18920,6 +18905,24 @@ case Builtin::BI__builtin_hlsl_elementwise_isinf: {
return EmitRuntimeCall(
Intrinsic::getOrInsertDeclaration(&CGM.getModule(), ID));
}
case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
// Due to the use of variadic arguments we must explicitly retreive them and
// create our function type.
Value *OpExpr = EmitScalarExpr(E->getArg(0));
Value *OpIndex = EmitScalarExpr(E->getArg(1));
llvm::FunctionType *FT = llvm::FunctionType::get(
OpExpr->getType(), ArrayRef{OpExpr->getType(), OpIndex->getType()},
false);

// Get overloaded name
std::string Name =
Intrinsic::getName(CGM.getHLSLRuntime().getWaveReadLaneAtIntrinsic(),
ArrayRef{OpExpr->getType()}, &CGM.getModule());
return EmitRuntimeCall(CGM.CreateRuntimeFunction(FT, Name, {},
/*Local=*/false,
/*AssumeConvergent=*/true),
ArrayRef{OpExpr, OpIndex}, "hlsl.wave.readlane");
}
case Builtin::BI__builtin_hlsl_elementwise_sign: {
auto *Arg0 = E->getArg(0);
Value *Op0 = EmitScalarExpr(Arg0);
Expand Down
11 changes: 1 addition & 10 deletions clang/lib/CodeGen/CGExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1771,14 +1771,6 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
EmitNewInitializer(*this, E, allocType, elementTy, result, numElements,
allocSizeWithoutCookie);
llvm::Value *resultPtr = result.emitRawPointer(*this);
if (E->isArray()) {
// NewPtr is a pointer to the base element type. If we're
// allocating an array of arrays, we'll need to cast back to the
// array pointer type.
llvm::Type *resultType = ConvertTypeForMem(E->getType());
if (resultPtr->getType() != resultType)
resultPtr = Builder.CreateBitCast(resultPtr, resultType);
}

// Deactivate the 'operator delete' cleanup if we finished
// initialization.
Expand All @@ -1805,7 +1797,7 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
}

void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,
llvm::Value *Ptr, QualType DeleteTy,
llvm::Value *DeletePtr, QualType DeleteTy,
llvm::Value *NumElements,
CharUnits CookieSize) {
assert((!NumElements && CookieSize.isZero()) ||
Expand All @@ -1819,7 +1811,6 @@ void CodeGenFunction::EmitDeleteCall(const FunctionDecl *DeleteFD,

// Pass the pointer itself.
QualType ArgTy = *ParamTypeIt++;
llvm::Value *DeletePtr = Builder.CreateBitCast(Ptr, ConvertType(ArgTy));
DeleteArgs.add(RValue::get(DeletePtr), ArgTy);

// Pass the std::destroying_delete tag if present.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CGHLSLRuntime.h
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ class CGHLSLRuntime {
GENERATE_HLSL_INTRINSIC_FUNCTION(SDot, sdot)
GENERATE_HLSL_INTRINSIC_FUNCTION(UDot, udot)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveIsFirstLane, wave_is_first_lane)
GENERATE_HLSL_INTRINSIC_FUNCTION(WaveReadLaneAt, wave_readlane)

//===----------------------------------------------------------------------===//
// End of reserved area for HLSL intrinsic getters.
Expand Down
1 change: 1 addition & 0 deletions clang/lib/CodeGen/CodeGenFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,7 @@ TypeEvaluationKind CodeGenFunction::getEvaluationKind(QualType type) {
case Type::ObjCObjectPointer:
case Type::Pipe:
case Type::BitInt:
case Type::HLSLAttributedResource:
return TEK_Scalar;

// Complexes.
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/CodeGen/CodeGenTypes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -743,6 +743,9 @@ llvm::Type *CodeGenTypes::ConvertType(QualType T) {
ResultType = llvm::Type::getIntNTy(getLLVMContext(), EIT->getNumBits());
break;
}
case Type::HLSLAttributedResource:
ResultType = CGM.getHLSLRuntime().convertHLSLSpecificType(Ty);
break;
}

assert(ResultType && "Didn't convert a type?");
Expand Down
6 changes: 6 additions & 0 deletions clang/lib/CodeGen/ItaniumCXXABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3947,6 +3947,9 @@ void ItaniumRTTIBuilder::BuildVTablePointer(const Type *Ty) {
// abi::__pointer_to_member_type_info.
VTableName = "_ZTVN10__cxxabiv129__pointer_to_member_type_infoE";
break;

case Type::HLSLAttributedResource:
llvm_unreachable("HLSL doesn't support virtual functions");
}

llvm::Constant *VTable = nullptr;
Expand Down Expand Up @@ -4209,6 +4212,9 @@ llvm::Constant *ItaniumRTTIBuilder::BuildTypeInfo(
case Type::Atomic:
// No fields, at least for the moment.
break;

case Type::HLSLAttributedResource:
llvm_unreachable("HLSL doesn't support RTTI");
}

llvm::Constant *Init = llvm::ConstantStruct::getAnon(Fields);
Expand Down
41 changes: 31 additions & 10 deletions clang/lib/CodeGen/Targets/DirectX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,19 +29,40 @@ class DirectXTargetCodeGenInfo : public TargetCodeGenInfo {

llvm::Type *DirectXTargetCodeGenInfo::getHLSLType(CodeGenModule &CGM,
const Type *Ty) const {
auto *BuiltinTy = dyn_cast<BuiltinType>(Ty);
if (!BuiltinTy || BuiltinTy->getKind() != BuiltinType::HLSLResource)
auto *ResType = dyn_cast<HLSLAttributedResourceType>(Ty);
if (!ResType)
return nullptr;

llvm::LLVMContext &Ctx = CGM.getLLVMContext();
// FIXME: translate __hlsl_resource_t to target("dx.TypedBuffer", <4 x float>,
// 1, 0, 0) only for now (RWBuffer<float4>); more work us needed to determine
// the target ext type and its parameters based on the handle type
// attributes (not yet implemented)
llvm::FixedVectorType *ElemType =
llvm::FixedVectorType::get(llvm::Type::getFloatTy(Ctx), 4);
unsigned Flags[] = {/*IsWriteable*/ 1, /*IsROV*/ 0, /*IsSigned*/ 0};
return llvm::TargetExtType::get(Ctx, "dx.TypedBuffer", {ElemType}, Flags);
const HLSLAttributedResourceType::Attributes &ResAttrs = ResType->getAttrs();
switch (ResAttrs.ResourceClass) {
case llvm::dxil::ResourceClass::UAV:
case llvm::dxil::ResourceClass::SRV: {
// TypedBuffer and RawBuffer both need element type
QualType ContainedTy = ResType->getContainedType();
if (ContainedTy.isNull())
return nullptr;

// convert element type
llvm::Type *ElemType = CGM.getTypes().ConvertType(ContainedTy);

llvm::StringRef TypeName =
ResAttrs.RawBuffer ? "dx.RawBuffer" : "dx.TypedBuffer";
SmallVector<unsigned, 3> Ints = {/*IsWriteable*/ ResAttrs.ResourceClass ==
llvm::dxil::ResourceClass::UAV,
/*IsROV*/ ResAttrs.IsROV};
if (!ResAttrs.RawBuffer)
Ints.push_back(/*IsSigned*/ ContainedTy->isSignedIntegerType());

return llvm::TargetExtType::get(Ctx, TypeName, {ElemType}, Ints);
}
case llvm::dxil::ResourceClass::CBuffer:
llvm_unreachable("dx.CBuffer handles are not implemented yet");
break;
case llvm::dxil::ResourceClass::Sampler:
llvm_unreachable("dx.Sampler handles are not implemented yet");
break;
}
}

} // namespace
Expand Down
8 changes: 8 additions & 0 deletions clang/lib/Driver/ToolChains/Clang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1870,6 +1870,14 @@ void Clang::AddLoongArchTargetArgs(const ArgList &Args,
CmdArgs.push_back("-tune-cpu");
CmdArgs.push_back(Args.MakeArgString(TuneCPU));
}

if (Arg *A = Args.getLastArg(options::OPT_mannotate_tablejump,
options::OPT_mno_annotate_tablejump)) {
if (A->getOption().matches(options::OPT_mannotate_tablejump)) {
CmdArgs.push_back("-mllvm");
CmdArgs.push_back("-loongarch-annotate-tablejump");
}
}
}

void Clang::AddMIPSTargetArgs(const ArgList &Args,
Expand Down
80 changes: 80 additions & 0 deletions clang/lib/Headers/hlsl/hlsl_intrinsics.h
Original file line number Diff line number Diff line change
Expand Up @@ -2097,6 +2097,86 @@ _HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_is_first_lane)
__attribute__((convergent)) bool WaveIsFirstLane();

//===----------------------------------------------------------------------===//
// WaveReadLaneAt builtins
//===----------------------------------------------------------------------===//

// \brief Returns the value of the expression for the given lane index within
// the specified wave.

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) bool WaveReadLaneAt(bool, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) bool2 WaveReadLaneAt(bool2, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) bool3 WaveReadLaneAt(bool3, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) bool4 WaveReadLaneAt(bool4, int32_t);

#ifdef __HLSL_ENABLE_16_BIT
_HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int16_t WaveReadLaneAt(int16_t, int32_t);
_HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int16_t2 WaveReadLaneAt(int16_t2, int32_t);
_HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int16_t3 WaveReadLaneAt(int16_t3, int32_t);
_HLSL_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int16_t4 WaveReadLaneAt(int16_t4, int32_t);
#endif

_HLSL_16BIT_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) half WaveReadLaneAt(half, int32_t);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) half2 WaveReadLaneAt(half2, int32_t);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) half3 WaveReadLaneAt(half3, int32_t);
_HLSL_16BIT_AVAILABILITY(shadermodel, 6.0)
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) half4 WaveReadLaneAt(half4, int32_t);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int WaveReadLaneAt(int, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int2 WaveReadLaneAt(int2, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int3 WaveReadLaneAt(int3, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int4 WaveReadLaneAt(int4, int32_t);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) float WaveReadLaneAt(float, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) float2 WaveReadLaneAt(float2, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) float3 WaveReadLaneAt(float3, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) float4 WaveReadLaneAt(float4, int32_t);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int64_t WaveReadLaneAt(int64_t, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int64_t2 WaveReadLaneAt(int64_t2, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int64_t3 WaveReadLaneAt(int64_t3, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) int64_t4 WaveReadLaneAt(int64_t4, int32_t);

_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) double WaveReadLaneAt(double, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) double2 WaveReadLaneAt(double2, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) double3 WaveReadLaneAt(double3, int32_t);
_HLSL_BUILTIN_ALIAS(__builtin_hlsl_wave_read_lane_at)
__attribute__((convergent)) double4 WaveReadLaneAt(double4, int32_t);

//===----------------------------------------------------------------------===//
// sign builtins
//===----------------------------------------------------------------------===//
Expand Down
29 changes: 25 additions & 4 deletions clang/lib/Sema/CheckExprLifetime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ struct IndirectLocalPathEntry {
GslReferenceInit,
GslPointerInit,
GslPointerAssignment,
DefaultArg,
} Kind;
Expr *E;
union {
Expand Down Expand Up @@ -609,15 +610,22 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
for (unsigned I = 0,
N = std::min<unsigned>(Callee->getNumParams(), Args.size());
I != N; ++I) {
Expr *Arg = Args[I];
RevertToOldSizeRAII RAII(Path);
if (auto *DAE = dyn_cast<CXXDefaultArgExpr>(Arg)) {
Path.push_back(
{IndirectLocalPathEntry::DefaultArg, DAE, DAE->getParam()});
Arg = DAE->getExpr();
}
if (CheckCoroCall || Callee->getParamDecl(I)->hasAttr<LifetimeBoundAttr>())
VisitLifetimeBoundArg(Callee->getParamDecl(I), Args[I]);
VisitLifetimeBoundArg(Callee->getParamDecl(I), Arg);
else if (EnableGSLAnalysis && I == 0) {
// Perform GSL analysis for the first argument
if (shouldTrackFirstArgument(Callee)) {
VisitGSLPointerArg(Callee, Args[0]);
VisitGSLPointerArg(Callee, Arg);
} else if (auto *Ctor = dyn_cast<CXXConstructExpr>(Call);
Ctor && shouldTrackFirstArgumentForConstructor(Ctor)) {
VisitGSLPointerArg(Ctor->getConstructor(), Args[0]);
VisitGSLPointerArg(Ctor->getConstructor(), Arg);
}
}
}
Expand Down Expand Up @@ -1060,6 +1068,9 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
if (!Path[I].Capture->capturesVariable())
continue;
return Path[I].E->getSourceRange();

case IndirectLocalPathEntry::DefaultArg:
return cast<CXXDefaultArgExpr>(Path[I].E)->getUsedLocation();
}
}
return E->getSourceRange();
Expand Down Expand Up @@ -1370,7 +1381,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
break;
}

case IndirectLocalPathEntry::LambdaCaptureInit:
case IndirectLocalPathEntry::LambdaCaptureInit: {
if (!Elem.Capture->capturesVariable())
break;
// FIXME: We can't easily tell apart an init-capture from a nested
Expand All @@ -1383,6 +1394,16 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
<< nextPathEntryRange(Path, I + 1, L);
break;
}

case IndirectLocalPathEntry::DefaultArg: {
const auto *DAE = cast<CXXDefaultArgExpr>(Elem.E);
const ParmVarDecl *Param = DAE->getParam();
SemaRef.Diag(Param->getDefaultArgRange().getBegin(),
diag::note_init_with_default_argument)
<< Param << nextPathEntryRange(Path, I + 1, L);
break;
}
}
}

// We didn't lifetime-extend, so don't go any further; we don't need more
Expand Down
2 changes: 0 additions & 2 deletions clang/lib/Sema/HLSLExternalSemaSource.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,8 +208,6 @@ struct BuiltinTypeDeclBuilder {
BuiltinTypeDeclBuilder &addArraySubscriptOperator(bool IsConst) {
if (Record->isCompleteDefinition())
return *this;
assert(Fields.count("h") > 0 &&
"Subscript operator must be added after the handle.");

ASTContext &AST = Record->getASTContext();
QualType ElemTy = AST.Char8Ty;
Expand Down
39 changes: 39 additions & 0 deletions clang/lib/Sema/SemaHLSL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1751,6 +1751,22 @@ static bool CheckScalarOrVector(Sema *S, CallExpr *TheCall, QualType Scalar,
return false;
}

static bool CheckAnyScalarOrVector(Sema *S, CallExpr *TheCall,
unsigned ArgIndex) {
assert(TheCall->getNumArgs() >= ArgIndex);
QualType ArgType = TheCall->getArg(ArgIndex)->getType();
auto *VTy = ArgType->getAs<VectorType>();
// not the scalar or vector<scalar>
if (!(ArgType->isScalarType() ||
(VTy && VTy->getElementType()->isScalarType()))) {
S->Diag(TheCall->getArg(0)->getBeginLoc(),
diag::err_typecheck_expect_any_scalar_or_vector)
<< ArgType;
return true;
}
return false;
}

static bool CheckBoolSelect(Sema *S, CallExpr *TheCall) {
assert(TheCall->getNumArgs() == 3);
Expr *Arg1 = TheCall->getArg(1);
Expand Down Expand Up @@ -1993,6 +2009,29 @@ bool SemaHLSL::CheckBuiltinFunctionCall(unsigned BuiltinID, CallExpr *TheCall) {
return true;
break;
}
case Builtin::BI__builtin_hlsl_wave_read_lane_at: {
if (SemaRef.checkArgCount(TheCall, 2))
return true;

// Ensure index parameter type can be interpreted as a uint
ExprResult Index = TheCall->getArg(1);
QualType ArgTyIndex = Index.get()->getType();
if (!ArgTyIndex->isIntegerType()) {
SemaRef.Diag(TheCall->getArg(1)->getBeginLoc(),
diag::err_typecheck_convert_incompatible)
<< ArgTyIndex << SemaRef.Context.UnsignedIntTy << 1 << 0 << 0;
return true;
}

// Ensure input expr type is a scalar/vector and the same as the return type
if (CheckAnyScalarOrVector(&SemaRef, TheCall, 0))
return true;

ExprResult Expr = TheCall->getArg(0);
QualType ArgTyExpr = Expr.get()->getType();
TheCall->setType(ArgTyExpr);
break;
}
case Builtin::BI__builtin_hlsl_wave_get_lane_index: {
if (SemaRef.checkArgCount(TheCall, 0))
return true;
Expand Down
3 changes: 3 additions & 0 deletions clang/lib/Sema/SemaLookup.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3215,6 +3215,9 @@ addAssociatedClassesAndNamespaces(AssociatedLookup &Result, QualType Ty) {
// Array parameter types are treated as fundamental types.
case Type::ArrayParameter:
break;

case Type::HLSLAttributedResource:
T = cast<HLSLAttributedResourceType>(T)->getWrappedType().getTypePtr();
}

if (Queue.empty())
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/Sema/SemaOverload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1798,6 +1798,23 @@ TryImplicitConversion(Sema &S, Expr *From, QualType ToType,
return ICS;
}

if (S.getLangOpts().HLSL && ToType->isHLSLAttributedResourceType() &&
FromType->isHLSLAttributedResourceType()) {
auto *ToResType = cast<HLSLAttributedResourceType>(ToType);
auto *FromResType = cast<HLSLAttributedResourceType>(FromType);
if (S.Context.hasSameUnqualifiedType(ToResType->getWrappedType(),
FromResType->getWrappedType()) &&
S.Context.hasSameUnqualifiedType(ToResType->getContainedType(),
FromResType->getContainedType()) &&
ToResType->getAttrs() == FromResType->getAttrs()) {
ICS.setStandard();
ICS.Standard.setAsIdentityConversion();
ICS.Standard.setFromType(FromType);
ICS.Standard.setAllToTypes(ToType);
return ICS;
}
}

return TryUserDefinedConversion(S, From, ToType, SuppressUserConversions,
AllowExplicit, InOverloadResolution, CStyle,
AllowObjCWritebackConversion,
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/SemaTemplate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6074,6 +6074,13 @@ bool UnnamedLocalNoLinkageFinder::VisitNestedNameSpecifier(
llvm_unreachable("Invalid NestedNameSpecifier::Kind!");
}

bool UnnamedLocalNoLinkageFinder::VisitHLSLAttributedResourceType(
const HLSLAttributedResourceType *T) {
if (T->hasContainedType() && Visit(T->getContainedType()))
return true;
return Visit(T->getWrappedType());
}

bool Sema::CheckTemplateArgument(TypeSourceInfo *ArgInfo) {
assert(ArgInfo && "invalid TypeSourceInfo");
QualType Arg = ArgInfo->getType();
Expand Down
11 changes: 11 additions & 0 deletions clang/lib/Sema/SemaTemplateDeduction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2449,6 +2449,7 @@ static TemplateDeductionResult DeduceTemplateArgumentsByTypeMatch(
case Type::PackExpansion:
case Type::Pipe:
case Type::ArrayParameter:
case Type::HLSLAttributedResource:
// No template argument deduction for these types
return TemplateDeductionResult::Success;

Expand Down Expand Up @@ -6844,6 +6845,16 @@ MarkUsedTemplateParameters(ASTContext &Ctx, QualType T,
OnlyDeduced, Depth, Used);
break;

case Type::HLSLAttributedResource:
MarkUsedTemplateParameters(
Ctx, cast<HLSLAttributedResourceType>(T)->getWrappedType(), OnlyDeduced,
Depth, Used);
if (cast<HLSLAttributedResourceType>(T)->hasContainedType())
MarkUsedTemplateParameters(
Ctx, cast<HLSLAttributedResourceType>(T)->getContainedType(),
OnlyDeduced, Depth, Used);
break;

// None of these types have any template parameters in them.
case Type::Builtin:
case Type::VariableArray:
Expand Down
370 changes: 370 additions & 0 deletions clang/test/AST/ByteCode/constexpr.c

Large diffs are not rendered by default.

2 changes: 0 additions & 2 deletions clang/test/AST/HLSL/RWBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,6 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
Expand All @@ -59,5 +58,4 @@ RWBuffer<float> Buffer;
// CHECK-NEXT: FieldDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
2 changes: 0 additions & 2 deletions clang/test/AST/HLSL/StructuredBuffer-AST.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ StructuredBuffer<float> Buffer;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(element_type)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer

// CHECK: CXXMethodDecl 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> <invalid sloc> operator[] 'element_type &const (unsigned int) const'
Expand Down Expand Up @@ -62,5 +61,4 @@ StructuredBuffer<float> Buffer;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK-NEXT: HLSLResourceAttr 0x{{[0-9A-Fa-f]+}} <<invalid sloc>> Implicit TypedBuffer
2 changes: 1 addition & 1 deletion clang/test/CodeGen/aarch64-type-sizes.c
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// RUN: %clang_cc1 -triple aarch64_be-none-linux-gnu -emit-llvm -w -o - %s | FileCheck %s
// char by definition has size 1

// CHECK: target datalayout = "E-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
// CHECK: target datalayout = "E-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"

int check_short(void) {
return sizeof(short);
Expand Down
2 changes: 1 addition & 1 deletion clang/test/CodeGen/coff-aarch64-type-sizes.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %clang_cc1 -triple aarch64-windows -emit-llvm -w -o - %s | FileCheck %s

// CHECK: target datalayout = "e-m:w-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
// CHECK: target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-p:64:64-i32:32-i64:64-i128:128-n32:64-S128-Fn32"
// CHECK: target triple = "aarch64-unknown-windows-msvc"

int check_short(void) {
Expand Down
19 changes: 19 additions & 0 deletions clang/test/CodeGen/ms-mixed-ptr-sizes.c
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// RUN: %clang_cc1 -triple x86_64-windows-msvc -fms-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefixes=X64,ALL
// RUN: %clang_cc1 -triple i386-pc-win32 -fms-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefixes=X86,ALL
// RUN: %clang_cc1 -triple aarch64-windows-msvc -fms-extensions -emit-llvm -O2 < %s | FileCheck %s --check-prefixes=AARCH64,ALL

struct Foo {
int * __ptr32 p32;
Expand All @@ -9,41 +10,51 @@ void use_foo(struct Foo *f);
void test_sign_ext(struct Foo *f, int * __ptr32 __sptr i) {
// X64-LABEL: define dso_local void @test_sign_ext({{.*}}ptr addrspace(270) noundef %i)
// X86-LABEL: define dso_local void @test_sign_ext(ptr noundef %f, ptr noundef %i)
// AARCH64-LABEL: define dso_local void @test_sign_ext({{.*}}ptr addrspace(270) noundef %i) local_unnamed_addr #0
// X64: %{{.+}} = addrspacecast ptr addrspace(270) %i to ptr
// X86: %{{.+}} = addrspacecast ptr %i to ptr addrspace(272)
// AARCH64: %{{.+}} = addrspacecast ptr addrspace(270) %i to ptr
f->p64 = i;
use_foo(f);
}
void test_zero_ext(struct Foo *f, int * __ptr32 __uptr i) {
// X64-LABEL: define dso_local void @test_zero_ext({{.*}}ptr addrspace(271) noundef %i)
// X86-LABEL: define dso_local void @test_zero_ext({{.*}}ptr addrspace(271) noundef %i)
// AARCH64-LABEL: define dso_local void @test_zero_ext({{.*}}ptr addrspace(271) noundef %i) local_unnamed_addr #0
// X64: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr
// X86: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr addrspace(272)
// AARCH64: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr
f->p64 = i;
use_foo(f);
}
void test_trunc(struct Foo *f, int * __ptr64 i) {
// X64-LABEL: define dso_local void @test_trunc(ptr noundef %f, ptr noundef %i)
// X86-LABEL: define dso_local void @test_trunc({{.*}}ptr addrspace(272) noundef %i)
// AARCH64-LABEL: define dso_local void @test_trunc(ptr noundef %f, ptr noundef %i) local_unnamed_addr #0
// X64: %{{.+}} = addrspacecast ptr %i to ptr addrspace(270)
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %i to ptr
// AARCH64: %{{.+}} = addrspacecast ptr %i to ptr addrspace(270)
f->p32 = i;
use_foo(f);
}
void test_noop(struct Foo *f, int * __ptr32 i) {
// X64-LABEL: define dso_local void @test_noop({{.*}}ptr addrspace(270) noundef %i)
// X86-LABEL: define dso_local void @test_noop({{.*}}ptr noundef %i)
// AARCH64-LABEL: define dso_local void @test_noop({{.*}}ptr addrspace(270) noundef %i) local_unnamed_addr #0
// X64-NOT: addrspacecast
// X86-NOT: addrspacecast
// AARCH64-NOT: addrspacecast
f->p32 = i;
use_foo(f);
}

void test_other(struct Foo *f, __attribute__((address_space(10))) int *i) {
// X64-LABEL: define dso_local void @test_other({{.*}}ptr addrspace(10) noundef %i)
// X86-LABEL: define dso_local void @test_other({{.*}}ptr addrspace(10) noundef %i)
// AARCH64-LABEL: define dso_local void @test_other({{.*}}ptr addrspace(10) noundef %i) local_unnamed_addr #0
// X64: %{{.+}} = addrspacecast ptr addrspace(10) %i to ptr addrspace(270)
// X86: %{{.+}} = addrspacecast ptr addrspace(10) %i to ptr
// AARCH64: %{{.+}} = addrspacecast ptr addrspace(10) %i to ptr addrspace(270)
f->p32 = (int * __ptr32)i;
use_foo(f);
}
Expand All @@ -54,6 +65,8 @@ int test_compare1(int *__ptr32 __uptr i, int *__ptr64 j) {
// X64: %cmp = icmp eq ptr addrspace(271) %i, %{{.+}}
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %j to ptr addrspace(271)
// X86: %cmp = icmp eq ptr addrspace(271) %i, %{{.+}}
// AARCH64: %{{.+}} = addrspacecast ptr %j to ptr addrspace(271)
// AARCH64: %cmp = icmp eq ptr addrspace(271) %i, %{{.+}}
return (i == j);
}

Expand All @@ -63,6 +76,8 @@ int test_compare2(int *__ptr32 __sptr i, int *__ptr64 j) {
// X64: %cmp = icmp eq ptr addrspace(270) %i, %{{.+}}
// X86: %{{.+}} = addrspacecast ptr addrspace(272) %j to ptr
// X86: %cmp = icmp eq ptr %i, %{{.+}}
// AARCH64: %{{.+}} = addrspacecast ptr %j to ptr addrspace(270)
// AARCH64: %cmp = icmp eq ptr addrspace(270) %i, %{{.+}}
return (i == j);
}

Expand All @@ -72,6 +87,8 @@ int test_compare3(int *__ptr32 __uptr i, int *__ptr64 j) {
// X64: %cmp = icmp eq ptr %j, %{{.+}}
// X86: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr addrspace(272)
// X86: %cmp = icmp eq ptr addrspace(272) %j, %{{.+}}
// AARCH64: %{{.+}} = addrspacecast ptr addrspace(271) %i to ptr
// AARCH64: %cmp = icmp eq ptr %j, %{{.+}}
return (j == i);
}

Expand All @@ -81,5 +98,7 @@ int test_compare4(int *__ptr32 __sptr i, int *__ptr64 j) {
// X64: %cmp = icmp eq ptr %j, %{{.+}}
// X86: %{{.+}} = addrspacecast ptr %i to ptr addrspace(272)
// X86: %cmp = icmp eq ptr addrspace(272) %j, %{{.+}}
// AARCH64: %{{.+}} = addrspacecast ptr addrspace(270) %i to ptr
// AARCH64: %cmp = icmp eq ptr %j, %{{.+}}
return (j == i);
}
6 changes: 3 additions & 3 deletions clang/test/CodeGen/target-data.c
Original file line number Diff line number Diff line change
Expand Up @@ -185,15 +185,15 @@

// RUN: %clang_cc1 -triple arm64-unknown -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=AARCH64
// AARCH64: target datalayout = "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"
// AARCH64: target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"

// RUN: %clang_cc1 -triple arm64_32-apple-ios7.0 -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=AARCH64-ILP32
// AARCH64-ILP32: target datalayout = "e-m:o-p:32:32-i64:64-i128:128-n32:64-S128-Fn32"
// AARCH64-ILP32: target datalayout = "e-m:o-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"

// RUN: %clang_cc1 -triple arm64-pc-win32-macho -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=AARCH64-WIN32-MACHO
// AARCH64-WIN32-MACHO: target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128-Fn32"
// AARCH64-WIN32-MACHO: target datalayout = "e-m:o-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-n32:64-S128-Fn32"

// RUN: %clang_cc1 -triple thumb-unknown-gnueabi -o - -emit-llvm %s | \
// RUN: FileCheck %s -check-prefix=THUMB
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGenHLSL/builtins/RWBuffer-elementtype.hlsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s

// NOTE: The type name number and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.

// CHECK: %"class.hlsl::RWBuffer" = type <{ target("dx.TypedBuffer", i16, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.0" = type <{ target("dx.TypedBuffer", i16, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.2" = type { target("dx.TypedBuffer", i32, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.3" = type { target("dx.TypedBuffer", i32, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.4" = type { target("dx.TypedBuffer", i64, 1, 0, 1)
// CHECK: %"class.hlsl::RWBuffer.5" = type { target("dx.TypedBuffer", i64, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.6" = type <{ target("dx.TypedBuffer", half, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.8" = type { target("dx.TypedBuffer", float, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.9" = type { target("dx.TypedBuffer", double, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.10" = type { target("dx.TypedBuffer", <4 x i16>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.11" = type { target("dx.TypedBuffer", <3 x i32>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.12" = type { target("dx.TypedBuffer", <2 x half>, 1, 0, 0)
// CHECK: %"class.hlsl::RWBuffer.13" = type { target("dx.TypedBuffer", <3 x float>, 1, 0, 0)

RWBuffer<int16_t> BufI16;
RWBuffer<uint16_t> BufU16;
RWBuffer<int> BufI32;
Expand Down
18 changes: 18 additions & 0 deletions clang/test/CodeGenHLSL/builtins/StructuredBuffer-elementtype.hlsl
Original file line number Diff line number Diff line change
@@ -1,5 +1,23 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.2-compute -finclude-default-header -fnative-half-type -emit-llvm -o - %s | FileCheck %s

// NOTE: The number in type name and whether the struct is packed or not will mostly
// likely change once subscript operators are properly implemented (llvm/llvm-project#95956)
// and theinterim field of the contained type is removed.

// CHECK: %"class.hlsl::StructuredBuffer" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.0" = type <{ target("dx.RawBuffer", i16, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.2" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.3" = type { target("dx.RawBuffer", i32, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.4" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.5" = type { target("dx.RawBuffer", i64, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.6" = type <{ target("dx.RawBuffer", half, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.8" = type { target("dx.RawBuffer", float, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.9" = type { target("dx.RawBuffer", double, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.10" = type { target("dx.RawBuffer", <4 x i16>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.11" = type { target("dx.RawBuffer", <3 x i32>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.12" = type { target("dx.RawBuffer", <2 x half>, 1, 0)
// CHECK: %"class.hlsl::StructuredBuffer.13" = type { target("dx.RawBuffer", <3 x float>, 1, 0)

StructuredBuffer<int16_t> BufI16;
StructuredBuffer<uint16_t> BufU16;
StructuredBuffer<int> BufI32;
Expand Down
74 changes: 74 additions & 0 deletions clang/test/CodeGenHLSL/builtins/WaveReadLaneAt.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -fnative-half-type -triple \
// RUN: dxil-pc-shadermodel6.3-compute %s -emit-llvm -disable-llvm-passes -o - | \
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-DXIL
// RUN: %clang_cc1 -std=hlsl2021 -finclude-default-header -fnative-half-type -triple \
// RUN: spirv-pc-vulkan-compute %s -emit-llvm -disable-llvm-passes -o - | \
// RUN: FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV

// Test basic lowering to runtime function call for int values.

// CHECK-LABEL: test_int
int test_int(int expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok0:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok0]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i32([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i32([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i32([[TY]], i32) #[[#attr:]]

#ifdef __HLSL_ENABLE_16_BIT
// CHECK-LABEL: test_int16
int16_t test_int16(int16_t expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok1:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok1]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.i16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.i16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.i16([[TY]], i32) #[[#attr:]]
#endif

// Test basic lowering to runtime function call with array and float values.

// CHECK-LABEL: test_half
half test_half(half expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok2:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok2]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f16([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f16([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f16([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_double
double test_double(double expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok3:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET:.*]] = call [[TY:.*]] @llvm.spv.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok3]]) ]
// CHECK-DXIL: %[[RET:.*]] = call [[TY:.*]] @llvm.dx.wave.readlane.f64([[TY]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY]] %[[RET]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY]] @llvm.dx.wave.readlane.f64([[TY]], i32) #[[#attr:]]
// CHECK-SPIRV: declare [[TY]] @llvm.spv.wave.readlane.f64([[TY]], i32) #[[#attr:]]

// CHECK-LABEL: test_floatv4
float4 test_floatv4(float4 expr, uint idx) {
// CHECK-SPIRV: %[[#entry_tok4:]] = call token @llvm.experimental.convergence.entry()
// CHECK-SPIRV: %[[RET1:.*]] = call [[TY1:.*]] @llvm.spv.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]]) [ "convergencectrl"(token %[[#entry_tok4]]) ]
// CHECK-DXIL: %[[RET1:.*]] = call [[TY1:.*]] @llvm.dx.wave.readlane.v4f32([[TY1]] %[[#]], i32 %[[#]])
// CHECK: ret [[TY1]] %[[RET1]]
return WaveReadLaneAt(expr, idx);
}

// CHECK-DXIL: declare [[TY1]] @llvm.dx.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]
// CHECK-SPIRV: declare [[TY1]] @llvm.spv.wave.readlane.v4f32([[TY1]], i32) #[[#attr]]

// CHECK: attributes #[[#attr]] = {{{.*}} convergent {{.*}}}
56 changes: 50 additions & 6 deletions clang/test/CodeGenHLSL/builtins/hlsl_resource_t.hlsl
Original file line number Diff line number Diff line change
@@ -1,9 +1,53 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -O1 -o - %s | FileCheck %s
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -finclude-default-header -x hlsl -emit-llvm -o - %s | FileCheck %s

void foo(__hlsl_resource_t res);
using handle_float_t = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float)]];

// CHECK: define void @_Z3baru17__hlsl_resource_t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[PARAM:[a-zA-Z0-9]+]])
// CHECK: call void @_Z3foou17__hlsl_resource_t(target("dx.TypedBuffer", <4 x float>, 1, 0, 0) %[[PARAM]])
void bar(__hlsl_resource_t a) {
foo(a);
// CHECK: %"class.hlsl::RWBuffer" = type { target("dx.TypedBuffer", <4 x float>, 1, 0, 0)
// CHECK: %"class.hlsl::StructuredBuffer" = type { target("dx.RawBuffer", %struct.MyStruct = type { <4 x float>, <2 x i32>, [8 x i8] }, 1, 0)

// CHECK: define void @_Z2faU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a)
// CHECK: call void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %0)
// CHECK: declare void @_Z4foo1U9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0))

void foo1(handle_float_t res);

void fa(handle_float_t a) {
foo1(a);
}

// CHECK: define void @_Z2fbU9_Res_u_CTfu17__hlsl_resource_t(target("dx.TypedBuffer", float, 1, 0, 0) %a)
void fb(handle_float_t a) {
handle_float_t b = a;
}

// CHECK: define void @_Z2fcN4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16 %a)
// CHECK: call void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16 %agg.tmp)
// CHECK: declare void @_Z4foo2N4hlsl8RWBufferIDv4_fEE(ptr noundef byval(%"class.hlsl::RWBuffer") align 16)
void foo2(RWBuffer<float4> buf);

void fc(RWBuffer<float4> a) {
foo2(a);
}

void fd(RWBuffer<float4> a) {
RWBuffer<float4> b = a;
}

struct MyStruct {
float4 f;
int2 i;
};

// CHECK: define void @_Z2feN4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16 %a)
// CHECK: call void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16 %agg.tmp)
// CHECK: declare void @_Z4foo3N4hlsl16StructuredBufferI8MyStructEE(ptr noundef byval(%"class.hlsl::StructuredBuffer") align 16)
void foo3(StructuredBuffer<MyStruct> buf);

void fe(StructuredBuffer<MyStruct> a) {
foo3(a);
}

void ff(StructuredBuffer<MyStruct> a) {
StructuredBuffer<MyStruct> b = a;
}

13 changes: 13 additions & 0 deletions clang/test/Driver/loongarch-mannotate-tablejump.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
/// Test -m[no-]annotate-tablejump options.

// RUN: %clang --target=loongarch64 -mannotate-tablejump %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-ANOTATE
// RUN: %clang --target=loongarch64 -mno-annotate-tablejump %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-ANOTATE
// RUN: %clang --target=loongarch64 -mannotate-tablejump -mno-annotate-tablejump %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-NO-ANOTATE
// RUN: %clang --target=loongarch64 -mno-annotate-tablejump -mannotate-tablejump %s -### 2>&1 | \
// RUN: FileCheck %s --check-prefix=CC1-ANOTATE

// CC1-ANOTATE: "-loongarch-annotate-tablejump"
// CC1-NO-ANOTATE-NOT: "-loongarch-annotate-tablejump"
13 changes: 5 additions & 8 deletions clang/test/ParserHLSL/hlsl_contained_type_attr.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,24 @@

typedef vector<float, 4> float4;

// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, col:83>
// CHECK: -TypeAliasDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:83>
// CHECK: -HLSLAttributedResourceType 0x{{[0-9a-f]+}} '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(int)]]
// CHECK-SAME: ' sugar
using ResourceIntAliasT = __hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(int)]];
ResourceIntAliasT h1;

// CHECK: -VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:82> col:82 h2 '__hlsl_resource_t
// CHECK: -VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:82> col:82 h2 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float4)]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(float4)]] h2;

// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 7]]:1, line:[[# @LINE + 9]]:1> line:[[# @LINE + 7]]:30 S
// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 6]]:1, line:[[# @LINE + 8]]:1> line:[[# @LINE + 6]]:30 S
// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:11, col:20> col:20 referenced typename depth 0 index 0 T
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:23, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:30 struct S definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:79> col:79 h '__hlsl_resource_t
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:23, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:30 struct S definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:79> col:79 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(T)]]
// CHECK-SAME: ':'__hlsl_resource_t'
template <typename T> struct S {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::contained_type(T)]] h;
};
9 changes: 3 additions & 6 deletions clang/test/ParserHLSL/hlsl_is_rov_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:68> col:68 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:68> col:68 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::is_rov]] h;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:66> col:66 res '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:66> col:66 res '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::is_rov]] [[hlsl::resource_class(SRV)]] res;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 r '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(Sampler)]] [[hlsl::is_rov]] r;
}
9 changes: 3 additions & 6 deletions clang/test/ParserHLSL/hlsl_raw_buffer_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,25 +1,22 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:3, col:72> col:72 h1 '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:72> col:72 h1 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h1;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, col:70> col:70 h2 '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:70> col:70 h2 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::raw_buffer]] [[hlsl::resource_class(SRV)]] h2;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 5]]:1, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:72> col:72 h3 '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::raw_buffer]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] [[hlsl::raw_buffer]] h3;
}
17 changes: 6 additions & 11 deletions clang/test/ParserHLSL/hlsl_resource_class_attr.hlsl
Original file line number Diff line number Diff line change
@@ -1,33 +1,29 @@
// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -ast-dump -o - %s | FileCheck %s

// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} {{.*}} struct MyBuffer definition
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
struct MyBuffer {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
};

// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, col:49> col:49 res '__hlsl_resource_t
// CHECK: VarDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 2]]:1, col:49> col:49 res '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(SRV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
__hlsl_resource_t [[hlsl::resource_class(SRV)]] res;

// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:1, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:6 f 'void ()
// CHECK: FunctionDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:1, line:[[# @LINE + 5]]:1> line:[[# @LINE + 3]]:6 f 'void ()
// CHECK: VarDecl 0x{{[0-9a-f]+}} <col:3, col:55> col:55 r '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(Sampler)]]
// CHECK-SAME: ':'__hlsl_resource_t'
void f() {
__hlsl_resource_t [[hlsl::resource_class(Sampler)]] r;
}

// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 7]]:1, line:[[# @LINE + 9]]:1> line:[[# @LINE + 7]]:29 MyBuffer2
// CHECK: ClassTemplateDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 6]]:1, line:[[# @LINE + 8]]:1> line:[[# @LINE + 6]]:29 MyBuffer2
// CHECK: TemplateTypeParmDecl 0x{{[0-9a-f]+}} <col:10, col:19> col:19 typename depth 0 index 0 T
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:[[# @LINE + 7]]:1> line:[[# @LINE + 5]]:29 struct MyBuffer2 definition
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, line:[[# @LINE + 6]]:1> line:[[# @LINE + 4]]:29 struct MyBuffer2 definition
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 4]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE + 3]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
template<typename T> struct MyBuffer2 {
__hlsl_resource_t [[hlsl::resource_class(UAV)]] h;
};
Expand All @@ -38,5 +34,4 @@ template<typename T> struct MyBuffer2 {
// CHECK: CXXRecordDecl 0x{{[0-9a-f]+}} <col:22, col:29> col:29 implicit struct MyBuffer2
// CHECK: FieldDecl 0x{{[0-9a-f]+}} <line:[[# @LINE - 7]]:3, col:51> col:51 h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME: ':'__hlsl_resource_t'
MyBuffer2<float> myBuffer2;
2 changes: 0 additions & 2 deletions clang/test/ParserHLSL/hlsl_resource_handle_attrs.hlsl
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
// CHECK: -FieldDecl 0x{{[0-9a-f]+}} <<invalid sloc>> <invalid sloc> implicit h '__hlsl_resource_t
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(float)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RWBuffer<float> Buffer1;

Expand All @@ -18,6 +17,5 @@ RWBuffer<float> Buffer1;
// CHECK-SAME{LITERAL}: [[hlsl::resource_class(UAV)]
// CHECK-SAME{LITERAL}: [[hlsl::is_rov]]
// CHECK-SAME{LITERAL}: [[hlsl::contained_type(vector<float, 4>)]]
// CHECK-SAME: ':'__hlsl_resource_t'
// CHECK: -HLSLResourceAttr 0x{{[0-9a-f]+}} <<invalid sloc>> Implicit TypedBuffer
RasterizerOrderedBuffer<vector<float, 4> > BufferArray3[4];
31 changes: 31 additions & 0 deletions clang/test/SemaCXX/attr-lifetimebound.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,37 @@ namespace std {
using std::operator""s;
using std::operator""sv;

namespace default_args {
using IntArray = int[];
const int *defaultparam1(const int &def1 [[clang::lifetimebound]] = 0); // #def1
const int &defaultparam_array([[clang::lifetimebound]] const int *p = IntArray{1, 2, 3}); // #def2
struct A {
A(const char *, const int &def3 [[clang::lifetimebound]] = 0); // #def3
};
const int &defaultparam2(const int &def4 [[clang::lifetimebound]] = 0); // #def4
const int &defaultparam3(const int &def5 [[clang::lifetimebound]] = defaultparam2(), const int &def6 [[clang::lifetimebound]] = 0); // #def5 #def6
std::string_view defaultparam4(std::string_view s [[clang::lifetimebound]] = std::string()); // #def7

const int *test_default_args() {
const int *c = defaultparam1(); // expected-warning {{temporary whose address is used as value of local variable 'c' will be destroyed at the end of the full-expression}} expected-note@#def1 {{initializing parameter 'def1' with default argument}}
A a = A(""); // expected-warning {{temporary whose address is used as value of local variable 'a' will be destroyed at the end of the full-expression}} expected-note@#def3 {{initializing parameter 'def3' with default argument}}
const int &s = defaultparam2(); // expected-warning {{temporary bound to local reference 's' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
const int &t = defaultparam3(); // expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def4 {{initializing parameter 'def4' with default argument}} expected-note@#def5 {{initializing parameter 'def5' with default argument}} expected-warning {{temporary bound to local reference 't' will be destroyed at the end of the full-expression}} expected-note@#def6 {{initializing parameter 'def6' with default argument}}
const int &u = defaultparam_array(); // expected-warning {{temporary bound to local reference 'u' will be destroyed at the end of the full-expression}} expected-note@#def2 {{initializing parameter 'p' with default argument}}
int local;
const int &v = defaultparam2(local); // no warning
const int &w = defaultparam2(1); // expected-warning {{temporary bound to local reference 'w' will be destroyed at the end of the full-expression}}
if (false) {
return &defaultparam2(); // expected-warning {{returning address of local temporary object}}
}
if (false) {
return &defaultparam2(0); // expected-warning {{returning address of local temporary object}} expected-note@#def4 {{initializing parameter 'def4' with default argument}}
}
std::string_view sv = defaultparam4(); // expected-warning {{temporary whose address is used as value of local variable 'sv' will be destroyed at the end of the full-expression}} expected-note@#def7 {{initializing parameter 's' with default argument}}
return nullptr;
}
} // namespace default_args

namespace p0936r0_examples {
std::string_view s = "foo"s; // expected-warning {{temporary}}

Expand Down
38 changes: 38 additions & 0 deletions clang/test/SemaHLSL/BuiltIns/WaveReadLaneAt-errors.hlsl
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// RUN: %clang_cc1 -finclude-default-header -triple dxil-pc-shadermodel6.6-library %s -emit-llvm-only -disable-llvm-passes -verify

bool test_too_few_arg() {
return __builtin_hlsl_wave_read_lane_at();
// expected-error@-1 {{too few arguments to function call, expected 2, have 0}}
}

float2 test_too_few_arg_1(float2 p0) {
return __builtin_hlsl_wave_read_lane_at(p0);
// expected-error@-1 {{too few arguments to function call, expected 2, have 1}}
}

float2 test_too_many_arg(float2 p0) {
return __builtin_hlsl_wave_read_lane_at(p0, p0, p0);
// expected-error@-1 {{too many arguments to function call, expected 2, have 3}}
}

float3 test_index_double_type_check(float3 p0, double idx) {
return __builtin_hlsl_wave_read_lane_at(p0, idx);
// expected-error@-1 {{passing 'double' to parameter of incompatible type 'unsigned int'}}
}

float3 test_index_int3_type_check(float3 p0, int3 idxs) {
return __builtin_hlsl_wave_read_lane_at(p0, idxs);
// expected-error@-1 {{passing 'int3' (aka 'vector<int, 3>') to parameter of incompatible type 'unsigned int'}}
}

struct S { float f; };

float3 test_index_S_type_check(float3 p0, S idx) {
return __builtin_hlsl_wave_read_lane_at(p0, idx);
// expected-error@-1 {{passing 'S' to parameter of incompatible type 'unsigned int'}}
}

S test_expr_struct_type_check(S p0, int idx) {
return __builtin_hlsl_wave_read_lane_at(p0, idx);
// expected-error@-1 {{invalid operand of type 'S' where a scalar or vector is required}}
}
16 changes: 8 additions & 8 deletions clang/utils/TableGen/ClangDiagnosticsEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ getCategoryFromDiagGroup(const Record *Group,
static std::string getDiagnosticCategory(const Record *R,
DiagGroupParentMap &DiagGroupParents) {
// If the diagnostic is in a group, and that group has a category, use it.
if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
if (const auto *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
// Check the diagnostic's diag group for a category.
std::string CatName = getCategoryFromDiagGroup(Group->getDef(),
DiagGroupParents);
Expand Down Expand Up @@ -161,7 +161,7 @@ static void groupDiagnostics(ArrayRef<const Record *> Diags,

for (unsigned i = 0, e = Diags.size(); i != e; ++i) {
const Record *R = Diags[i];
DefInit *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
const auto *DI = dyn_cast<DefInit>(R->getValueInit("Group"));
if (!DI)
continue;
assert(R->getValueAsDef("Class")->getName() != "CLASS_NOTE" &&
Expand Down Expand Up @@ -359,7 +359,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
const Record *R = Diags[i];
if (isExtension(R) && isOffByDefault(R)) {
DiagsSet.insert(R);
if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
if (const auto *Group = dyn_cast<DefInit>(R->getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
if (!isSubGroupOfGroup(GroupRec, "pedantic")) {
markGroup(GroupRec);
Expand All @@ -378,13 +378,13 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
// Check if the group is implicitly in -Wpedantic. If so,
// the diagnostic should not be directly included in the -Wpedantic
// diagnostic group.
if (DefInit *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
if (const auto *Group = dyn_cast<DefInit>(R->getValueInit("Group")))
if (groupInPedantic(Group->getDef()))
continue;

// The diagnostic is not included in a group that is (transitively) in
// -Wpedantic. Include it in -Wpedantic directly.
if (RecordVec *V = DiagsInPedantic.dyn_cast<RecordVec*>())
if (auto *V = DiagsInPedantic.dyn_cast<RecordVec *>())
V->push_back(R);
else {
DiagsInPedantic.get<RecordSet*>()->insert(R);
Expand Down Expand Up @@ -413,7 +413,7 @@ void InferPedantic::compute(VecOrSet DiagsInPedantic,
if (Parents.size() > 0 && AllParentsInPedantic)
continue;

if (RecordVec *V = GroupsInPedantic.dyn_cast<RecordVec*>())
if (auto *V = GroupsInPedantic.dyn_cast<RecordVec *>())
V->push_back(Group);
else {
GroupsInPedantic.get<RecordSet*>()->insert(Group);
Expand Down Expand Up @@ -1443,7 +1443,7 @@ void clang::EmitClangDiagsDefs(const RecordKeeper &Records, raw_ostream &OS,
// Check if this is an error that is accidentally in a warning
// group.
if (isError(R)) {
if (DefInit *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
if (const auto *Group = dyn_cast<DefInit>(R.getValueInit("Group"))) {
const Record *GroupRec = Group->getDef();
const std::string &GroupName =
std::string(GroupRec->getValueAsString("GroupName"));
Expand Down Expand Up @@ -1478,7 +1478,7 @@ void clang::EmitClangDiagsDefs(const RecordKeeper &Records, raw_ostream &OS,

// Warning group associated with the diagnostic. This is stored as an index
// into the alphabetically sorted warning group table.
if (DefInit *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
if (const auto *DI = dyn_cast<DefInit>(R.getValueInit("Group"))) {
std::map<std::string, GroupInfo>::iterator I = DiagsInGroup.find(
std::string(DI->getDef()->getValueAsString("GroupName")));
assert(I != DiagsInGroup.end());
Expand Down
10 changes: 5 additions & 5 deletions clang/utils/TableGen/ClangSACheckersEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ static std::string getPackageFullName(const Record *R, StringRef Sep = ".");
static std::string getParentPackageFullName(const Record *R,
StringRef Sep = ".") {
std::string name;
if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
if (const DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
name = getPackageFullName(DI->getDef(), Sep);
return name;
}
Expand All @@ -53,7 +53,7 @@ static std::string getCheckerFullName(const Record *R, StringRef Sep = ".") {
}

static std::string getStringValue(const Record &R, StringRef field) {
if (StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
if (const StringInit *SI = dyn_cast<StringInit>(R.getValueInit(field)))
return std::string(SI->getValue());
return std::string();
}
Expand Down Expand Up @@ -94,7 +94,7 @@ static std::string getCheckerDocs(const Record &R) {
/// the class itself has to be modified for adding a new option type in
/// CheckerBase.td.
static std::string getCheckerOptionType(const Record &R) {
if (BitsInit *BI = R.getValueAsBitsInit("Type")) {
if (const BitsInit *BI = R.getValueAsBitsInit("Type")) {
switch(getValueFromBitsInit(BI, R)) {
case 0:
return "int";
Expand All @@ -111,7 +111,7 @@ static std::string getCheckerOptionType(const Record &R) {
}

static std::string getDevelopmentStage(const Record &R) {
if (BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
if (const BitsInit *BI = R.getValueAsBitsInit("DevelopmentStage")) {
switch(getValueFromBitsInit(BI, R)) {
case 0:
return "alpha";
Expand All @@ -131,7 +131,7 @@ static bool isHidden(const Record *R) {
return true;

// Not declared as hidden, check the parent package if it is hidden.
if (DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
if (const DefInit *DI = dyn_cast<DefInit>(R->getValueInit("ParentPackage")))
return isHidden(DI->getDef());

return false;
Expand Down
82 changes: 45 additions & 37 deletions clang/utils/TableGen/NeonEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,7 @@ class Intrinsic {
ClassKind CK;
/// The list of DAGs for the body. May be empty, in which case we should
/// emit a builtin call.
ListInit *Body;
const ListInit *Body;
/// The architectural ifdef guard.
std::string ArchGuard;
/// The architectural target() guard.
Expand Down Expand Up @@ -372,9 +372,9 @@ class Intrinsic {

public:
Intrinsic(const Record *R, StringRef Name, StringRef Proto, TypeSpec OutTS,
TypeSpec InTS, ClassKind CK, ListInit *Body, NeonEmitter &Emitter,
StringRef ArchGuard, StringRef TargetGuard, bool IsUnavailable,
bool BigEndianSafe)
TypeSpec InTS, ClassKind CK, const ListInit *Body,
NeonEmitter &Emitter, StringRef ArchGuard, StringRef TargetGuard,
bool IsUnavailable, bool BigEndianSafe)
: R(R), Name(Name.str()), OutTS(OutTS), InTS(InTS), CK(CK), Body(Body),
ArchGuard(ArchGuard.str()), TargetGuard(TargetGuard.str()),
IsUnavailable(IsUnavailable), BigEndianSafe(BigEndianSafe),
Expand Down Expand Up @@ -554,19 +554,20 @@ class Intrinsic {
DagEmitter(Intrinsic &Intr, StringRef CallPrefix) :
Intr(Intr), CallPrefix(CallPrefix) {
}
std::pair<Type, std::string> emitDagArg(Init *Arg, std::string ArgName);
std::pair<Type, std::string> emitDagSaveTemp(DagInit *DI);
std::pair<Type, std::string> emitDagSplat(DagInit *DI);
std::pair<Type, std::string> emitDagDup(DagInit *DI);
std::pair<Type, std::string> emitDagDupTyped(DagInit *DI);
std::pair<Type, std::string> emitDagShuffle(DagInit *DI);
std::pair<Type, std::string> emitDagCast(DagInit *DI, bool IsBitCast);
std::pair<Type, std::string> emitDagCall(DagInit *DI,
std::pair<Type, std::string> emitDagArg(const Init *Arg,
std::string ArgName);
std::pair<Type, std::string> emitDagSaveTemp(const DagInit *DI);
std::pair<Type, std::string> emitDagSplat(const DagInit *DI);
std::pair<Type, std::string> emitDagDup(const DagInit *DI);
std::pair<Type, std::string> emitDagDupTyped(const DagInit *DI);
std::pair<Type, std::string> emitDagShuffle(const DagInit *DI);
std::pair<Type, std::string> emitDagCast(const DagInit *DI, bool IsBitCast);
std::pair<Type, std::string> emitDagCall(const DagInit *DI,
bool MatchMangledName);
std::pair<Type, std::string> emitDagNameReplace(DagInit *DI);
std::pair<Type, std::string> emitDagLiteral(DagInit *DI);
std::pair<Type, std::string> emitDagOp(DagInit *DI);
std::pair<Type, std::string> emitDag(DagInit *DI);
std::pair<Type, std::string> emitDagNameReplace(const DagInit *DI);
std::pair<Type, std::string> emitDagLiteral(const DagInit *DI);
std::pair<Type, std::string> emitDagOp(const DagInit *DI);
std::pair<Type, std::string> emitDag(const DagInit *DI);
};
};

Expand Down Expand Up @@ -1410,9 +1411,9 @@ void Intrinsic::emitBody(StringRef CallPrefix) {

// We have a list of "things to output". The last should be returned.
for (auto *I : Body->getValues()) {
if (StringInit *SI = dyn_cast<StringInit>(I)) {
if (const auto *SI = dyn_cast<StringInit>(I)) {
Lines.push_back(replaceParamsIn(SI->getAsString()));
} else if (DagInit *DI = dyn_cast<DagInit>(I)) {
} else if (const auto *DI = dyn_cast<DagInit>(I)) {
DagEmitter DE(*this, CallPrefix);
Lines.push_back(DE.emitDag(DI).second + ";");
}
Expand All @@ -1438,9 +1439,9 @@ void Intrinsic::emitReturn() {
emitNewLine();
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(DagInit *DI) {
std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(const DagInit *DI) {
// At this point we should only be seeing a def.
DefInit *DefI = cast<DefInit>(DI->getOperator());
const DefInit *DefI = cast<DefInit>(DI->getOperator());
std::string Op = DefI->getAsString();

if (Op == "cast" || Op == "bitcast")
Expand All @@ -1467,7 +1468,8 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDag(DagInit *DI) {
return std::make_pair(Type::getVoid(), "");
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagOp(DagInit *DI) {
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagOp(const DagInit *DI) {
std::string Op = cast<StringInit>(DI->getArg(0))->getAsUnquotedString();
if (DI->getNumArgs() == 2) {
// Unary op.
Expand All @@ -1486,7 +1488,7 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagOp(DagInit *DI) {
}

std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {
Intrinsic::DagEmitter::emitDagCall(const DagInit *DI, bool MatchMangledName) {
std::vector<Type> Types;
std::vector<std::string> Values;
for (unsigned I = 0; I < DI->getNumArgs() - 1; ++I) {
Expand All @@ -1498,7 +1500,7 @@ Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {

// Look up the called intrinsic.
std::string N;
if (StringInit *SI = dyn_cast<StringInit>(DI->getArg(0)))
if (const auto *SI = dyn_cast<StringInit>(DI->getArg(0)))
N = SI->getAsUnquotedString();
else
N = emitDagArg(DI->getArg(0), "").second;
Expand Down Expand Up @@ -1529,8 +1531,8 @@ Intrinsic::DagEmitter::emitDagCall(DagInit *DI, bool MatchMangledName) {
return std::make_pair(Callee.getReturnType(), S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI,
bool IsBitCast){
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagCast(const DagInit *DI, bool IsBitCast) {
// (cast MOD* VAL) -> cast VAL to type given by MOD.
std::pair<Type, std::string> R =
emitDagArg(DI->getArg(DI->getNumArgs() - 1),
Expand All @@ -1552,7 +1554,7 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI,
castToType =
Intr.Variables[std::string(DI->getArgNameStr(ArgIdx))].getType();
} else {
StringInit *SI = dyn_cast<StringInit>(DI->getArg(ArgIdx));
const auto *SI = dyn_cast<StringInit>(DI->getArg(ArgIdx));
assert_with_loc(SI, "Expected string type or $Name for cast type");

if (SI->getAsUnquotedString() == "R") {
Expand Down Expand Up @@ -1599,7 +1601,8 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagCast(DagInit *DI,
return std::make_pair(castToType, S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagShuffle(const DagInit *DI) {
// See the documentation in arm_neon.td for a description of these operators.
class LowHalf : public SetTheory::Operator {
public:
Expand Down Expand Up @@ -1710,7 +1713,8 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagShuffle(DagInit *DI){
return std::make_pair(T, S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDup(DagInit *DI) {
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagDup(const DagInit *DI) {
assert_with_loc(DI->getNumArgs() == 1, "dup() expects one argument");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
Expand All @@ -1729,15 +1733,16 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDup(DagInit *DI) {
return std::make_pair(T, S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDupTyped(DagInit *DI) {
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagDupTyped(const DagInit *DI) {
assert_with_loc(DI->getNumArgs() == 2, "dup_typed() expects two arguments");
std::pair<Type, std::string> B =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
assert_with_loc(B.first.isScalar(),
"dup_typed() requires a scalar as the second argument");
Type T;
// If the type argument is a constant string, construct the type directly.
if (StringInit *SI = dyn_cast<StringInit>(DI->getArg(0))) {
if (const auto *SI = dyn_cast<StringInit>(DI->getArg(0))) {
T = Type::fromTypedefName(SI->getAsUnquotedString());
assert_with_loc(!T.isVoid(), "Unknown typedef");
} else
Expand All @@ -1755,7 +1760,8 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagDupTyped(DagInit *DI)
return std::make_pair(T, S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSplat(DagInit *DI) {
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagSplat(const DagInit *DI) {
assert_with_loc(DI->getNumArgs() == 2, "splat() expects two arguments");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(0), std::string(DI->getArgNameStr(0)));
Expand All @@ -1774,7 +1780,8 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSplat(DagInit *DI) {
return std::make_pair(Intr.getBaseType(), S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSaveTemp(DagInit *DI) {
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagSaveTemp(const DagInit *DI) {
assert_with_loc(DI->getNumArgs() == 2, "save_temp() expects two arguments");
std::pair<Type, std::string> A =
emitDagArg(DI->getArg(1), std::string(DI->getArgNameStr(1)));
Expand All @@ -1797,7 +1804,7 @@ std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagSaveTemp(DagInit *DI)
}

std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagNameReplace(DagInit *DI) {
Intrinsic::DagEmitter::emitDagNameReplace(const DagInit *DI) {
std::string S = Intr.Name;

assert_with_loc(DI->getNumArgs() == 2, "name_replace requires 2 arguments!");
Expand All @@ -1812,14 +1819,15 @@ Intrinsic::DagEmitter::emitDagNameReplace(DagInit *DI) {
return std::make_pair(Type::getVoid(), S);
}

std::pair<Type, std::string> Intrinsic::DagEmitter::emitDagLiteral(DagInit *DI){
std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagLiteral(const DagInit *DI) {
std::string Ty = cast<StringInit>(DI->getArg(0))->getAsUnquotedString();
std::string Value = cast<StringInit>(DI->getArg(1))->getAsUnquotedString();
return std::make_pair(Type::fromTypedefName(Ty), Value);
}

std::pair<Type, std::string>
Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) {
Intrinsic::DagEmitter::emitDagArg(const Init *Arg, std::string ArgName) {
if (!ArgName.empty()) {
assert_with_loc(!Arg->isComplete(),
"Arguments must either be DAGs or names, not both!");
Expand All @@ -1830,7 +1838,7 @@ Intrinsic::DagEmitter::emitDagArg(Init *Arg, std::string ArgName) {
}

assert(Arg && "Neither ArgName nor Arg?!");
DagInit *DI = dyn_cast<DagInit>(Arg);
const auto *DI = dyn_cast<DagInit>(Arg);
assert_with_loc(DI, "Arguments must either be DAGs or names!");

return emitDag(DI);
Expand Down Expand Up @@ -1994,7 +2002,7 @@ void NeonEmitter::createIntrinsic(const Record *R,
// decent location information even when highly nested.
CurrentRecord = R;

ListInit *Body = OperationRec->getValueAsListInit("Ops");
const ListInit *Body = OperationRec->getValueAsListInit("Ops");

std::vector<TypeSpec> TypeSpecs = TypeSpec::fromTypeSpecs(Types);

Expand Down
5 changes: 0 additions & 5 deletions cmake/Modules/CMakePolicy.cmake
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
# CMake policy settings shared between LLVM projects

# CMP0114: ExternalProject step targets fully adopt their steps.
# New in CMake 3.19: https://cmake.org/cmake/help/latest/policy/CMP0114.html
if(POLICY CMP0114)
cmake_policy(SET CMP0114 OLD)
endif()
# CMP0116: Ninja generators transform `DEPFILE`s from `add_custom_command()`
# New in CMake 3.20. https://cmake.org/cmake/help/latest/policy/CMP0116.html
if(POLICY CMP0116)
Expand Down
6 changes: 3 additions & 3 deletions compiler-rt/lib/lsan/lsan_common.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -712,11 +712,11 @@ static bool ReportUnsuspendedThreads(

Sort(threads.data(), threads.size());

InternalMmapVector<tid_t> unsuspended;
GetRunningThreadsLocked(&unsuspended);
InternalMmapVector<tid_t> known_threads;
GetRunningThreadsLocked(&known_threads);

bool succeded = true;
for (auto os_id : unsuspended) {
for (auto os_id : known_threads) {
uptr i = InternalLowerBound(threads, os_id);
if (i >= threads.size() || threads[i] != os_id) {
succeded = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ TEST(SanitizerCommon, ChainedOriginDepotBasic) {

TEST(SanitizerCommon, ChainedOriginDepotAbsent) {
u32 prev_id;
EXPECT_EQ(0U, chainedOriginDepot.Get(99, &prev_id));
EXPECT_EQ(0U, chainedOriginDepot.Get(123456, &prev_id));
EXPECT_EQ(0U, prev_id);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,6 @@ TEST(SanitizerLinux, ThreadDescriptorSize) {
void *result;
ASSERT_EQ(0, pthread_create(&tid, 0, thread_descriptor_size_test_func, 0));
ASSERT_EQ(0, pthread_join(tid, &result));
EXPECT_EQ(0u, ThreadDescriptorSize());
InitTlsSize();
EXPECT_EQ((uptr)result, ThreadDescriptorSize());
}
Expand Down
22 changes: 14 additions & 8 deletions compiler-rt/lib/scudo/standalone/combined.h
Original file line number Diff line number Diff line change
Expand Up @@ -1255,22 +1255,26 @@ class Allocator {
else
Header->State = Chunk::State::Quarantined;

void *BlockBegin;
if (LIKELY(!useMemoryTagging<AllocatorConfig>(Options))) {
if (LIKELY(!useMemoryTagging<AllocatorConfig>(Options)))
Header->OriginOrWasZeroed = 0U;
if (BypassQuarantine && allocatorSupportsMemoryTagging<AllocatorConfig>())
Ptr = untagPointer(Ptr);
BlockBegin = getBlockBegin(Ptr, Header);
} else {
else {
Header->OriginOrWasZeroed =
Header->ClassId && !TSDRegistry.getDisableMemInit();
BlockBegin =
retagBlock(Options, TaggedPtr, Ptr, Header, Size, BypassQuarantine);
}

Chunk::storeHeader(Cookie, Ptr, Header);

if (BypassQuarantine) {
void *BlockBegin;
if (LIKELY(!useMemoryTagging<AllocatorConfig>(Options))) {
// Must do this after storeHeader because loadHeader uses a tagged ptr.
if (allocatorSupportsMemoryTagging<AllocatorConfig>())
Ptr = untagPointer(Ptr);
BlockBegin = getBlockBegin(Ptr, Header);
} else {
BlockBegin = retagBlock(Options, TaggedPtr, Ptr, Header, Size, true);
}

const uptr ClassId = Header->ClassId;
if (LIKELY(ClassId)) {
bool CacheDrained;
Expand All @@ -1288,6 +1292,8 @@ class Allocator {
Secondary.deallocate(Options, BlockBegin);
}
} else {
if (UNLIKELY(useMemoryTagging<AllocatorConfig>(Options)))
retagBlock(Options, TaggedPtr, Ptr, Header, Size, false);
typename TSDRegistryT::ScopedTSD TSD(TSDRegistry);
Quarantine.put(&TSD->getQuarantineCache(),
QuarantineCallback(*this, TSD->getCache()), Ptr, Size);
Expand Down
21 changes: 21 additions & 0 deletions compiler-rt/lib/scudo/standalone/tests/combined_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -534,6 +534,27 @@ SCUDO_TYPED_TEST(ScudoCombinedDeathTest, UseAfterFree) {
}
}

SCUDO_TYPED_TEST(ScudoCombinedDeathTest, DoubleFreeFromPrimary) {
auto *Allocator = this->Allocator.get();

for (scudo::uptr SizeLog = 0U; SizeLog <= 20U; SizeLog++) {
const scudo::uptr Size = 1U << SizeLog;
if (!isPrimaryAllocation<TestAllocator<TypeParam>>(Size, 0))
break;

// Verify that a double free results in a chunk state error.
EXPECT_DEATH(
{
// Allocate from primary
void *P = Allocator->allocate(Size, Origin);
ASSERT_TRUE(P != nullptr);
Allocator->deallocate(P, Origin);
Allocator->deallocate(P, Origin);
},
"invalid chunk state");
}
}

SCUDO_TYPED_TEST(ScudoCombinedDeathTest, DisableMemoryTagging) {
auto *Allocator = this->Allocator.get();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
#include <Foundation/Foundation.h>

@interface Foo : NSObject
@end

@implementation Foo
@end
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clang -c -o %t/EmptyClassFoo.o %S/Inputs/EmptyClassFoo.m
// RUN: ar r %t/libFooClass.a %t/EmptyClassFoo.o
// RUN: %clang -c -o %t/force-objc.o %s
// RUN: %llvm_jitlink -ObjC %t/force-objc.o -L%t -lFooClass
//
// REQUIRES: system-darwin && host-arch-compatible

id objc_getClass(const char *name);

int main(int argc, char *argv[]) {
// Return succeess if we find Foo, error otherwise.
return objc_getClass("Foo") ? 0 : 1;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
extern "C" int x;

namespace {

struct Init {
public:
Init() { x = 1; }
};

Init SetX;

} // namespace
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
// Check that the -all_load flag to llvm-jitlink causes all objects from
// archives to be loaded, regardless of whether or not they're referenced.
//
// RUN: rm -rf %t && mkdir -p %t
// RUN: %clangxx -c -o %t/SetX.o %S/Inputs/SetGlobalIntXInConstructor.cpp
// RUN: ar r %t/libSetX.a %t/SetX.o
// RUN: %clang -c -o %t/all_load.o %s
// RUN: %llvm_jitlink -all_load %t/all_load.o -L%t -lSetX
//
// REQUIRES: system-darwin && host-arch-compatible

int x = 0;

int main(int argc, char *argv[]) { return x == 1 ? 0 : 1; }
5 changes: 4 additions & 1 deletion compiler-rt/test/orc/lit.cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

if config.host_arch == "x86_64h" and config.target_arch == "x86_64":
host_arch_compatible = True
if host_arch_compatible:
config.available_features.add("host-arch-compatible")
config.test_target_is_host_executable = (
config.target_os == config.host_os and host_arch_compatible
)
Expand Down Expand Up @@ -71,9 +73,10 @@ def build_invocation(compile_flags):
(lli + " -jit-kind=orc -jit-linker=jitlink -orc-runtime=" + orc_rt_path),
)
)
config.substitutions.append(("%ar", "ar"))

# Default test suffixes.
config.suffixes = [".c", ".cpp", ".S", ".ll", ".test"]
config.suffixes = [".c", ".cpp", ".m", ".S", ".ll", ".test"]

# Exclude Inputs directories.
config.excludes = ["Inputs"]
Expand Down
2 changes: 2 additions & 0 deletions flang/docs/Extensions.md
Original file line number Diff line number Diff line change
Expand Up @@ -389,6 +389,8 @@ end
* A local data object may appear in a specification expression, even
when it is not a dummy argument or in COMMON, so long as it is
has the SAVE attribute and was initialized.
* `PRINT namelistname` is accepted and interpreted as
`WRITE(*,NML=namelistname)`, a near-universal extension.

### Extensions supported when enabled by options

Expand Down
8 changes: 4 additions & 4 deletions flang/include/flang/Common/Fortran-features.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ ENUM_CLASS(LanguageFeature, BackslashEscapes, OldDebugLines,
NonBindCInteroperability, CudaManaged, CudaUnified,
PolymorphicActualAllocatableOrPointerToMonomorphicDummy, RelaxedPureDummy,
UndefinableAsynchronousOrVolatileActual, AutomaticInMainProgram, PrintCptr,
SavedLocalInSpecExpr)
SavedLocalInSpecExpr, PrintNamelist)

// Portability and suspicious usage warnings
ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
Expand All @@ -63,9 +63,9 @@ ENUM_CLASS(UsageWarning, Portability, PointerToUndefinable,
F202XAllocatableBreakingChange, OptionalMustBePresent, CommonBlockPadding,
LogicalVsCBool, BindCCharLength, ProcDummyArgShapes, ExternalNameConflict,
FoldingException, FoldingAvoidsRuntimeCrash, FoldingValueChecks,
FoldingFailure, FoldingLimit, Interoperability, Bounds, Preprocessing,
Scanning, OpenAccUsage, ProcPointerCompatibility, VoidMold,
KnownBadImplicitInterface, EmptyCase, CaseOverflow, CUDAUsage,
FoldingFailure, FoldingLimit, Interoperability, CharacterInteroperability,
Bounds, Preprocessing, Scanning, OpenAccUsage, ProcPointerCompatibility,
VoidMold, KnownBadImplicitInterface, EmptyCase, CaseOverflow, CUDAUsage,
IgnoreTKRUsage, ExternalInterfaceMismatch, DefinedOperatorArgs, Final,
ZeroDoStep, UnusedForallIndex, OpenMPUsage, ModuleFile, DataLength,
IgnoredDirective, HomonymousSpecific, HomonymousResult,
Expand Down
116 changes: 116 additions & 0 deletions flang/include/flang/Common/erfc-scaled.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
//===-- include/flang/Common/erfc-scaled.h-----------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#ifndef FORTRAN_COMMON_ERFC_SCALED_H_
#define FORTRAN_COMMON_ERFC_SCALED_H_

namespace Fortran::common {
template <typename T> inline T ErfcScaled(T arg) {
// Coefficients for approximation to erfc in the first interval.
static const T a[5] = {3.16112374387056560e00, 1.13864154151050156e02,
3.77485237685302021e02, 3.20937758913846947e03, 1.85777706184603153e-1};
static const T b[4] = {2.36012909523441209e01, 2.44024637934444173e02,
1.28261652607737228e03, 2.84423683343917062e03};

// Coefficients for approximation to erfc in the second interval.
static const T c[9] = {5.64188496988670089e-1, 8.88314979438837594e00,
6.61191906371416295e01, 2.98635138197400131e02, 8.81952221241769090e02,
1.71204761263407058e03, 2.05107837782607147e03, 1.23033935479799725e03,
2.15311535474403846e-8};
static const T d[8] = {1.57449261107098347e01, 1.17693950891312499e02,
5.37181101862009858e02, 1.62138957456669019e03, 3.29079923573345963e03,
4.36261909014324716e03, 3.43936767414372164e03, 1.23033935480374942e03};

// Coefficients for approximation to erfc in the third interval.
static const T p[6] = {3.05326634961232344e-1, 3.60344899949804439e-1,
1.25781726111229246e-1, 1.60837851487422766e-2, 6.58749161529837803e-4,
1.63153871373020978e-2};
static const T q[5] = {2.56852019228982242e00, 1.87295284992346047e00,
5.27905102951428412e-1, 6.05183413124413191e-2, 2.33520497626869185e-3};

constexpr T sqrtpi{1.7724538509078120380404576221783883301349L};
constexpr T rsqrtpi{0.5641895835477562869480794515607725858440L};
constexpr T epsilonby2{std::numeric_limits<T>::epsilon() * 0.5};
constexpr T xneg{-26.628e0};
constexpr T xhuge{6.71e7};
constexpr T thresh{0.46875e0};
constexpr T zero{0.0};
constexpr T one{1.0};
constexpr T four{4.0};
constexpr T sixteen{16.0};
constexpr T xmax{1.0 / (sqrtpi * std::numeric_limits<T>::min())};
static_assert(xmax > xhuge, "xmax must be greater than xhuge");

T ysq;
T xnum;
T xden;
T del;
T result;

auto x{arg};
auto y{std::fabs(x)};

if (y <= thresh) {
// evaluate erf for |x| <= 0.46875
ysq = zero;
if (y > epsilonby2) {
ysq = y * y;
}
xnum = a[4] * ysq;
xden = ysq;
for (int i{0}; i < 3; i++) {
xnum = (xnum + a[i]) * ysq;
xden = (xden + b[i]) * ysq;
}
result = x * (xnum + a[3]) / (xden + b[3]);
result = one - result;
result = std::exp(ysq) * result;
return result;
} else if (y <= four) {
// evaluate erfc for 0.46875 < |x| <= 4.0
xnum = c[8] * y;
xden = y;
for (int i{0}; i < 7; ++i) {
xnum = (xnum + c[i]) * y;
xden = (xden + d[i]) * y;
}
result = (xnum + c[7]) / (xden + d[7]);
} else {
// evaluate erfc for |x| > 4.0
result = zero;
if (y >= xhuge) {
if (y < xmax) {
result = rsqrtpi / y;
}
} else {
ysq = one / (y * y);
xnum = p[5] * ysq;
xden = ysq;
for (int i{0}; i < 4; ++i) {
xnum = (xnum + p[i]) * ysq;
xden = (xden + q[i]) * ysq;
}
result = ysq * (xnum + p[4]) / (xden + q[4]);
result = (rsqrtpi - result) / y;
}
}
// fix up for negative argument, erf, etc.
if (x < zero) {
if (x < xneg) {
result = std::numeric_limits<T>::max();
} else {
ysq = trunc(x * sixteen) / sixteen;
del = (x - ysq) * (x + ysq);
y = std::exp((ysq * ysq)) * std::exp((del));
result = (y + y) - result;
}
}
return result;
}
} // namespace Fortran::common
#endif // FORTRAN_COMMON_ERFC_SCALED_H_
6 changes: 5 additions & 1 deletion flang/include/flang/Evaluate/tools.h
Original file line number Diff line number Diff line change
Expand Up @@ -1252,8 +1252,12 @@ class ArrayConstantBoundChanger {
// Predicate: should two expressions be considered identical for the purposes
// of determining whether two procedure interfaces are compatible, modulo
// naming of corresponding dummy arguments?
std::optional<bool> AreEquivalentInInterface(
template <typename T>
std::optional<bool> AreEquivalentInInterface(const Expr<T> &, const Expr<T> &);
extern template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &);
extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
const Expr<SomeInteger> &, const Expr<SomeInteger> &);

bool CheckForCoindexedObject(parser::ContextualMessages &,
const std::optional<ActualArgument> &, const std::string &procName,
Expand Down
19 changes: 19 additions & 0 deletions flang/include/flang/Optimizer/Dialect/CUF/CUFOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -288,4 +288,23 @@ def cuf_KernelOp : cuf_Op<"kernel", [AttrSizedOperandSegments,
let hasVerifier = 1;
}

def cuf_RegisterKernelOp : cuf_Op<"register_kernel", []> {
let summary = "Register a CUDA kernel";

let arguments = (ins
SymbolRefAttr:$name
);

let assemblyFormat = [{
$name attr-dict
}];

let hasVerifier = 1;

let extraClassDeclaration = [{
mlir::StringAttr getKernelName();
mlir::StringAttr getKernelModuleName();
}];
}

#endif // FORTRAN_DIALECT_CUF_CUF_OPS
2 changes: 1 addition & 1 deletion flang/include/flang/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -439,7 +439,7 @@ def CufImplicitDeviceGlobal :
def CUFAddConstructor : Pass<"cuf-add-constructor", "mlir::ModuleOp"> {
let summary = "Add constructor to register CUDA Fortran allocators";
let dependentDialects = [
"mlir::func::FuncDialect"
"cuf::CUFDialect", "mlir::func::FuncDialect"
];
}

Expand Down
12 changes: 12 additions & 0 deletions flang/include/flang/Semantics/type.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,13 @@ namespace Fortran::parser {
struct Keyword;
}

namespace Fortran::evaluate { // avoid including all of Evaluate/tools.h
template <typename T>
std::optional<bool> AreEquivalentInInterface(const Expr<T> &, const Expr<T> &);
extern template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
const Expr<SomeInteger> &, const Expr<SomeInteger> &);
} // namespace Fortran::evaluate

namespace Fortran::semantics {

class Scope;
Expand Down Expand Up @@ -110,6 +117,11 @@ class ParamValue {
return category_ == that.category_ && expr_ == that.expr_;
}
bool operator!=(const ParamValue &that) const { return !(*this == that); }
bool IsEquivalentInInterface(const ParamValue &that) const {
return (category_ == that.category_ &&
expr_.has_value() == that.expr_.has_value() &&
(!expr_ || evaluate::AreEquivalentInInterface(*expr_, *that.expr_)));
}
std::string AsFortran() const;

private:
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Common/Fortran-features.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ LanguageFeatureControl::LanguageFeatureControl() {
warnUsage_.set(UsageWarning::FoldingFailure);
warnUsage_.set(UsageWarning::FoldingLimit);
warnUsage_.set(UsageWarning::Interoperability);
// CharacterInteroperability warnings about length are off by default
warnUsage_.set(UsageWarning::Bounds);
warnUsage_.set(UsageWarning::Preprocessing);
warnUsage_.set(UsageWarning::Scanning);
Expand Down
2 changes: 2 additions & 0 deletions flang/lib/Evaluate/intrinsics-library.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "flang/Evaluate/intrinsics-library.h"
#include "fold-implementation.h"
#include "host.h"
#include "flang/Common/erfc-scaled.h"
#include "flang/Common/static-multimap-view.h"
#include "flang/Evaluate/expression.h"
#include <cfloat>
Expand Down Expand Up @@ -231,6 +232,7 @@ struct HostRuntimeLibrary<HostT, LibraryVersion::Libm> {
FolderFactory<F, F{std::cosh}>::Create("cosh"),
FolderFactory<F, F{std::erf}>::Create("erf"),
FolderFactory<F, F{std::erfc}>::Create("erfc"),
FolderFactory<F, F{common::ErfcScaled}>::Create("erfc_scaled"),
FolderFactory<F, F{std::exp}>::Create("exp"),
FolderFactory<F, F{std::tgamma}>::Create("gamma"),
FolderFactory<F, F{std::log}>::Create("log"),
Expand Down
45 changes: 33 additions & 12 deletions flang/lib/Evaluate/intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2861,12 +2861,22 @@ IntrinsicProcTable::Implementation::HandleC_F_Pointer(
}
} else if (!IsInteroperableIntrinsicType(
*type, &context.languageFeatures())
.value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type %s"_warn_en_US,
type->AsFortran());
.value_or(true)) {
if (type->category() == TypeCategory::Character &&
type->kind() == 1) {
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::CharacterInteroperability)) {
context.messages().Say(
common::UsageWarning::CharacterInteroperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable character length %s"_warn_en_US,
type->AsFortran());
}
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability, at,
"FPTR= argument to C_F_POINTER() should not have the non-interoperable intrinsic type or kind %s"_warn_en_US,
type->AsFortran());
}
}
if (ExtractCoarrayRef(*expr)) {
context.messages().Say(at,
Expand Down Expand Up @@ -2963,12 +2973,23 @@ std::optional<SpecificCall> IntrinsicProcTable::Implementation::HandleC_Loc(
context.messages().Say(arguments[0]->sourceLocation(),
"C_LOC() argument may not be zero-length character"_err_en_US);
} else if (typeAndShape->type().category() != TypeCategory::Derived &&
!IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true) &&
context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type, kind, or length"_warn_en_US);
!IsInteroperableIntrinsicType(typeAndShape->type()).value_or(true)) {
if (typeAndShape->type().category() == TypeCategory::Character &&
typeAndShape->type().kind() == 1) {
// Default character kind, but length is not known to be 1
if (context.languageFeatures().ShouldWarn(
common::UsageWarning::CharacterInteroperability)) {
context.messages().Say(
common::UsageWarning::CharacterInteroperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable character length"_warn_en_US);
}
} else if (context.languageFeatures().ShouldWarn(
common::UsageWarning::Interoperability)) {
context.messages().Say(common::UsageWarning::Interoperability,
arguments[0]->sourceLocation(),
"C_LOC() argument has non-interoperable intrinsic type or kind"_warn_en_US);
}
}

characteristics::DummyDataObject ddo{std::move(*typeAndShape)};
Expand Down
16 changes: 14 additions & 2 deletions flang/lib/Evaluate/tools.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1320,8 +1320,10 @@ std::optional<Expr<SomeType>> HollerithToBOZ(FoldingContext &context,

// Extracts a whole symbol being used as a bound of a dummy argument,
// possibly wrapped with parentheses or MAX(0, ...).
// Works with any integer expression.
template <typename T> const Symbol *GetBoundSymbol(const Expr<T> &);
template <int KIND>
static const Symbol *GetBoundSymbol(
const Symbol *GetBoundSymbol(
const Expr<Type<TypeCategory::Integer, KIND>> &expr) {
using T = Type<TypeCategory::Integer, KIND>;
return common::visit(
Expand Down Expand Up @@ -1358,9 +1360,15 @@ static const Symbol *GetBoundSymbol(
},
expr.u);
}
template <>
const Symbol *GetBoundSymbol<SomeInteger>(const Expr<SomeInteger> &expr) {
return common::visit(
[](const auto &kindExpr) { return GetBoundSymbol(kindExpr); }, expr.u);
}

template <typename T>
std::optional<bool> AreEquivalentInInterface(
const Expr<SubscriptInteger> &x, const Expr<SubscriptInteger> &y) {
const Expr<T> &x, const Expr<T> &y) {
auto xVal{ToInt64(x)};
auto yVal{ToInt64(y)};
if (xVal && yVal) {
Expand Down Expand Up @@ -1394,6 +1402,10 @@ std::optional<bool> AreEquivalentInInterface(
return std::nullopt; // not sure
}
}
template std::optional<bool> AreEquivalentInInterface<SubscriptInteger>(
const Expr<SubscriptInteger> &, const Expr<SubscriptInteger> &);
template std::optional<bool> AreEquivalentInInterface<SomeInteger>(
const Expr<SomeInteger> &, const Expr<SomeInteger> &);

bool CheckForCoindexedObject(parser::ContextualMessages &messages,
const std::optional<ActualArgument> &arg, const std::string &procName,
Expand Down
5 changes: 4 additions & 1 deletion flang/lib/Evaluate/type.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -518,7 +518,10 @@ static bool AreSameDerivedType(

bool DynamicType::IsEquivalentTo(const DynamicType &that) const {
return category_ == that.category_ && kind_ == that.kind_ &&
PointeeComparison(charLengthParamValue_, that.charLengthParamValue_) &&
(charLengthParamValue_ == that.charLengthParamValue_ ||
(charLengthParamValue_ && that.charLengthParamValue_ &&
charLengthParamValue_->IsEquivalentInInterface(
*that.charLengthParamValue_))) &&
knownLength().has_value() == that.knownLength().has_value() &&
(!knownLength() || *knownLength() == *that.knownLength()) &&
AreSameDerivedType(derived_, that.derived_);
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Optimizer/Dialect/CUF/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ add_flang_library(CUFDialect
FIRDialect
FIRDialectSupport
MLIRIR
MLIRGPUDialect
MLIRTargetLLVMIRExport

LINK_COMPONENTS
Expand Down
37 changes: 37 additions & 0 deletions flang/lib/Optimizer/Dialect/CUF/CUFOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
#include "flang/Optimizer/Dialect/CUF/CUFDialect.h"
#include "flang/Optimizer/Dialect/FIRAttr.h"
#include "flang/Optimizer/Dialect/FIRType.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/IR/Attributes.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinOps.h"
Expand Down Expand Up @@ -253,6 +254,42 @@ llvm::LogicalResult cuf::KernelOp::verify() {
return mlir::success();
}

//===----------------------------------------------------------------------===//
// RegisterKernelOp
//===----------------------------------------------------------------------===//

mlir::StringAttr cuf::RegisterKernelOp::getKernelModuleName() {
return getName().getRootReference();
}

mlir::StringAttr cuf::RegisterKernelOp::getKernelName() {
return getName().getLeafReference();
}

mlir::LogicalResult cuf::RegisterKernelOp::verify() {
if (getKernelName() == getKernelModuleName())
return emitOpError("expect a module and a kernel name");

auto mod = getOperation()->getParentOfType<mlir::ModuleOp>();
if (!mod)
return emitOpError("expect to be in a module");

mlir::SymbolTable symTab(mod);
auto gpuMod = symTab.lookup<mlir::gpu::GPUModuleOp>(getKernelModuleName());
if (!gpuMod)
return emitOpError("gpu module not found");

mlir::SymbolTable gpuSymTab(gpuMod);
auto func = gpuSymTab.lookup<mlir::gpu::GPUFuncOp>(getKernelName());
if (!func)
return emitOpError("device function not found");

if (!func.isKernel())
return emitOpError("only kernel gpu.func can be registered");

return mlir::success();
}

// Tablegen operators

#define GET_OP_CLASSES
Expand Down
1 change: 1 addition & 0 deletions flang/lib/Optimizer/Transforms/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ add_flang_library(FIRTransforms
HLFIRDialect
MLIRAffineUtils
MLIRFuncDialect
MLIRGPUDialect
MLIRLLVMDialect
MLIRLLVMCommonConversion
MLIRMathTransforms
Expand Down
Loading