aboutsummaryrefslogtreecommitdiff
path: root/clang
diff options
context:
space:
mode:
Diffstat (limited to 'clang')
-rw-r--r--clang/docs/LibASTMatchersReference.html14
-rw-r--r--clang/include/clang/ASTMatchers/ASTMatchers.h15
-rw-r--r--clang/include/clang/Basic/Attr.td4
-rw-r--r--clang/include/clang/Basic/DiagnosticSemaKinds.td1
-rw-r--r--clang/include/clang/Basic/LangOptions.def2
-rw-r--r--clang/include/clang/CIR/Dialect/IR/CIROps.td51
-rw-r--r--clang/include/clang/CIR/MissingFeatures.h1
-rw-r--r--clang/include/clang/Sema/SemaHLSL.h8
-rw-r--r--clang/lib/AST/ByteCode/Compiler.cpp2
-rw-r--r--clang/lib/AST/ExprConstant.cpp11
-rw-r--r--clang/lib/ASTMatchers/ASTMatchersInternal.cpp2
-rw-r--r--clang/lib/ASTMatchers/Dynamic/Registry.cpp1
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp52
-rw-r--r--clang/lib/CIR/CodeGen/CIRGenFunction.h22
-rw-r--r--clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp23
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.cpp76
-rw-r--r--clang/lib/CodeGen/CGHLSLRuntime.h16
-rw-r--r--clang/lib/Sema/SemaHLSL.cpp48
-rw-r--r--clang/test/CIR/CodeGen/object-size-flex-array.c317
-rw-r--r--clang/test/CIR/CodeGen/object-size.c877
-rw-r--r--clang/test/CIR/CodeGen/object-size.cpp108
-rw-r--r--clang/test/CIR/IR/objsize.cir89
-rw-r--r--clang/test/ClangScanDeps/strip-codegen-args.m6
-rw-r--r--clang/test/CodeGenHLSL/semantics/DispatchThreadID.hlsl1
-rw-r--r--clang/test/CodeGenHLSL/semantics/semantic.arbitrary.hlsl36
-rw-r--r--clang/test/CodeGenHLSL/semantics/semantic.array.hlsl37
-rw-r--r--clang/test/CodeGenHLSL/semantics/semantic.struct.hlsl77
-rw-r--r--clang/test/ParserHLSL/semantic_parsing.hlsl21
-rw-r--r--clang/test/SemaCXX/dependent-switch-case.cpp6
-rw-r--r--clang/test/SemaHLSL/Semantics/semantics-invalid.hlsl17
-rw-r--r--clang/test/SemaHLSL/Semantics/semantics-valid.hlsl33
-rw-r--r--clang/unittests/ASTMatchers/ASTMatchersNodeTest.cpp14
-rw-r--r--clang/unittests/Support/TimeProfilerTest.cpp3
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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('fileScopeAsmDecl0')"><a name="fileScopeAsmDecl0Anchor">fileScopeAsmDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FileScopeAsmDecl.html">FileScopeAsmDecl</a>&gt;...</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&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1Decl.html">Decl</a>&gt;</td><td class="name" onclick="toggle('friendDecl0')"><a name="friendDecl0Anchor">friendDecl</a></td><td>Matcher&lt;<a href="https://clang.llvm.org/doxygen/classclang_1_1FriendDecl.html">FriendDecl</a>&gt;...</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);