Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 9 additions & 11 deletions clang/include/clang/StaticAnalyzer/Core/PathSensitive/SMTConv.h
Original file line number Diff line number Diff line change
Expand Up @@ -456,17 +456,15 @@ class SMTConv {
llvm::SMTExprRef OperandExp =
getSymExpr(Solver, Ctx, USE->getOperand(), &OperandTy, hasComparison);

if (const BinarySymExpr *BSE =
dyn_cast<BinarySymExpr>(USE->getOperand())) {
if (USE->getOpcode() == UO_Minus &&
BinaryOperator::isComparisonOp(BSE->getOpcode()))
// The comparison operator yields a boolean value in the Z3
// language and applying the unary minus operator on a boolean
// crashes Z3. However, the unary minus does nothing in this
// context (a number is truthy if and only if its negative is
// truthy), so let's just ignore the unary minus.
// TODO: Replace this with a more general solution.
return OperandExp;
// When the operand is a bool expr, but the operator is an integeral
// operator, casting the bool expr to the integer before creating the
// unary operator.
// E.g. -(5 && a)
if (OperandTy == Ctx.BoolTy && OperandTy != *RetTy &&
(*RetTy)->isIntegerType()) {
OperandExp = fromCast(Solver, OperandExp, (*RetTy),
Ctx.getTypeSize(*RetTy), OperandTy, 1);
OperandTy = (*RetTy);
}

llvm::SMTExprRef UnaryExp =
Expand Down
29 changes: 29 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,35 @@ class CIRGenBuilderTy : public cir::CIRBaseBuilderTy {
info.isSigned, isLvalueVolatile,
addr.getAlignment().getAsAlign().value());
}

cir::VecShuffleOp
createVecShuffle(mlir::Location loc, mlir::Value vec1, mlir::Value vec2,
llvm::ArrayRef<mlir::Attribute> maskAttrs) {
auto vecType = mlir::cast<cir::VectorType>(vec1.getType());
auto resultTy = cir::VectorType::get(getContext(), vecType.getElementType(),
maskAttrs.size());
return cir::VecShuffleOp::create(*this, loc, resultTy, vec1, vec2,
getArrayAttr(maskAttrs));
}

cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
mlir::Value vec2,
llvm::ArrayRef<int64_t> mask) {
auto maskAttrs = llvm::to_vector_of<mlir::Attribute>(
llvm::map_range(mask, [&](int32_t idx) {
return cir::IntAttr::get(getSInt32Ty(), idx);
}));
return createVecShuffle(loc, vec1, vec2, maskAttrs);
}

cir::VecShuffleOp createVecShuffle(mlir::Location loc, mlir::Value vec1,
llvm::ArrayRef<int64_t> mask) {
/// Create a unary shuffle. The second vector operand of the IR instruction
/// is poison.
cir::ConstantOp poison =
getConstant(loc, cir::PoisonAttr::get(vec1.getType()));
return createVecShuffle(loc, vec1, poison, mask);
}
};

} // namespace clang::CIRGen
Expand Down
15 changes: 12 additions & 3 deletions clang/lib/CIR/CodeGen/CIRGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -669,9 +669,18 @@ RValue CIRGenFunction::emitLoadOfExtVectorElementLValue(LValue lv) {
return RValue::get(cir::VecExtractOp::create(builder, loc, vec, index));
}

cgm.errorNYI(
loc, "emitLoadOfExtVectorElementLValue: Result of expr is vector type");
return {};
// Always use shuffle vector to try to retain the original program structure
SmallVector<int64_t> mask;
for (auto i : llvm::seq<unsigned>(0, exprVecTy->getNumElements()))
mask.push_back(getAccessedFieldNo(i, elts));

cir::VecShuffleOp resultVec = builder.createVecShuffle(loc, vec, mask);
if (lv.getType()->isExtVectorBoolType()) {
cgm.errorNYI(loc, "emitLoadOfExtVectorElementLValue: ExtVectorBoolType");
return {};
}

return RValue::get(resultVec);
}

