diff options
Diffstat (limited to 'clang')
33 files changed, 1961 insertions, 30 deletions
diff --git a/clang/docs/LibASTMatchersReference.html b/clang/docs/LibASTMatchersReference.html index 5b2a96d..ac1abb4 100644 --- a/clang/docs/LibASTMatchersReference.html +++ b/clang/docs/LibASTMatchersReference.html @@ -825,6 +825,20 @@ fieldDecl() </pre></td></tr> +<tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('fileScopeAsmDecl0')"><a name="fileScopeAsmDecl0Anchor">fileScopeAsmDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FileScopeAsmDecl.html">FileScopeAsmDecl</a>>...</td></tr> +<tr><td colspan="4" class="doc" id="fileScopeAsmDecl0"><pre>Matches top level asm declarations. + +Given + __asm("nop"); + void f() { + __asm("mov al, 2"); + } +fileScopeAsmDecl() + matches '__asm("nop")', + but not '__asm("mov al, 2")'. +</pre></td></tr> + + <tr><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>></td><td class="name" onclick="toggle('friendDecl0')"><a name="friendDecl0Anchor">friendDecl</a></td><td>Matcher<<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>>...</td></tr> <tr><td colspan="4" class="doc" id="friendDecl0"><pre>Matches friend declarations. diff --git a/clang/include/clang/ASTMatchers/ASTMatchers.h b/clang/include/clang/ASTMatchers/ASTMatchers.h index 98e62de..bca2d84 100644 --- a/clang/include/clang/ASTMatchers/ASTMatchers.h +++ b/clang/include/clang/ASTMatchers/ASTMatchers.h @@ -2478,6 +2478,21 @@ extern const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; /// matches '__asm("mov al, 2")' extern const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; +/// Matches top level asm declarations. +/// +/// Given +/// \code +/// __asm("nop"); +/// void f() { +/// __asm("mov al, 2"); +/// } +/// \endcode +/// fileScopeAsmDecl() +/// matches '__asm("nop")', +/// but not '__asm("mov al, 2")'. +extern const internal::VariadicDynCastAllOfMatcher<Decl, FileScopeAsmDecl> + fileScopeAsmDecl; + /// Matches bool literals. /// /// Example matches true diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 749f531..1013bfc 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -5017,6 +5017,10 @@ def HLSLUnparsedSemantic : HLSLAnnotationAttr { let Documentation = [InternalOnly]; } +def HLSLUserSemantic : HLSLSemanticAttr</* Indexable= */ 1> { + let Documentation = [InternalOnly]; +} + def HLSLSV_Position : HLSLSemanticAttr</* Indexable= */ 1> { let Documentation = [HLSLSV_PositionDocs]; } diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index fa50953..f43707e 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -13184,6 +13184,7 @@ def err_hlsl_semantic_indexing_not_supported : Error<"semantic %0 does not allow indexing">; def err_hlsl_init_priority_unsupported : Error< "initializer priorities are not supported in HLSL">; +def err_hlsl_semantic_index_overlap : Error<"semantic index overlap %0">; def warn_hlsl_user_defined_type_missing_member: Warning<"binding type '%select{t|u|b|s|c}0' only applies to types containing %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric types}0">, InGroup<LegacyConstantRegisterBinding>; def err_hlsl_binding_type_mismatch: Error<"binding type '%select{t|u|b|s|c}0' only applies to %select{SRV resources|UAV resources|constant buffer resources|sampler state|numeric variables in the global scope}0">; diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def index d3cca82..40fc66e 100644 --- a/clang/include/clang/Basic/LangOptions.def +++ b/clang/include/clang/Basic/LangOptions.def @@ -454,7 +454,7 @@ LANGOPT(BranchTargetEnforcement, 1, 0, NotCompatible, "Branch-target enforcement LANGOPT(BranchProtectionPAuthLR, 1, 0, NotCompatible, "Use PC as a diversifier using PAuthLR NOP instructions.") LANGOPT(GuardedControlStack, 1, 0, NotCompatible, "Guarded control stack enabled") -LANGOPT(SpeculativeLoadHardening, 1, 0, NotCompatible, "Speculative load hardening enabled") +LANGOPT(SpeculativeLoadHardening, 1, 0, Benign, "Speculative load hardening enabled") LANGOPT(RelativeCXXABIVTables, 1, 0, NotCompatible, "Use an ABI-incompatible v-table layout that uses relative references") diff --git a/clang/include/clang/CIR/Dialect/IR/CIROps.td b/clang/include/clang/CIR/Dialect/IR/CIROps.td index 6f9a69e..1625851 100644 --- a/clang/include/clang/CIR/Dialect/IR/CIROps.td +++ b/clang/include/clang/CIR/Dialect/IR/CIROps.td @@ -4090,6 +4090,57 @@ def CIR_PrefetchOp : CIR_Op<"prefetch"> { } //===----------------------------------------------------------------------===// +// ObjSizeOp +//===----------------------------------------------------------------------===// + +def CIR_ObjSizeOp : CIR_Op<"objsize", [Pure]> { + let summary = "Implements the llvm.objsize builtin"; + let description = [{ + The `cir.objsize` operation is designed to provide information to the + optimizer to determine whether a) an operation (like memcpy) will + overflow a buffer that corresponds to an object, or b) that a runtime + check for overflow isn’t necessary. An object in this context means an + allocation of a specific class, structure, array, or other object. + + When the `min` attribute is present, the operation returns the minimum + guaranteed accessible size. When absent (max mode), it returns the maximum + possible object size. Corresponds to `llvm.objectsize`'s `min` argument. + + The `dynamic` attribute determines if the value should be evaluated at + runtime. Corresponds to `llvm.objectsize`'s `dynamic` argument. + + The `nullunknown` attribute controls how null pointers are handled. When + present, null pointers are treated as having unknown size. When absent, + null pointers are treated as having 0 size (in min mode) or -1 size + (in max mode). Corresponds to `llvm.objectsize`'s `nullunknown` argument. + + Example: + + ```mlir + %size = cir.objsize min %ptr : !cir.ptr<i32> -> i64 + %dsize = cir.objsize max dynamic %ptr : !cir.ptr<i32> -> i64 + %nsize = cir.objsize min nullunknown %ptr : !cir.ptr<i32> -> i64 + ``` + }]; + + let arguments = (ins + CIR_PointerType:$ptr, + UnitAttr:$min, + UnitAttr:$nullunknown, + UnitAttr:$dynamic + ); + + let results = (outs CIR_AnyFundamentalIntType:$result); + + let assemblyFormat = [{ + (`min` $min^) : (`max`)? + (`nullunknown` $nullunknown^)? + (`dynamic` $dynamic^)? + $ptr `:` qualified(type($ptr)) `->` qualified(type($result)) attr-dict + }]; +} + +//===----------------------------------------------------------------------===// // PtrDiffOp //===----------------------------------------------------------------------===// diff --git a/clang/include/clang/CIR/MissingFeatures.h b/clang/include/clang/CIR/MissingFeatures.h index 6f099a7..af1ffff 100644 --- a/clang/include/clang/CIR/MissingFeatures.h +++ b/clang/include/clang/CIR/MissingFeatures.h @@ -215,6 +215,7 @@ struct MissingFeatures { static bool builtinCallMathErrno() { return false; } static bool builtinCheckKind() { return false; } static bool cgCapturedStmtInfo() { return false; } + static bool countedBySize() { return false; } static bool cgFPOptionsRAII() { return false; } static bool checkBitfieldClipping() { return false; } static bool cirgenABIInfo() { return false; } diff --git a/clang/include/clang/Sema/SemaHLSL.h b/clang/include/clang/Sema/SemaHLSL.h index 8c3b6ae..28b03ac 100644 --- a/clang/include/clang/Sema/SemaHLSL.h +++ b/clang/include/clang/Sema/SemaHLSL.h @@ -20,7 +20,9 @@ #include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/SourceLocation.h" #include "clang/Sema/SemaBase.h" +#include "llvm/ADT/DenseMap.h" #include "llvm/ADT/SmallVector.h" +#include "llvm/ADT/StringSet.h" #include "llvm/TargetParser/Triple.h" #include <initializer_list> @@ -259,9 +261,11 @@ private: HLSLSemanticAttr *createSemantic(const SemanticInfo &Semantic, DeclaratorDecl *TargetDecl); bool determineActiveSemanticOnScalar(FunctionDecl *FD, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic); + SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics); bool determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic); + SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics); void processExplicitBindingsOnDecl(VarDecl *D); diff --git a/clang/lib/AST/ByteCode/Compiler.cpp b/clang/lib/AST/ByteCode/Compiler.cpp index 4e63400..84f7e62 100644 --- a/clang/lib/AST/ByteCode/Compiler.cpp +++ b/clang/lib/AST/ByteCode/Compiler.cpp @@ -6007,6 +6007,8 @@ bool Compiler<Emitter>::visitSwitchStmt(const SwitchStmt *S) { CaseLabels[SC] = this->getLabel(); const Expr *Value = CS->getLHS(); + if (Value->isValueDependent()) + return false; PrimType ValueT = this->classifyPrim(Value->getType()); // Compare the case statement's value to the switch condition. diff --git a/clang/lib/AST/ExprConstant.cpp b/clang/lib/AST/ExprConstant.cpp index 8fab6ef..193f87c 100644 --- a/clang/lib/AST/ExprConstant.cpp +++ b/clang/lib/AST/ExprConstant.cpp @@ -5452,10 +5452,13 @@ static EvalStmtResult EvaluateSwitch(StmtResult &Result, EvalInfo &Info, } const CaseStmt *CS = cast<CaseStmt>(SC); - APSInt LHS = CS->getLHS()->EvaluateKnownConstInt(Info.Ctx); - APSInt RHS = CS->getRHS() ? CS->getRHS()->EvaluateKnownConstInt(Info.Ctx) - : LHS; - if (LHS <= Value && Value <= RHS) { + const Expr *LHS = CS->getLHS(); + const Expr *RHS = CS->getRHS(); + if (LHS->isValueDependent() || (RHS && RHS->isValueDependent())) + return ESR_Failed; + APSInt LHSValue = LHS->EvaluateKnownConstInt(Info.Ctx); + APSInt RHSValue = RHS ? RHS->EvaluateKnownConstInt(Info.Ctx) : LHSValue; + if (LHSValue <= Value && Value <= RHSValue) { Found = SC; break; } diff --git a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp index 42f124b..0874b3d 100644 --- a/clang/lib/ASTMatchers/ASTMatchersInternal.cpp +++ b/clang/lib/ASTMatchers/ASTMatchersInternal.cpp @@ -954,6 +954,8 @@ const internal::VariadicDynCastAllOfMatcher<Stmt, CXXTryStmt> cxxTryStmt; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXThrowExpr> cxxThrowExpr; const internal::VariadicDynCastAllOfMatcher<Stmt, NullStmt> nullStmt; const internal::VariadicDynCastAllOfMatcher<Stmt, AsmStmt> asmStmt; +const internal::VariadicDynCastAllOfMatcher<Decl, FileScopeAsmDecl> + fileScopeAsmDecl; const internal::VariadicDynCastAllOfMatcher<Stmt, CXXBoolLiteralExpr> cxxBoolLiteral; const internal::VariadicDynCastAllOfMatcher<Stmt, StringLiteral> stringLiteral; diff --git a/clang/lib/ASTMatchers/Dynamic/Registry.cpp b/clang/lib/ASTMatchers/Dynamic/Registry.cpp index 01c03f3..66848f7 100644 --- a/clang/lib/ASTMatchers/Dynamic/Registry.cpp +++ b/clang/lib/ASTMatchers/Dynamic/Registry.cpp @@ -246,6 +246,7 @@ RegistryMaps::RegistryMaps() { REGISTER_MATCHER(expr); REGISTER_MATCHER(exprWithCleanups); REGISTER_MATCHER(fieldDecl); + REGISTER_MATCHER(fileScopeAsmDecl); REGISTER_MATCHER(fixedPointLiteral); REGISTER_MATCHER(floatLiteral); REGISTER_MATCHER(forCallable); diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp index 0803910..4e6a5ee 100644 --- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp +++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp @@ -481,6 +481,19 @@ RValue CIRGenFunction::emitBuiltinExpr(const GlobalDecl &gd, unsigned builtinID, return emitCall(e->getCallee()->getType(), CIRGenCallee::forDirect(fnOp), e, returnValue); } + case Builtin::BI__builtin_dynamic_object_size: + case Builtin::BI__builtin_object_size: { + unsigned type = + e->getArg(1)->EvaluateKnownConstInt(getContext()).getZExtValue(); + auto resType = mlir::cast<cir::IntType>(convertType(e->getType())); + + // We pass this builtin onto the optimizer so that it can figure out the + // object size in more complex cases. + bool isDynamic = builtinID == Builtin::BI__builtin_dynamic_object_size; + return RValue::get(emitBuiltinObjectSize(e->getArg(0), type, resType, + /*EmittedE=*/nullptr, isDynamic)); + } + case Builtin::BI__builtin_prefetch: { auto evaluateOperandAsInt = [&](const Expr *arg) { Expr::EvalResult res; @@ -663,3 +676,42 @@ mlir::Value CIRGenFunction::emitVAArg(VAArgExpr *ve) { mlir::Value vaList = emitVAListRef(ve->getSubExpr()).getPointer(); return cir::VAArgOp::create(builder, loc, type, vaList); } + +mlir::Value CIRGenFunction::emitBuiltinObjectSize(const Expr *e, unsigned type, + cir::IntType resType, + mlir::Value emittedE, + bool isDynamic) { + assert(!cir::MissingFeatures::opCallImplicitObjectSizeArgs()); + + // LLVM can't handle type=3 appropriately, and __builtin_object_size shouldn't + // evaluate e for side-effects. In either case, just like original LLVM + // lowering, we shouldn't lower to `cir.objsize` but to a constant instead. + if (type == 3 || (!emittedE && e->HasSideEffects(getContext()))) + return builder.getConstInt(getLoc(e->getSourceRange()), resType, + (type & 2) ? 0 : -1); + + mlir::Value ptr = emittedE ? emittedE : emitScalarExpr(e); + assert(mlir::isa<cir::PointerType>(ptr.getType()) && + "Non-pointer passed to __builtin_object_size?"); + + assert(!cir::MissingFeatures::countedBySize()); + + // Extract the min/max mode from type. CIR only supports type 0 + // (max, whole object) and type 2 (min, whole object), not type 1 or 3 + // (closest subobject variants). + const bool min = ((type & 2) != 0); + // For GCC compatibility, __builtin_object_size treats NULL as unknown size. + auto op = + cir::ObjSizeOp::create(builder, getLoc(e->getSourceRange()), resType, ptr, + min, /*nullUnknown=*/true, isDynamic); + return op.getResult(); +} + +mlir::Value CIRGenFunction::evaluateOrEmitBuiltinObjectSize( + const Expr *e, unsigned type, cir::IntType resType, mlir::Value emittedE, + bool isDynamic) { + uint64_t objectSize; + if (!e->tryEvaluateObjectSize(objectSize, getContext(), type)) + return emitBuiltinObjectSize(e, type, resType, emittedE, isDynamic); + return builder.getConstInt(getLoc(e->getSourceRange()), resType, objectSize); +} diff --git a/clang/lib/CIR/CodeGen/CIRGenFunction.h b/clang/lib/CIR/CodeGen/CIRGenFunction.h index 1c52a78..f879e58 100644 --- a/clang/lib/CIR/CodeGen/CIRGenFunction.h +++ b/clang/lib/CIR/CodeGen/CIRGenFunction.h @@ -1307,6 +1307,28 @@ public: RValue emitBuiltinExpr(const clang::GlobalDecl &gd, unsigned builtinID, const clang::CallExpr *e, ReturnValueSlot returnValue); + /// Returns a Value corresponding to the size of the given expression by + /// emitting a `cir.objsize` operation. + /// + /// \param e The expression whose object size to compute + /// \param type Determines the semantics of the object size computation. + /// The type parameter is a 2-bit value where: + /// bit 0 (type & 1): 0 = whole object, 1 = closest subobject + /// bit 1 (type & 2): 0 = maximum size, 2 = minimum size + /// \param resType The result type for the size value + /// \param emittedE Optional pre-emitted pointer value. If non-null, we'll + /// call `cir.objsize` on this value rather than emitting e. + /// \param isDynamic If true, allows runtime evaluation via dynamic mode + mlir::Value emitBuiltinObjectSize(const clang::Expr *e, unsigned type, + cir::IntType resType, mlir::Value emittedE, + bool isDynamic); + + mlir::Value evaluateOrEmitBuiltinObjectSize(const clang::Expr *e, + unsigned type, + cir::IntType resType, + mlir::Value emittedE, + bool isDynamic); + RValue emitCall(const CIRGenFunctionInfo &funcInfo, const CIRGenCallee &callee, ReturnValueSlot returnValue, const CallArgList &args, cir::CIRCallOpInterface *callOp, diff --git a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp index ba967a4..b4afed7 100644 --- a/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp +++ b/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp @@ -2832,6 +2832,29 @@ static void collectUnreachable(mlir::Operation *parent, } } +mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite( + cir::ObjSizeOp op, OpAdaptor adaptor, + mlir::ConversionPatternRewriter &rewriter) const { + mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType()); + mlir::Location loc = op->getLoc(); + + mlir::IntegerType i1Ty = rewriter.getI1Type(); + + auto i1Val = [&rewriter, &loc, &i1Ty](bool val) { + return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val); + }; + + replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy, + { + adaptor.getPtr(), + i1Val(op.getMin()), + i1Val(op.getNullunknown()), + i1Val(op.getDynamic()), + }); + + return mlir::LogicalResult::success(); +} + void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) { // Lower the module attributes to LLVM equivalents. if (mlir::Attribute tripleAttr = diff --git a/clang/lib/CodeGen/CGHLSLRuntime.cpp b/clang/lib/CodeGen/CGHLSLRuntime.cpp index 945f9e2..e392a12 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.cpp +++ b/clang/lib/CodeGen/CGHLSLRuntime.cpp @@ -549,6 +549,16 @@ static void addSPIRVBuiltinDecoration(llvm::GlobalVariable *GV, GV->addMetadata("spirv.Decorations", *Decoration); } +static void addLocationDecoration(llvm::GlobalVariable *GV, unsigned Location) { + LLVMContext &Ctx = GV->getContext(); + IRBuilder<> B(GV->getContext()); + MDNode *Operands = + MDNode::get(Ctx, {ConstantAsMetadata::get(B.getInt32(/* Location */ 30)), + ConstantAsMetadata::get(B.getInt32(Location))}); + MDNode *Decoration = MDNode::get(Ctx, {Operands}); + GV->addMetadata("spirv.Decorations", *Decoration); +} + static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, llvm::Type *Ty, const Twine &Name, unsigned BuiltInID) { @@ -562,6 +572,69 @@ static llvm::Value *createSPIRVBuiltinLoad(IRBuilder<> &B, llvm::Module &M, return B.CreateLoad(Ty, GV); } +static llvm::Value *createSPIRVLocationLoad(IRBuilder<> &B, llvm::Module &M, + llvm::Type *Ty, unsigned Location, + StringRef Name) { + auto *GV = new llvm::GlobalVariable( + M, Ty, /* isConstant= */ true, llvm::GlobalValue::ExternalLinkage, + /* Initializer= */ nullptr, /* Name= */ Name, /* insertBefore= */ nullptr, + llvm::GlobalVariable::GeneralDynamicTLSModel, + /* AddressSpace */ 7, /* isExternallyInitialized= */ true); + GV->setVisibility(llvm::GlobalValue::HiddenVisibility); + addLocationDecoration(GV, Location); + return B.CreateLoad(Ty, GV); +} + +llvm::Value * +CGHLSLRuntime::emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index) { + Twine BaseName = Twine(Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); + + unsigned Location = SPIRVLastAssignedInputSemanticLocation; + + // DXC completely ignores the semantic/index pair. Location are assigned from + // the first semantic to the last. + llvm::ArrayType *AT = dyn_cast<llvm::ArrayType>(Type); + unsigned ElementCount = AT ? AT->getNumElements() : 1; + SPIRVLastAssignedInputSemanticLocation += ElementCount; + return createSPIRVLocationLoad(B, CGM.getModule(), Type, Location, + VariableName.str()); +} + +llvm::Value * +CGHLSLRuntime::emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index) { + Twine BaseName = Twine(Semantic->getAttrName()->getName()); + Twine VariableName = BaseName.concat(Twine(Index.value_or(0))); + + // DXIL packing rules etc shall be handled here. + // FIXME: generate proper sigpoint, index, col, row values. + // FIXME: also DXIL loads vectors element by element. + SmallVector<Value *> Args{B.getInt32(4), B.getInt32(0), B.getInt32(0), + B.getInt8(0), + llvm::PoisonValue::get(B.getInt32Ty())}; + + llvm::Intrinsic::ID IntrinsicID = llvm::Intrinsic::dx_load_input; + llvm::Value *Value = B.CreateIntrinsic(/*ReturnType=*/Type, IntrinsicID, Args, + nullptr, VariableName); + return Value; +} + +llvm::Value *CGHLSLRuntime::emitUserSemanticLoad( + IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, + HLSLSemanticAttr *Semantic, std::optional<unsigned> Index) { + if (CGM.getTarget().getTriple().isSPIRV()) + return emitSPIRVUserSemanticLoad(B, Type, Semantic, Index); + + if (CGM.getTarget().getTriple().isDXIL()) + return emitDXILUserSemanticLoad(B, Type, Semantic, Index); + + llvm_unreachable("Unsupported target for user-semantic load."); +} + llvm::Value *CGHLSLRuntime::emitSystemSemanticLoad( IRBuilder<> &B, llvm::Type *Type, const clang::DeclaratorDecl *Decl, Attr *Semantic, std::optional<unsigned> Index) { @@ -626,6 +699,9 @@ CGHLSLRuntime::handleScalarSemanticLoad(IRBuilder<> &B, const FunctionDecl *FD, std::optional<unsigned> Index = std::nullopt; if (Semantic->isSemanticIndexExplicit()) Index = Semantic->getSemanticIndex(); + + if (isa<HLSLUserSemanticAttr>(Semantic)) + return emitUserSemanticLoad(B, Type, Decl, Semantic, Index); return emitSystemSemanticLoad(B, Type, Decl, Semantic, Index); } diff --git a/clang/lib/CodeGen/CGHLSLRuntime.h b/clang/lib/CodeGen/CGHLSLRuntime.h index d35df52..9d31714 100644 --- a/clang/lib/CodeGen/CGHLSLRuntime.h +++ b/clang/lib/CodeGen/CGHLSLRuntime.h @@ -200,9 +200,25 @@ private: llvm::GlobalVariable *BufGV); void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, llvm::GlobalVariable *GV); + void initializeBufferFromBinding(const HLSLBufferDecl *BufDecl, + llvm::GlobalVariable *GV, + HLSLResourceBindingAttr *RBA); + + llvm::Value *emitSPIRVUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Value *emitDXILUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Value *emitUserSemanticLoad(llvm::IRBuilder<> &B, llvm::Type *Type, + const clang::DeclaratorDecl *Decl, + HLSLSemanticAttr *Semantic, + std::optional<unsigned> Index); + llvm::Triple::ArchType getArch(); llvm::DenseMap<const clang::RecordType *, llvm::TargetExtType *> LayoutTypes; + unsigned SPIRVLastAssignedInputSemanticLocation = 0; }; } // namespace CodeGen diff --git a/clang/lib/Sema/SemaHLSL.cpp b/clang/lib/Sema/SemaHLSL.cpp index b9707f0..a06c57b 100644 --- a/clang/lib/Sema/SemaHLSL.cpp +++ b/clang/lib/Sema/SemaHLSL.cpp @@ -775,6 +775,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info, DeclaratorDecl *TargetDecl) { std::string SemanticName = Info.Semantic->getAttrName()->getName().upper(); + if (dyn_cast<HLSLUserSemanticAttr>(Info.Semantic)) + return createSemanticAttr<HLSLUserSemanticAttr>(*Info.Semantic, TargetDecl, + Info.Index); + if (SemanticName == "SV_DISPATCHTHREADID") { return createSemanticAttr<HLSLSV_DispatchThreadIDAttr>( *Info.Semantic, TargetDecl, Info.Index); @@ -797,9 +801,10 @@ HLSLSemanticAttr *SemaHLSL::createSemantic(const SemanticInfo &Info, return nullptr; } -bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD, - DeclaratorDecl *D, - SemanticInfo &ActiveSemantic) { +bool SemaHLSL::determineActiveSemanticOnScalar( + FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics) { + if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>(); if (ActiveSemantic.Semantic && @@ -818,11 +823,31 @@ bool SemaHLSL::determineActiveSemanticOnScalar(FunctionDecl *FD, checkSemanticAnnotation(FD, D, A); FD->addAttr(A); + + unsigned Location = ActiveSemantic.Index.value_or(0); + + const ConstantArrayType *AT = dyn_cast<ConstantArrayType>(D->getType()); + unsigned ElementCount = AT ? AT->getZExtSize() : 1; + ActiveSemantic.Index = Location + ElementCount; + + Twine BaseName = Twine(ActiveSemantic.Semantic->getAttrName()->getName()); + for (unsigned I = 0; I < ElementCount; ++I) { + Twine VariableName = BaseName.concat(Twine(Location + I)); + + auto [_, Inserted] = ActiveInputSemantics.insert(VariableName.str()); + if (!Inserted) { + Diag(D->getLocation(), diag::err_hlsl_semantic_index_overlap) + << VariableName.str(); + return false; + } + } + return true; } -bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, - SemanticInfo &ActiveSemantic) { +bool SemaHLSL::determineActiveSemantic( + FunctionDecl *FD, DeclaratorDecl *D, SemanticInfo &ActiveSemantic, + llvm::StringSet<> &ActiveInputSemantics) { if (ActiveSemantic.Semantic == nullptr) { ActiveSemantic.Semantic = D->getAttr<HLSLSemanticAttr>(); if (ActiveSemantic.Semantic && @@ -833,12 +858,13 @@ bool SemaHLSL::determineActiveSemantic(FunctionDecl *FD, DeclaratorDecl *D, const Type *T = D->getType()->getUnqualifiedDesugaredType(); const RecordType *RT = dyn_cast<RecordType>(T); if (!RT) - return determineActiveSemanticOnScalar(FD, D, ActiveSemantic); + return determineActiveSemanticOnScalar(FD, D, ActiveSemantic, + ActiveInputSemantics); const RecordDecl *RD = RT->getDecl(); for (FieldDecl *Field : RD->fields()) { SemanticInfo Info = ActiveSemantic; - if (!determineActiveSemantic(FD, Field, Info)) { + if (!determineActiveSemantic(FD, Field, Info, ActiveInputSemantics)) { Diag(Field->getLocation(), diag::note_hlsl_semantic_used_here) << Field; return false; } @@ -911,12 +937,14 @@ void SemaHLSL::CheckEntryPoint(FunctionDecl *FD) { llvm_unreachable("Unhandled environment in triple"); } + llvm::StringSet<> ActiveInputSemantics; for (ParmVarDecl *Param : FD->parameters()) { SemanticInfo ActiveSemantic; ActiveSemantic.Semantic = nullptr; ActiveSemantic.Index = std::nullopt; - if (!determineActiveSemantic(FD, Param, ActiveSemantic)) { + if (!determineActiveSemantic(FD, Param, ActiveSemantic, + ActiveInputSemantics)) { Diag(Param->getLocation(), diag::note_previous_decl) << Param; FD->setInvalidDecl(); } @@ -947,6 +975,8 @@ void SemaHLSL::checkSemanticAnnotation(FunctionDecl *EntryPoint, return; DiagnoseAttrStageMismatch(SemanticAttr, ST, {llvm::Triple::Pixel}); break; + case attr::HLSLUserSemantic: + return; default: llvm_unreachable("Unknown SemanticAttr"); } @@ -1766,7 +1796,7 @@ void SemaHLSL::handleSemanticAttr(Decl *D, const ParsedAttr &AL) { if (AL.getAttrName()->getName().starts_with_insensitive("SV_")) diagnoseSystemSemanticAttr(D, AL, Index); else - Diag(AL.getLoc(), diag::err_hlsl_unknown_semantic) << AL; + D->addAttr(createSemanticAttr<HLSLUserSemanticAttr>(AL, nullptr, Index)); } void SemaHLSL::handlePackOffsetAttr(Decl *D, const ParsedAttr &AL) { diff --git a/clang/test/CIR/CodeGen/object-size-flex-array.c b/clang/test/CIR/CodeGen/object-size-flex-array.c new file mode 100644 index 0000000..74229fd --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size-flex-array.c @@ -0,0 +1,317 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR --check-prefix=CIR-NO-STRICT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -emit-llvm -disable-llvm-passes %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM --check-prefix=LLVM-NO-STRICT +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -emit-llvm -disable-llvm-passes %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG --check-prefix=OGCG-NO-STRICT + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=0 -emit-cir %s -o %t-strict-0.cir +// RUN: FileCheck --input-file=%t-strict-0.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-0 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=0 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-0.ll +// RUN: FileCheck --input-file=%t-cir-strict-0.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-0 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=0 -emit-llvm -disable-llvm-passes %s -o %t-strict-0.ll +// RUN: FileCheck --input-file=%t-strict-0.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-0 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=1 -emit-cir %s -o %t-strict-1.cir +// RUN: FileCheck --input-file=%t-strict-1.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-1 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=1 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-1.ll +// RUN: FileCheck --input-file=%t-cir-strict-1.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-1 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=1 -emit-llvm -disable-llvm-passes %s -o %t-strict-1.ll +// RUN: FileCheck --input-file=%t-strict-1.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-1 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=2 -emit-cir %s -o %t-strict-2.cir +// RUN: FileCheck --input-file=%t-strict-2.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-2 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=2 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-2.ll +// RUN: FileCheck --input-file=%t-cir-strict-2.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-2 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=2 -emit-llvm -disable-llvm-passes %s -o %t-strict-2.ll +// RUN: FileCheck --input-file=%t-strict-2.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-2 + +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=3 -emit-cir %s -o %t-strict-3.cir +// RUN: FileCheck --input-file=%t-strict-3.cir %s --check-prefix=CIR --check-prefix=CIR-STRICT-3 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fclangir -fstrict-flex-arrays=3 -emit-llvm -disable-llvm-passes %s -o %t-cir-strict-3.ll +// RUN: FileCheck --input-file=%t-cir-strict-3.ll %s --check-prefix=LLVM --check-prefix=LLVM-STRICT-3 +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -O2 -fstrict-flex-arrays=3 -emit-llvm -disable-llvm-passes %s -o %t-strict-3.ll +// RUN: FileCheck --input-file=%t-strict-3.ll %s --check-prefix=OGCG --check-prefix=OGCG-STRICT-3 + +#define OBJECT_SIZE_BUILTIN __builtin_object_size + +typedef struct { + float f; + double c[]; +} foo_t; + +typedef struct { + float f; + double c[0]; +} foo0_t; + +typedef struct { + float f; + double c[1]; +} foo1_t; + +typedef struct { + float f; + double c[2]; +} foo2_t; + +// CIR-LABEL: @bar +// LLVM-LABEL: @bar( +// OGCG-LABEL: @bar( +unsigned bar(foo_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar0 +// LLVM-LABEL: @bar0( +// OGCG-LABEL: @bar0( +unsigned bar0(foo0_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-3: ret i32 0 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar1 +// LLVM-LABEL: @bar1( +// OGCG-LABEL: @bar1( +unsigned bar1(foo1_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @bar2 +// LLVM-LABEL: @bar2( +// OGCG-LABEL: @bar2( +unsigned bar2(foo2_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 false) + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +#define DYNAMIC_OBJECT_SIZE_BUILTIN __builtin_dynamic_object_size + +// CIR-LABEL: @dyn_bar +// LLVM-LABEL: @dyn_bar( +// OGCG-LABEL: @dyn_bar( +unsigned dyn_bar(foo_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-3: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar0 +// LLVM-LABEL: @dyn_bar0( +// OGCG-LABEL: @dyn_bar0( +unsigned dyn_bar0(foo0_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-3: ret i32 0 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar1 +// LLVM-LABEL: @dyn_bar1( +// OGCG-LABEL: @dyn_bar1( +unsigned dyn_bar1(foo1_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @dyn_bar2 +// LLVM-LABEL: @dyn_bar2( +// OGCG-LABEL: @dyn_bar2( +unsigned dyn_bar2(foo2_t *f) { + // CIR-NO-STRICT: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-0: cir.objsize max nullunknown dynamic {{.*}} : !cir.ptr<!void> -> !u64i + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-0: llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 true) + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return DYNAMIC_OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// Also checks for non-trailing flex-array like members + +typedef struct { + double c[0]; + float f; +} foofoo0_t; + +typedef struct { + double c[1]; + float f; +} foofoo1_t; + +typedef struct { + double c[2]; + float f; +} foofoo2_t; + +// CIR-LABEL: @babar0 +// LLVM-LABEL: @babar0( +// OGCG-LABEL: @babar0( +unsigned babar0(foofoo0_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<0> + // CIR-STRICT-0: cir.const #cir.int<0> + // CIR-STRICT-1: cir.const #cir.int<0> + // CIR-STRICT-2: cir.const #cir.int<0> + // CIR-STRICT-3: cir.const #cir.int<0> + // LLVM-NO-STRICT: store i32 0 + // LLVM-STRICT-0: store i32 0 + // LLVM-STRICT-1: store i32 0 + // LLVM-STRICT-2: store i32 0 + // LLVM-STRICT-3: store i32 0 + // OGCG-NO-STRICT: ret i32 0 + // OGCG-STRICT-0: ret i32 0 + // OGCG-STRICT-1: ret i32 0 + // OGCG-STRICT-2: ret i32 0 + // OGCG-STRICT-3: ret i32 0 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @babar1 +// LLVM-LABEL: @babar1( +// OGCG-LABEL: @babar1( +unsigned babar1(foofoo1_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<8> + // CIR-STRICT-0: cir.const #cir.int<8> + // CIR-STRICT-1: cir.const #cir.int<8> + // CIR-STRICT-2: cir.const #cir.int<8> + // CIR-STRICT-3: cir.const #cir.int<8> + // LLVM-NO-STRICT: store i32 8 + // LLVM-STRICT-0: store i32 8 + // LLVM-STRICT-1: store i32 8 + // LLVM-STRICT-2: store i32 8 + // LLVM-STRICT-3: store i32 8 + // OGCG-NO-STRICT: ret i32 8 + // OGCG-STRICT-0: ret i32 8 + // OGCG-STRICT-1: ret i32 8 + // OGCG-STRICT-2: ret i32 8 + // OGCG-STRICT-3: ret i32 8 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} + +// CIR-LABEL: @babar2 +// LLVM-LABEL: @babar2( +// OGCG-LABEL: @babar2( +unsigned babar2(foofoo2_t *f) { + // CIR-NO-STRICT: cir.const #cir.int<16> + // CIR-STRICT-0: cir.const #cir.int<16> + // CIR-STRICT-1: cir.const #cir.int<16> + // CIR-STRICT-2: cir.const #cir.int<16> + // CIR-STRICT-3: cir.const #cir.int<16> + // LLVM-NO-STRICT: store i32 16 + // LLVM-STRICT-0: store i32 16 + // LLVM-STRICT-1: store i32 16 + // LLVM-STRICT-2: store i32 16 + // LLVM-STRICT-3: store i32 16 + // OGCG-NO-STRICT: ret i32 16 + // OGCG-STRICT-0: ret i32 16 + // OGCG-STRICT-1: ret i32 16 + // OGCG-STRICT-2: ret i32 16 + // OGCG-STRICT-3: ret i32 16 + return OBJECT_SIZE_BUILTIN(f->c, 1); +} diff --git a/clang/test/CIR/CodeGen/object-size.c b/clang/test/CIR/CodeGen/object-size.c new file mode 100644 index 0000000..1b10fb8b --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size.c @@ -0,0 +1,877 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +char gbuf[63]; +char *gp; +int gi, gj; + +// CIR-LABEL: @test1 +// LLVM-LABEL: define {{.*}} void @test1 +// OGCG-LABEL: define {{.*}} void @test1 +void test1(void) { + // CIR: cir.const #cir.int<59> + // LLVM: store i32 59 + // OGCG: store i32 59 + gi = __builtin_object_size(&gbuf[4], 1); +} + +// CIR-LABEL: @test2 +// LLVM-LABEL: define {{.*}} void @test2 +// OGCG-LABEL: define {{.*}} void @test2 +void test2(void) { + // CIR: cir.const #cir.int<63> + // LLVM: store i32 63 + // OGCG: store i32 63 + gi = __builtin_object_size(gbuf, 1); +} + +// CIR-LABEL: @test3 +// LLVM-LABEL: define {{.*}} void @test3 +// OGCG-LABEL: define {{.*}} void @test3 +void test3(void) { + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&gbuf[100], 1); +} + +// CIR-LABEL: @test4 +// LLVM-LABEL: define {{.*}} void @test4 +// OGCG-LABEL: define {{.*}} void @test4 +void test4(void) { + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)(void*)&gbuf[-1], 1); +} + +// CIR-LABEL: @test5 +// LLVM-LABEL: define {{.*}} void @test5 +// OGCG-LABEL: define {{.*}} void @test5 +void test5(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(gp, 0); +} + +// CIR-LABEL: @test6 +// LLVM-LABEL: define {{.*}} void @test6 +// OGCG-LABEL: define {{.*}} void @test6 +void test6(void) { + char buf[57]; + + // CIR: cir.const #cir.int<53> + // LLVM: store i32 53 + // OGCG: store i32 53 + gi = __builtin_object_size(&buf[4], 1); +} + +// CIR-LABEL: @test18 +// LLVM-LABEL: define {{.*}} i32 @test18 +// OGCG-LABEL: define {{.*}} i32 @test18 +unsigned test18(int cond) { + int a[4], b[4]; + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64 + // OGCG: call i64 @llvm.objectsize.i64 + return __builtin_object_size(cond ? a : b, 0); +} + +// CIR-LABEL: @test19 +// LLVM-LABEL: define {{.*}} void @test19 +// OGCG-LABEL: define {{.*}} void @test19 +void test19(void) { + struct { + int a, b; + } foo; + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&foo.a, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.a, 1); + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&foo.a, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.a, 3); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 1); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&foo.b, 3); +} + +// CIR-LABEL: @test20 +// LLVM-LABEL: define {{.*}} void @test20 +// OGCG-LABEL: define {{.*}} void @test20 +void test20(void) { + struct { int t[10]; } t[10]; + + // CIR: cir.const #cir.int<380> + // LLVM: store i32 380 + // OGCG: store i32 380 + gi = __builtin_object_size(&t[0].t[5], 0); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&t[0].t[5], 1); + + // CIR: cir.const #cir.int<380> + // LLVM: store i32 380 + // OGCG: store i32 380 + gi = __builtin_object_size(&t[0].t[5], 2); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&t[0].t[5], 3); +} + +// CIR-LABEL: @test21 +// LLVM-LABEL: define {{.*}} void @test21 +// OGCG-LABEL: define {{.*}} void @test21 +void test21(void) { + struct { int t; } t; + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t + 1, 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t.t + 1, 3); +} + +// CIR-LABEL: @test22 +// LLVM-LABEL: define {{.*}} void @test22 +// OGCG-LABEL: define {{.*}} void @test22 +void test22(void) { + struct { int t[10]; } t[10]; + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[10], 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[9].t[10], 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[0] + sizeof(t), 3); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 0); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 1); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((char*)&t[9].t[0] + 10*sizeof(t[0].t), 3); +} + +struct Test23Ty { int a; int t[10]; }; + +// CIR-LABEL: @test23 +// LLVM-LABEL: define {{.*}} void @test23 +// OGCG-LABEL: define {{.*}} void @test23 +void test23(struct Test23Ty *p) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(p, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(p, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(p, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(p, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->a, 0); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&p->a, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&p->a, 2); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&p->a, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&p->t[5], 2); + + // CIR: cir.const #cir.int<20> + // LLVM: store i32 20 + // OGCG: store i32 20 + gi = __builtin_object_size(&p->t[5], 3); +} + +// CIR-LABEL: @test24 +// LLVM-LABEL: define {{.*}} void @test24 +// OGCG-LABEL: define {{.*}} void @test24 +void test24(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size((void*)0, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((void*)0, 3); +} + +// CIR-LABEL: @test25 +// LLVM-LABEL: define {{.*}} void @test25 +// OGCG-LABEL: define {{.*}} void @test25 +void test25(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size((void*)0x1000, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size((void*)0x1000, 3); + + // Skipping (void*)0 + 0x1000 tests - void pointer arithmetic NYI in CIR +} + +// CIR-LABEL: @test26 +// LLVM-LABEL: define {{.*}} void @test26 +// OGCG-LABEL: define {{.*}} void @test26 +void test26(void) { + struct { int v[10]; } t[10]; + + // CIR: cir.const #cir.int<316> + // LLVM: store i32 316 + // OGCG: store i32 316 + gi = __builtin_object_size(&t[1].v[11], 0); + + // CIR: cir.const #cir.int<312> + // LLVM: store i32 312 + // OGCG: store i32 312 + gi = __builtin_object_size(&t[1].v[12], 1); + + // CIR: cir.const #cir.int<308> + // LLVM: store i32 308 + // OGCG: store i32 308 + gi = __builtin_object_size(&t[1].v[13], 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&t[1].v[14], 3); +} + +struct Test27IncompleteTy; + +// CIR-LABEL: @test27 +// LLVM-LABEL: define {{.*}} void @test27 +// OGCG-LABEL: define {{.*}} void @test27 +void test27(struct Test27IncompleteTy *t) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(t, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(t, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(t, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(t, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&test27, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(&test27, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr {{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(&test27, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(&test27, 3); +} + +// CIR-LABEL: @test28 +// LLVM-LABEL: define {{.*}} void @test28 +// OGCG-LABEL: define {{.*}} void @test28 +void test28(void) { + struct { int v[10]; } t[10]; + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 0); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 1); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 2); + + // CIR: cir.const #cir.int<360> + // LLVM: store i32 360 + // OGCG: store i32 360 + gi = __builtin_object_size((char*)((short*)(&t[1])), 3); + + // CIR: cir.const #cir.int<356> + // LLVM: store i32 356 + // OGCG: store i32 356 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 0); + + // CIR: cir.const #cir.int<36> + // LLVM: store i32 36 + // OGCG: store i32 36 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 1); + + // CIR: cir.const #cir.int<356> + // LLVM: store i32 356 + // OGCG: store i32 356 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 2); + + // CIR: cir.const #cir.int<36> + // LLVM: store i32 36 + // OGCG: store i32 36 + gi = __builtin_object_size((char*)((short*)(&t[1].v[1])), 3); +} + +struct DynStructVar { + char fst[16]; + char snd[]; +}; + +struct DynStruct0 { + char fst[16]; + char snd[0]; +}; + +struct DynStruct1 { + char fst[16]; + char snd[1]; +}; + +struct StaticStruct { + char fst[16]; + char snd[2]; +}; + +// CIR-LABEL: @test29 +// LLVM-LABEL: define {{.*}} void @test29 +// OGCG-LABEL: define {{.*}} void @test29 +void test29(struct DynStructVar *dv, struct DynStruct0 *d0, + struct DynStruct1 *d1, struct StaticStruct *ss) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(dv->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(dv->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(dv->snd, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(dv->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d0->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d0->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(d0->snd, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(d0->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d1->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(d1->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(d1->snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(d1->snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(ss->snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(ss->snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(ss->snd, 2); + + // CIR: cir.const #cir.int<2> + // LLVM: store i32 2 + // OGCG: store i32 2 + gi = __builtin_object_size(ss->snd, 3); +} + +// CIR-LABEL: @test30 +// LLVM-LABEL: define {{.*}} void @test30 +// OGCG-LABEL: define {{.*}} void @test30 +void test30(void) { + struct { struct DynStruct1 fst, snd; } *nested; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->fst.snd, 0); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->fst.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(nested->fst.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->fst.snd, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(nested->snd.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(nested->snd.snd, 3); + + union { struct DynStruct1 d1; char c[1]; } *u; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->c, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->c, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(u->c, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(u->c, 3); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(u->d1.snd, 2); + + // CIR: cir.const #cir.int<1> + // LLVM: store i32 1 + // OGCG: store i32 1 + gi = __builtin_object_size(u->d1.snd, 3); +} + +// CIR-LABEL: @test32 +// LLVM-LABEL: define {{.*}} i64 @test32 +// OGCG-LABEL: define {{.*}} i64 @test32 +static struct DynStructVar D32 = { + .fst = {}, + .snd = { 0, 1, 2, }, +}; +unsigned long test32(void) { + // CIR: cir.const #cir.int<19> + // LLVM: store i64 19 + // OGCG: ret i64 19 + return __builtin_object_size(&D32, 1); +} + +// CIR-LABEL: @test33 +// LLVM-LABEL: define {{.*}} i64 @test33 +// OGCG-LABEL: define {{.*}} i64 @test33 +static struct DynStructVar D33 = { + .fst = {}, + .snd = {}, +}; +unsigned long test33(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&D33, 1); +} + +// CIR-LABEL: @test34 +// LLVM-LABEL: define {{.*}} i64 @test34 +// OGCG-LABEL: define {{.*}} i64 @test34 +static struct DynStructVar D34 = { + .fst = {}, +}; +unsigned long test34(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&D34, 1); +} + +// CIR-LABEL: @test35 +// LLVM-LABEL: define {{.*}} i64 @test35 +// OGCG-LABEL: define {{.*}} i64 @test35 +unsigned long test35(void) { + // CIR: cir.const #cir.int<16> + // LLVM: store i64 16 + // OGCG: ret i64 16 + return __builtin_object_size(&(struct DynStructVar){}, 1); +} + +// CIR-LABEL: @test37 +// LLVM-LABEL: define {{.*}} i64 @test37 +// OGCG-LABEL: define {{.*}} i64 @test37 +struct Z { struct A { int x, y[]; } z; int a; int b[]; }; +static struct Z my_z = { .b = {1,2,3} }; +unsigned long test37(void) { + // CIR: cir.const #cir.int<4> + // LLVM: store i64 4 + // OGCG: ret i64 4 + return __builtin_object_size(&my_z.z, 1); +} + +// CIR-LABEL: @PR30346 +// LLVM-LABEL: define {{.*}} void @PR30346 +// OGCG-LABEL: define {{.*}} void @PR30346 +void PR30346(void) { + struct sa_family_t {}; + struct sockaddr { + struct sa_family_t sa_family; + char sa_data[14]; + }; + + struct sockaddr *sa; + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 + gi = __builtin_object_size(sa->sa_data, 2); + + // CIR: cir.const #cir.int<14> + // LLVM: store i32 14 + // OGCG: store i32 14 + gi = __builtin_object_size(sa->sa_data, 3); +} + +extern char incomplete_char_array[]; + +// CIR-LABEL: @incomplete_and_function_types +// LLVM-LABEL: define {{.*}} void @incomplete_and_function_types +// OGCG-LABEL: define {{.*}} void @incomplete_and_function_types +void incomplete_and_function_types(void) { + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 0); + + // CIR: cir.objsize max nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 1); + + // CIR: cir.objsize min nullunknown {{.*}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0 + // OGCG: call i64 @llvm.objectsize.i64.p0 + gi = __builtin_object_size(incomplete_char_array, 2); + + // CIR: cir.const #cir.int<0> + // LLVM: store i32 0 + // OGCG: store i32 0 + gi = __builtin_object_size(incomplete_char_array, 3); +} + +// CIR-LABEL: @deeply_nested +// LLVM-LABEL: define {{.*}} void @deeply_nested +// OGCG-LABEL: define {{.*}} void @deeply_nested +void deeply_nested(void) { + struct { + struct { + struct { + struct { + int e[2]; + char f; + } d[2]; + } c[2]; + } b[2]; + } *a; + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 1); + + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size(&a->b[1].c[1].d[1].e[1], 3); +} diff --git a/clang/test/CIR/CodeGen/object-size.cpp b/clang/test/CIR/CodeGen/object-size.cpp new file mode 100644 index 0000000..b60e245 --- /dev/null +++ b/clang/test/CIR/CodeGen/object-size.cpp @@ -0,0 +1,108 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-cir %s -o %t.cir +// RUN: FileCheck --input-file=%t.cir %s --check-prefix=CIR +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -fclangir -emit-llvm %s -o %t-cir.ll +// RUN: FileCheck --input-file=%t-cir.ll %s --check-prefix=LLVM +// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -emit-llvm %s -o %t.ll +// RUN: FileCheck --input-file=%t.ll %s --check-prefix=OGCG + +// C++-specific tests for __builtin_object_size + +int gi; + +// CIR-LABEL: @_Z5test1v +// LLVM-LABEL: define{{.*}} void @_Z5test1v() +// OGCG-LABEL: define{{.*}} void @_Z5test1v() +void test1() { + // Guaranteeing that our cast removal logic doesn't break more interesting + // cases. + struct A { int a; }; + struct B { int b; }; + struct C: public A, public B {}; + + C c; + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size(&c, 0); + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((A*)&c, 0); + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size((B*)&c, 0); + + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((char*)&c, 0); + // CIR: cir.const #cir.int<8> + // LLVM: store i32 8 + // OGCG: store i32 8 + gi = __builtin_object_size((char*)(A*)&c, 0); + // CIR: cir.const #cir.int<4> + // LLVM: store i32 4 + // OGCG: store i32 4 + gi = __builtin_object_size((char*)(B*)&c, 0); +} + +// CIR-LABEL: @_Z5test2v() +// LLVM-LABEL: define{{.*}} void @_Z5test2v() +// OGCG-LABEL: define{{.*}} void @_Z5test2v() +void test2() { + struct A { char buf[16]; }; + struct B : A {}; + struct C { int i; B bs[1]; } *c; + + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 0); + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 1); + // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0], 2); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0], 3); + + // NYI: DerivedToBase cast + // gi = __builtin_object_size((A*)&c->bs[0], 0); + + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size((A*)&c->bs[0], 1); + + // NYI: DerivedToBase cast + // gi = __builtin_object_size((A*)&c->bs[0], 2); + + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size((A*)&c->bs[0], 3); + + // CIR: cir.objsize max nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 false, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0].buf[0], 0); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0].buf[0], 1); + // CIR: cir.objsize min nullunknown %{{.+}} : !cir.ptr<!void> -> !u64i + // LLVM: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + // OGCG: call i64 @llvm.objectsize.i64.p0(ptr %{{.*}}, i1 true, i1 true, i1 false) + gi = __builtin_object_size(&c->bs[0].buf[0], 2); + // CIR: cir.const #cir.int<16> + // LLVM: store i32 16 + // OGCG: store i32 16 + gi = __builtin_object_size(&c->bs[0].buf[0], 3); +} diff --git a/clang/test/CIR/IR/objsize.cir b/clang/test/CIR/IR/objsize.cir new file mode 100644 index 0000000..bc24551 --- /dev/null +++ b/clang/test/CIR/IR/objsize.cir @@ -0,0 +1,89 @@ +// Test the cir.objsize operation can parse and print correctly (roundtrip) +// with all possible combinations of optional attributes + +// RUN: cir-opt %s --verify-roundtrip | FileCheck %s + +!u64i = !cir.int<u, 64> +!void = !cir.void + +module { + cir.func @test_max(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize max %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_max_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize max nullunknown %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_max_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize max dynamic %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_max_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize max nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_min(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize min %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_min_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize min nullunknown %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_min_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize min dynamic %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } + + cir.func @test_min_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { + %0 = cir.objsize min nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i + cir.return %0 : !u64i + } +} + +// CHECK: cir.func @test_max(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize max %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_max_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize max nullunknown %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_max_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize max dynamic %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_max_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize max nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_min(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize min %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_min_nullunknown(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize min nullunknown %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_min_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize min dynamic %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } + +// CHECK: cir.func @test_min_nullunknown_dynamic(%arg0: !cir.ptr<!void>) -> !u64i { +// CHECK: %0 = cir.objsize min nullunknown dynamic %arg0 : !cir.ptr<!void> -> !u64i +// CHECK: cir.return %0 : !u64i +// CHECK: } diff --git a/clang/test/ClangScanDeps/strip-codegen-args.m b/clang/test/ClangScanDeps/strip-codegen-args.m index 71171f4..f2cec62 100644 --- a/clang/test/ClangScanDeps/strip-codegen-args.m +++ b/clang/test/ClangScanDeps/strip-codegen-args.m @@ -16,6 +16,7 @@ // CHECK-NOT: "-flto" // CHECK-NOT: "-fno-autolink" // CHECK-NOT: "-mrelax-relocations=no" +// CHECK-NOT: "-mspeculative-load-hardening" // CHECK: ] // CHECK: "name": "A" // CHECK: } @@ -39,6 +40,11 @@ "command": "clang -Imodules/A -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -O2 -flto=full -fsyntax-only DIR/t3.m", "file": "DIR/t2.m" } + { + "directory": "DIR", + "command": "clang -Imodules/A -fmodules -fmodules-cache-path=DIR/module-cache -fimplicit-modules -O2 -mspeculative-load-hardening -fsyntax-only DIR/t3.m", + "file": "DIR/t3.m" + } ] //--- modules/A/module.modulemap diff --git a/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl index 7aeb877..b0abaed 100644 --- a/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl +++ b/clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl @@ -24,4 +24,3 @@ void foo(uint Idx : SV_DispatchThreadID) {} [shader("compute")] [numthreads(8,8,1)] void bar(uint2 Idx : SV_DispatchThreadID) {} - diff --git a/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl new file mode 100644 index 0000000..96d5b99 --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl @@ -0,0 +1,36 @@ +// RUN: %clang_cc1 -triple spirv-unknown-vulkan-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-vertex -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx + +// CHECK-SPIRV-DAG: @AAA0 = external hidden thread_local addrspace(7) externally_initialized constant float, !spirv.Decorations ![[#METADATA_0:]] +// CHECK-SPIRV-DAG: @B0 = external hidden thread_local addrspace(7) externally_initialized constant i32, !spirv.Decorations ![[#METADATA_2:]] +// CHECK-SPIRV-DAG: @CC0 = external hidden thread_local addrspace(7) externally_initialized constant <2 x float>, !spirv.Decorations ![[#METADATA_4:]] + + +// FIXME: replace `float2 c` with a matrix when available. +void main(float a : AAA, int b : B, float2 c : CC) { + float tmp = a + b + c.x + c.y; +} +// CHECK-SPIRV: define internal spir_func void @_Z4mainfiDv2_f(float noundef nofpclass(nan inf) %a, i32 noundef %b, <2 x float> noundef nofpclass(nan inf) %c) #0 { + +// CHECK: define void @main() + +// CHECK-DXIL: %AAA0 = call float @llvm.dx.load.input.f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: %B0 = call i32 @llvm.dx.load.input.i32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL %CC0 = call <2 x float> @llvm.dx.load.input.v2f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: call void @_Z4mainfiDv2_f(float %AAA0, i32 %B0, <2 x float> %CC0) + +// CHECK-SPIRV: %[[#AAA0:]] = load float, ptr addrspace(7) @AAA0, align 4 +// CHECK-SPIRV: %[[#B0:]] = load i32, ptr addrspace(7) @B0, align 4 +// CHECK-SPIRV: %[[#CC0:]] = load <2 x float>, ptr addrspace(7) @CC0, align 8 +// CHECK-SPIRV: call spir_func void @_Z4mainfiDv2_f(float %[[#AAA0]], i32 %[[#B0]], <2 x float> %[[#CC0]]) [ "convergencectrl"(token %0) ] + + +// CHECK-SPIRV-DAG: ![[#METADATA_0]] = !{![[#METADATA_1:]]} +// CHECK-SPIRV-DAG: ![[#METADATA_2]] = !{![[#METADATA_3:]]} +// CHECK-SPIRV-DAG: ![[#METADATA_4]] = !{![[#METADATA_5:]]} + +// CHECK-SPIRV-DAG: ![[#METADATA_1]] = !{i32 30, i32 0} +// CHECK-SPIRV-DAG: ![[#METADATA_3]] = !{i32 30, i32 1} +// CHECK-SPIRV-DAG: ![[#METADATA_5]] = !{i32 30, i32 2} +// | `- Location index +// `-> Decoration "Location" diff --git a/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl new file mode 100644 index 0000000..b2cb3da --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.array.hlsl @@ -0,0 +1,37 @@ +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv +// RUN: %clang_cc1 -triple dxil-px-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx + +struct S0 { + float4 position[2]; + float4 color; +}; + +// CHECK: %struct.S0 = type { [2 x <4 x float>], <4 x float> } + +// CHECK-SPIRV: @A0 = external hidden thread_local addrspace(7) externally_initialized constant [2 x <4 x float>], !spirv.Decorations ![[#MD_0:]] +// CHECK-SPIRV: @A2 = external hidden thread_local addrspace(7) externally_initialized constant <4 x float>, !spirv.Decorations ![[#MD_2:]] + +// CHECK: define void @main0() +// CHECK-DXIL: %A0 = call [2 x <4 x float>] @llvm.dx.load.input.a2v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %A0, 0 +// CHECK-DXIL: %A2 = call <4 x float> @llvm.dx.load.input.v4f32(i32 4, i32 0, i32 0, i8 0, i32 poison) +// CHECK-DXIL: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %A2, 1 + +// CHECK-SPIRV: %[[#A0:]] = load [2 x <4 x float>], ptr addrspace(7) @A0, align 16 +// CHECK-SPIRV: %[[#TMP0:]] = insertvalue %struct.S0 poison, [2 x <4 x float>] %[[#A0]], 0 +// CHECK-SPIRV: %[[#A2:]] = load <4 x float>, ptr addrspace(7) @A2, align 16 +// CHECK-SPIRV: %[[#TMP1:]] = insertvalue %struct.S0 %[[#TMP0]], <4 x float> %[[#A2]], 1 + +// CHECK: %[[#ARG:]] = alloca %struct.S0, align 16 +// CHECK: store %struct.S0 %[[#TMP1]], ptr %[[#ARG]], align 16 +// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +[shader("pixel")] +void main0(S0 p : A) { + float tmp = p.position[0] + p.position[1] + p.color; +} + +// CHECK-SPIRV: ![[#MD_0]] = !{![[#MD_1:]]} +// CHECK-SPIRV: ![[#MD_1]] = !{i32 30, i32 0} +// CHECK-SPIRV: ![[#MD_2]] = !{![[#MD_3:]]} +// CHECK-SPIRV: ![[#MD_3]] = !{i32 30, i32 2} diff --git a/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl new file mode 100644 index 0000000..733cf3a --- /dev/null +++ b/clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl @@ -0,0 +1,77 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.3-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-DXIL -DTARGET=dx +// RUN: %clang_cc1 -triple spirv-linux-vulkan-library -x hlsl -emit-llvm -finclude-default-header -disable-llvm-passes -o - %s | FileCheck %s --check-prefixes=CHECK,CHECK-SPIRV -DTARGET=spv + +struct S0 { + uint Idx : SV_DispatchThreadID; +}; + +// CHECK: define void @main0() +// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0) +// CHECK: %[[#TMP:]] = insertvalue %struct.S0 poison, i32 %[[#ID:]], 0 +// CHECK: %[[#ARG:]] = alloca %struct.S0, align 8 +// CHECK: store %struct.S0 %[[#TMP]], ptr %[[#ARG]], align 4 +// CHECK-DXIL: call void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main0{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main0(S0 p) {} + +struct S1 { + uint2 a : SV_DispatchThreadID; + uint2 b : SV_GroupThreadID; +}; + +// CHECK: define void @main1() +// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0) +// CHECK: %[[#AX_:]] = insertelement <2 x i32> poison, i32 %[[#ID]], i64 0 +// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 1) +// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 1) +// CHECK: %[[#AXY:]] = insertelement <2 x i32> %[[#AX_]], i32 %[[#ID]], i64 1 +// CHECK: %[[#S1A_:]] = insertvalue %struct.S1 poison, <2 x i32> %[[#AXY]], 0 +// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK: %[[#S1AB:]] = insertvalue %struct.S1 %[[#S1A_]], <2 x i32> %[[#ID_XYZ:]], 1 +// CHECK: %[[#ARG:]] = alloca %struct.S1, align 8 +// CHECK: store %struct.S1 %[[#S1AB]], ptr %[[#ARG]], align 8 +// CHECK-DXIL: call void @{{.*}}main1{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main1{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main1(S1 p) {} + +struct S2C { + uint2 b : SV_GroupThreadID; +}; + +struct S2 { + uint a : SV_DispatchThreadID; + S2C child; +}; + +// CHECK: define void @main2() +// CHECK-DXIL: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id(i32 0) +// CHECK-SPIRV: %[[#ID:]] = call i32 @llvm.[[TARGET]].thread.id.i32(i32 0) +// CHECK: %[[#S2A_:]] = insertvalue %struct.S2 poison, i32 %[[#ID:]], 0 + +// CHECK-DXIL: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 0) +// CHECK-SPIRV: %[[#ID_X:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 0) +// CHECK: %[[#ID_X_:]] = insertelement <2 x i32> poison, i32 %[[#ID_X]], i64 0 +// CHECK-DXIL: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group(i32 1) +// CHECK-SPIRV: %[[#ID_Y:]] = call i32 @llvm.[[TARGET]].thread.id.in.group.i32(i32 1) +// CHECK: %[[#ID_XY:]] = insertelement <2 x i32> %[[#ID_X_]], i32 %[[#ID_Y]], i64 1 +// CHECK: %[[#S2C:]] = insertvalue %struct.S2C poison, <2 x i32> %[[#ID_XY:]], 0 + +// CHECK: %[[#S2AB:]] = insertvalue %struct.S2 %[[#S2A_]], %struct.S2C %[[#S2V:]], 1 +// CHECK: %[[#ARG:]] = alloca %struct.S2, align 8 +// CHECK: store %struct.S2 %[[#S2AB]], ptr %[[#ARG]], align 1 +// CHECK-DXIL: call void @{{.*}}main2{{.*}}(ptr %[[#ARG]]) +// CHECK-SPIRV: call spir_func void @{{.*}}main2{{.*}}(ptr %[[#ARG]]) +[shader("compute")] +[numthreads(8,8,1)] +void main2(S2 p) {} diff --git a/clang/test/ParserHLSL/semantic_parsing.hlsl b/clang/test/ParserHLSL/semantic_parsing.hlsl index 726dead..bff7bd0 100644 --- a/clang/test/ParserHLSL/semantic_parsing.hlsl +++ b/clang/test/ParserHLSL/semantic_parsing.hlsl @@ -12,30 +12,33 @@ void Pony(int GI : SV_IWantAPony) { } // expected-note@+1 {{to match this '('}} void SuperPony(int GI : 0) { } -// expected-error@+1 {{unknown HLSL semantic '_'}} +// '_' is a valid CPP identifier. void MegaPony(int GI : _) { } -// expected-error@+1 {{unknown HLSL semantic 'A0A'}} +void GarguantuanPony(int GI : _1) { } + void CoolPony(int GI : A0A0) { } -// expected-error@+1 {{unknown HLSL semantic 'A_'}} void NicePony(int GI : A_0) { } -// expected-error@+1 {{unknown HLSL semantic 'A'}} void CutePony(int GI : A00) { } -// expected-error@+3 {{unknown HLSL semantic 'A'}} // expected-error@+2 {{expected ')'}} // expected-note@+1 {{to match this '('}} void DoublePony(int GI : A00 B) { } -// expected-error@+1 {{unknown HLSL semantic 'é'}} -void BigPony(int GI : é) { } +// Unicode can be used: +// https://timsong-cpp.github.io/cppwp/n3337/charname.allowed +void FrenchPony(int GI : garçon_de_café) { } +void UnicodePony(int GI : ℮) { } + +// Since P1949 seems Emojis are not allowed, even if in the range +// mentioned in N3337. +// https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2021/p1949r7.html // expected-error@+2 {{unexpected character <U+1F60A>}} // expected-error@+1 {{expected HLSL Semantic identifier}} void UTFPony(int GI : 😊) { } -// expected-error@+2 {{character <U+1F60A> not allowed in an identifier}} -// expected-error@+1 {{unknown HLSL semantic 'PonyWithA😊'}} +// expected-error@+1 {{character <U+1F60A> not allowed in an identifier}} void SmilingPony(int GI : PonyWithA😊) { } diff --git a/clang/test/SemaCXX/dependent-switch-case.cpp b/clang/test/SemaCXX/dependent-switch-case.cpp new file mode 100644 index 0000000..bbeab3a --- /dev/null +++ b/clang/test/SemaCXX/dependent-switch-case.cpp @@ -0,0 +1,6 @@ +// RUN: %clang_cc1 -std=c++20 %s -verify +// RUN: %clang_cc1 -std=c++20 %s -verify -fexperimental-new-constant-interpreter + +constexpr bool e(int){switch(0)0=0:return t(;} // expected-error {{expression is not assignable}} \ + // expected-error {{expected 'case' keyword before expression}} \ + // expected-error {{expected expression}} diff --git a/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl b/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl new file mode 100644 index 0000000..fdba6f6 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl @@ -0,0 +1,17 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -x hlsl -fsyntax-only -hlsl-entry main -verify %s + +typedef float t_f : SEMANTIC; // expected-warning{{'SEMANTIC' attribute only applies to parameters, non-static data members, and functions}} + +struct semantic_on_struct : SEMANTIC { // expected-error{{expected class name}} + float a; +}; + +struct s_fields_multiple_semantics { + float a : semantic_a : semantic_c; // expected-error{{use of undeclared identifier 'semantic_c'}} + float b : semantic_b; +}; + +[numthreads(1, 1, 1)] +void main() { + float a : SEM_A; // expected-warning{{'SEM_A' attribute only applies to parameters, non-static data members, and functions}} +} diff --git a/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl new file mode 100644 index 0000000..1e6bae4 --- /dev/null +++ b/clang/test/SemaHLSL/Semantics/semantics-valid.hlsl @@ -0,0 +1,33 @@ +// RUN: %clang_cc1 -triple dxil-pc-shadermodel6.0-compute -hlsl-entry CSMain -x hlsl -finclude-default-header -ast-dump -o - %s | FileCheck %s + +struct s_fields { + float a : semantic_a; + float b : semantic_b; +// CHECK: |-CXXRecordDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> line:[[@LINE-3]]:8 struct s_fields definition +// CHECK: | |-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 a 'float' +// CHECK: | | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} <col:13> +// CHECK: | `-FieldDecl 0x{{[0-9a-fA-F]+}} <{{.*}}> col:9 b 'float' +// CHECK: | `-HLSLUserSemanticAttr 0x{{[0-9a-fA-F]+}} <col:13> +}; + +float fn_foo1(float a : a, float b : b) : sem_ret { return 1.0f; } +// CHECK: |-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo1 'float (float, float)' +// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' +// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK-NEXT: | |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' +// CHECK-NEXT: | | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK-NEXT: | |-CompoundStmt {{.*}} <{{.*}}> +// CHECK-NEXT: | | `-ReturnStmt {{.*}} <{{.*}}> +// CHECK-NEXT: | | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 +// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +float fn_foo2(float a : a, float b : b) : sem_ret : also_ret { return 1.0f; } +// CHECK: `-FunctionDecl {{.*}} <{{.*}}> col:7 fn_foo2 'float (float, float)' +// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:21 a 'float' +// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK-NEXT: |-ParmVarDecl {{.*}} <{{.*}}> col:34 b 'float' +// CHECK-NEXT: | `-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK-NEXT: |-CompoundStmt {{.*}} <{{.*}}> +// CHECK-NEXT: | `-ReturnStmt {{.*}} <{{.*}}> +// CHECK-NEXT: | `-FloatingLiteral {{.*}} <{{.*}}> 'float' 1.000000e+00 +// CHECK-NEXT: |-HLSLUserSemanticAttr {{.*}} <{{.*}}> +// CHECK-NEXT: `-HLSLUserSemanticAttr {{.*}} <{{.*}}> diff --git a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp index 9692d6e..3fcb558 100644 --- a/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp +++ b/clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp @@ -1179,6 +1179,12 @@ TEST_P(ASTMatchersTest, PredefinedExpr) { has(stringLiteral())))); } +TEST_P(ASTMatchersTest, FileScopeAsmDecl) { + EXPECT_TRUE(matches("__asm(\"nop\");", fileScopeAsmDecl())); + EXPECT_TRUE( + notMatches("void f() { __asm(\"mov al, 2\"); }", fileScopeAsmDecl())); +} + TEST_P(ASTMatchersTest, AsmStatement) { EXPECT_TRUE(matches("void foo() { __asm(\"mov al, 2\"); }", asmStmt())); } @@ -2442,7 +2448,8 @@ TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureOfReferenceType) { "int main() {" " int a;" " f(a);" - "}", matcher)); + "}", + matcher)); EXPECT_FALSE(matches("template <class ...T> void f(T &...args) {" " [...args = args] () mutable {" " }();" @@ -2450,7 +2457,8 @@ TEST_P(ASTMatchersTest, LambdaCaptureTest_BindsToCaptureOfReferenceType) { "int main() {" " int a;" " f(a);" - "}", matcher)); + "}", + matcher)); } TEST_P(ASTMatchersTest, IsDerivedFromRecursion) { @@ -2628,7 +2636,7 @@ TEST(ASTMatchersTestObjC, ObjCStringLiteral) { " [Test someFunction:@\"Ola!\"]; " "}\n" "@end "; - EXPECT_TRUE(matchesObjC(Objc1String, objcStringLiteral())); + EXPECT_TRUE(matchesObjC(Objc1String, objcStringLiteral())); } TEST(ASTMatchersTestObjC, ObjCDecls) { diff --git a/clang/unittests/Support/TimeProfilerTest.cpp b/clang/unittests/Support/TimeProfilerTest.cpp index e544c89..3b18aa83 100644 --- a/clang/unittests/Support/TimeProfilerTest.cpp +++ b/clang/unittests/Support/TimeProfilerTest.cpp @@ -186,7 +186,8 @@ std::string buildTraceGraph(StringRef Json) { } // namespace -TEST(TimeProfilerTest, ConstantEvaluationCxx20) { +// FIXME: Flaky test. See https://github.com/llvm/llvm-project/pull/138613 +TEST(TimeProfilerTest, DISABLED_ConstantEvaluationCxx20) { std::string Code = R"( void print(double value); |