static cir::FuncOp emitFunctionDeclPointer(CIRGenModule &cgm, GlobalDecl gd) {
Expand Down
17 changes: 17 additions & 0 deletions clang/lib/CIR/CodeGen/CIRGenExprScalar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,8 @@ class ScalarExprEmitter : public StmtVisitor<ScalarExprEmitter, mlir::Value> {
return emitNullValue(e->getType(), cgf.getLoc(e->getSourceRange()));
}

mlir::Value VisitOffsetOfExpr(OffsetOfExpr *e);

mlir::Value VisitOpaqueValueExpr(OpaqueValueExpr *e) {
if (e->isGLValue())
return emitLoadOfLValue(cgf.getOrCreateOpaqueLValueMapping(e),
Expand Down Expand Up @@ -2209,6 +2211,21 @@ mlir::Value ScalarExprEmitter::VisitUnaryLNot(const UnaryOperator *e) {
return maybePromoteBoolResult(boolVal, cgf.convertType(e->getType()));
}

mlir::Value ScalarExprEmitter::VisitOffsetOfExpr(OffsetOfExpr *e) {
// Try folding the offsetof to a constant.
Expr::EvalResult evalResult;
if (e->EvaluateAsInt(evalResult, cgf.getContext())) {
mlir::Type type = cgf.convertType(e->getType());
llvm::APSInt value = evalResult.Val.getInt();
return builder.getConstAPInt(cgf.getLoc(e->getExprLoc()), type, value);
}

cgf.getCIRGenModule().errorNYI(
e->getSourceRange(),
"ScalarExprEmitter::VisitOffsetOfExpr Can't eval expr as int");
return {};
}

mlir::Value ScalarExprEmitter::VisitUnaryReal(const UnaryOperator *e) {
QualType promotionTy = getPromotionType(e->getSubExpr()->getType());
mlir::Value result = VisitRealImag(e, promotionTy);
Expand Down
8 changes: 8 additions & 0 deletions clang/test/Analysis/z3-unarysymexpr.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,11 @@ int z3_crash2(int a) {
return *d; // expected-warning{{Dereference of undefined pointer value}}
return 0;
}

// Refer to issue 165779
void z3_crash3(long a) {
if (~-(5 && a)) {
long *c;
*c; // expected-warning{{Dereference of undefined pointer value (loaded from variable 'c')}}
}
}
93 changes: 93 additions & 0 deletions clang/test/CIR/CodeGen/offset-of.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-cir %s -o %t.cir
// RUN: FileCheck --input-file=%t.cir %s -check-prefix=CIR
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -fclangir -emit-llvm %s -o %t-cir.ll
// RUN: FileCheck --input-file=%t-cir.ll %s -check-prefix=LLVM
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG

struct Struct {
int a;
float b;
double c;
bool d;
};

void offset_of_builtin() {
unsigned long a = __builtin_offsetof(Struct, a);
unsigned long b = __builtin_offsetof(Struct, b);
unsigned long c = __builtin_offsetof(Struct, c);
unsigned long d = __builtin_offsetof(Struct, d);
}

// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init]
// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init]
// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init]
// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init]
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i
// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_4:.*]] = cir.const #cir.int<4> : !u64i
// CIR: cir.store {{.*}} %[[CONST_4]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_8:.*]] = cir.const #cir.int<8> : !u64i
// CIR: cir.store {{.*}} %[[CONST_8]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_16:.*]] = cir.const #cir.int<16> : !u64i
// CIR: cir.store {{.*}} %[[CONST_16]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i>

// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: store i64 0, ptr %[[A_ADDR]], align 8
// LLVM: store i64 4, ptr %[[B_ADDR]], align 8
// LLVM: store i64 8, ptr %[[C_ADDR]], align 8
// LLVM: store i64 16, ptr %[[D_ADDR]], align 8

// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8
// OGCG: store i64 0, ptr %[[A_ADDR]], align 8
// OGCG: store i64 4, ptr %[[B_ADDR]], align 8
// OGCG: store i64 8, ptr %[[C_ADDR]], align 8
// OGCG: store i64 16, ptr %[[D_ADDR]], align 8

struct StructWithArray {
Struct array[4][4];
};

void offset_of_builtin_from_array_element() {
unsigned long a = __builtin_offsetof(StructWithArray, array[0][0].a);
unsigned long b = __builtin_offsetof(StructWithArray, array[1][1].b);
unsigned long c = __builtin_offsetof(StructWithArray, array[2][2].c);
unsigned long d = __builtin_offsetof(StructWithArray, array[3][3].d);
}

// CIR: %[[A_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["a", init]
// CIR: %[[B_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["b", init]
// CIR: %[[C_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["c", init]
// CIR: %[[D_ADDR:.*]] = cir.alloca !u64i, !cir.ptr<!u64i>, ["d", init]
// CIR: %[[CONST_0:.*]] = cir.const #cir.int<0> : !u64i
// CIR: cir.store {{.*}} %[[CONST_0]], %[[A_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_124:.*]] = cir.const #cir.int<124> : !u64i
// CIR: cir.store {{.*}} %[[CONST_124]], %[[B_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_248:.*]] = cir.const #cir.int<248> : !u64i
// CIR: cir.store {{.*}} %[[CONST_248]], %[[C_ADDR]] : !u64i, !cir.ptr<!u64i>
// CIR: %[[CONST_376:.*]] = cir.const #cir.int<376> : !u64i
// CIR: cir.store {{.*}} %[[CONST_376]], %[[D_ADDR]] : !u64i, !cir.ptr<!u64i>

// LLVM: %[[A_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[B_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[C_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: %[[D_ADDR:.*]] = alloca i64, i64 1, align 8
// LLVM: store i64 0, ptr %[[A_ADDR]], align 8
// LLVM: store i64 124, ptr %[[B_ADDR]], align 8
// LLVM: store i64 248, ptr %[[C_ADDR]], align 8
// LLVM: store i64 376, ptr %[[D_ADDR]], align 8

// OGCG: %[[A_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[B_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[C_ADDR:.*]] = alloca i64, align 8
// OGCG: %[[D_ADDR:.*]] = alloca i64, align 8
// OGCG: store i64 0, ptr %[[A_ADDR]], align 8
// OGCG: store i64 124, ptr %[[B_ADDR]], align 8
// OGCG: store i64 248, ptr %[[C_ADDR]], align 8
// OGCG: store i64 376, ptr %[[D_ADDR]], align 8
39 changes: 39 additions & 0 deletions clang/test/CIR/CodeGen/vector-ext-element.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
// RUN: %clang_cc1 -triple x86_64-unknown-linux-gnu -Wno-unused-value -emit-llvm %s -o %t.ll
// RUN: FileCheck --input-file=%t.ll %s -check-prefix=OGCG

typedef int vi2 __attribute__((ext_vector_type(2)));
typedef int vi4 __attribute__((ext_vector_type(4)));

void element_expr_from_gl() {
Expand Down Expand Up @@ -44,3 +45,41 @@ void element_expr_from_gl() {
// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// OGCG: %[[ELEM_1:.*]] = extractelement <4 x i32> %[[TMP_A]], i64 1
// OGCG: store i32 %[[ELEM_1]], ptr %[[Y_ADDR]], align 4

void element_expr_from_gl_with_vec_result() {
vi4 a;
vi2 b = a.xy;
vi4 c = a.wzyx;
}

// CIR: %[[A_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["a"]
// CIR: %[[B_ADDR:.*]] = cir.alloca !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>>, ["b", init]
// CIR: %[[C_ADDR:.*]] = cir.alloca !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>, ["c", init]
// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i>
// CIR: %[[B_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<0> : !s32i, #cir.int<1> : !s32i] : !cir.vector<2 x !s32i>
// CIR: cir.store {{.*}} %[[B_VALUE]], %[[B_ADDR]] : !cir.vector<2 x !s32i>, !cir.ptr<!cir.vector<2 x !s32i>>
// CIR: %[[TMP_A:.*]] = cir.load {{.*}} %[[A_ADDR]] : !cir.ptr<!cir.vector<4 x !s32i>>, !cir.vector<4 x !s32i>
// CIR: %[[POISON:.*]] = cir.const #cir.poison : !cir.vector<4 x !s32i>
// CIR: %[[C_VALUE:.*]] = cir.vec.shuffle(%[[TMP_A]], %[[POISON]] : !cir.vector<4 x !s32i>) [#cir.int<3> : !s32i, #cir.int<2> : !s32i, #cir.int<1> : !s32i, #cir.int<0> : !s32i] : !cir.vector<4 x !s32i>
// CIR: cir.store {{.*}} %[[C_VALUE]], %[[C_ADDR]] : !cir.vector<4 x !s32i>, !cir.ptr<!cir.vector<4 x !s32i>>

// LLVM: %[[A_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16
// LLVM: %[[B_ADDR:.*]] = alloca <2 x i32>, i64 1, align 8
// LLVM: %[[C_ADDR:.*]] = alloca <4 x i32>, i64 1, align 16
// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// LLVM: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1>
// LLVM: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8
// LLVM: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// LLVM: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
// LLVM: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16

// OGCG: %[[A_ADDR:.*]] = alloca <4 x i32>, align 16
// OGCG: %[[B_ADDR:.*]] = alloca <2 x i32>, align 8
// OGCG: %[[C_ADDR:.*]] = alloca <4 x i32>, align 16
// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// OGCG: %[[B_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <2 x i32> <i32 0, i32 1>
// OGCG: store <2 x i32> %[[B_VALUE]], ptr %[[B_ADDR]], align 8
// OGCG: %[[TMP_A:.*]] = load <4 x i32>, ptr %[[A_ADDR]], align 16
// OGCG: %[[C_VALUE:.*]] = shufflevector <4 x i32> %[[TMP_A]], <4 x i32> poison, <4 x i32> <i32 3, i32 2, i32 1, i32 0>
// OGCG: store <4 x i32> %[[C_VALUE]], ptr %[[C_ADDR]], align 16
3 changes: 2 additions & 1 deletion libcxx/include/limits
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ template<> class numeric_limits<cv long double>;
#else
# include <__config>
# include <__type_traits/is_arithmetic.h>
# include <__type_traits/is_same.h>
# include <__type_traits/is_signed.h>

# if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER)
Expand Down Expand Up @@ -220,7 +221,7 @@ protected:
static _LIBCPP_CONSTEXPR const bool is_modulo = !std::is_signed<_Tp>::value;

# if defined(__i386__) || defined(__x86_64__) || defined(__wasm__)
static _LIBCPP_CONSTEXPR const bool traps = true;
static _LIBCPP_CONSTEXPR const bool traps = is_same<decltype(+_Tp(0)), _Tp>::value;
# else
static _LIBCPP_CONSTEXPR const bool traps = false;
# endif
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@

// traps

// XFAIL: FROZEN-CXX03-HEADERS-FIXME

#include <limits>

#include "test_macros.h"
Expand All @@ -33,17 +35,17 @@ test()
int main(int, char**)
{
test<bool, false>();
test<char, integral_types_trap>();
test<signed char, integral_types_trap>();
test<unsigned char, integral_types_trap>();
test<wchar_t, integral_types_trap>();
test<char, false>();
test<signed char, false>();
test<unsigned char, false>();
test<wchar_t, false>();
#if TEST_STD_VER > 17 && defined(__cpp_char8_t)
test<char8_t, integral_types_trap>();
test<char8_t, false>();
#endif
test<char16_t, integral_types_trap>();
test<char32_t, integral_types_trap>();
test<short, integral_types_trap>();
test<unsigned short, integral_types_trap>();
test<char16_t, false>();
test<char32_t, false>();
test<short, false>();
test<unsigned short, false>();
test<int, integral_types_trap>();
test<unsigned int, integral_types_trap>();
test<long, integral_types_trap>();
Expand Down
2 changes: 1 addition & 1 deletion llvm/include/llvm/MC/MCAsmBackend.h
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ class LLVM_ABI MCAsmBackend {

// Return true if fragment offsets have been adjusted and an extra layout
// iteration is needed.
virtual bool finishLayout(const MCAssembler &Asm) const { return false; }
virtual bool finishLayout() const { return false; }

/// Generate the compact unwind encoding for the CFI instructions.
virtual uint64_t generateCompactUnwindEncoding(const MCDwarfFrameInfo *FI,
Expand Down
20 changes: 8 additions & 12 deletions llvm/include/llvm/MC/MCSection.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,10 @@ class MCFragment {
uint32_t VarContentEnd = 0;
uint32_t VarFixupStart = 0;

protected:
const MCSubtargetInfo *STI = nullptr;

private:
// Optional variable-size tail used by various fragment types.
union Tail {
struct {
Expand Down Expand Up @@ -362,22 +364,19 @@ class MCNopsFragment : public MCFragment {
/// Source location of the directive that this fragment was created for.
SMLoc Loc;

/// When emitting Nops some subtargets have specific nop encodings.
const MCSubtargetInfo &STI;

public:
MCNopsFragment(int64_t NumBytes, int64_t ControlledNopLength, SMLoc L,
const MCSubtargetInfo &STI)
: MCFragment(FT_Nops), Size(NumBytes),
ControlledNopLength(ControlledNopLength), Loc(L), STI(STI) {}
ControlledNopLength(ControlledNopLength), Loc(L) {
this->STI = &STI;
}

int64_t getNumBytes() const { return Size; }
int64_t getControlledNopLength() const { return ControlledNopLength; }

SMLoc getLoc() const { return Loc; }

const MCSubtargetInfo *getSubtargetInfo() const { return &STI; }

static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_Nops;
}
Expand Down Expand Up @@ -490,12 +489,11 @@ class MCBoundaryAlignFragment : public MCFragment {
/// is not meaningful before that.
uint64_t Size = 0;

/// When emitting Nops some subtargets have specific nop encodings.
const MCSubtargetInfo &STI;

public:
MCBoundaryAlignFragment(Align AlignBoundary, const MCSubtargetInfo &STI)
: MCFragment(FT_BoundaryAlign), AlignBoundary(AlignBoundary), STI(STI) {}
: MCFragment(FT_BoundaryAlign), AlignBoundary(AlignBoundary) {
this->STI = &STI;
}

uint64_t getSize() const { return Size; }
void setSize(uint64_t Value) { Size = Value; }
Expand All @@ -509,8 +507,6 @@ class MCBoundaryAlignFragment : public MCFragment {
LastFragment = F;
}

const MCSubtargetInfo *getSubtargetInfo() const { return &STI; }

static bool classof(const MCFragment *F) {
return F->getKind() == MCFragment::FT_BoundaryAlign;
}
Expand Down
Loading