lebedev.ri updated this revision to Diff 239958.
lebedev.ri added a comment.
Rebased, NFC.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D73005/new/
https://reviews.llvm.org/D73005
Files:
clang/lib/CodeGen/CGCall.cpp
clang/test/CodeGen/assume-aligned-and-alloc-align-attributes.c
clang/test/CodeGen/builtin-assume-aligned.c
clang/test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp
Index: clang/test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp
===================================================================
--- clang/test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp
+++ clang/test/CodeGen/catch-alignment-assumption-attribute-assume_aligned-on-function.cpp
@@ -6,7 +6,7 @@
// CHECK-SANITIZE-ANYRECOVER: @[[CHAR:.*]] = {{.*}} c"'char **'\00" }
// CHECK-SANITIZE-ANYRECOVER: @[[LINE_100_ALIGNMENT_ASSUMPTION:.*]] = {{.*}}, i32 100, i32 10 }, {{.*}}* @[[CHAR]] }
-char **__attribute__((assume_aligned(0x80000000))) passthrough(char **x) {
+char **__attribute__((assume_aligned(128))) passthrough(char **x) {
// CHECK: define i8** @[[PASSTHROUGH:.*]](i8** %[[X:.*]])
// CHECK-NEXT: entry:
// CHECK-NEXT: %[[X_ADDR:.*]] = alloca i8**, align 8
@@ -23,19 +23,20 @@
// CHECK-NEXT: %[[X_ADDR]] = alloca i8**, align 8
// CHECK-NEXT: store i8** %[[X]], i8*** %[[X_ADDR]], align 8
// CHECK-NEXT: %[[X_RELOADED:.*]] = load i8**, i8*** %[[X_ADDR]], align 8
- // CHECK-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]])
- // CHECK-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
- // CHECK-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 2147483647
- // CHECK-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
+ // CHECK-NOSANITIZE-NEXT: %[[X_RETURNED:.*]] = call align 128 i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]])
+ // CHECK-SANITIZE-NEXT: %[[X_RETURNED:.*]] = call i8** @[[PASSTHROUGH]](i8** %[[X_RELOADED]])
+ // CHECK-SANITIZE-NEXT: %[[PTRINT:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64
+ // CHECK-SANITIZE-NEXT: %[[MASKEDPTR:.*]] = and i64 %[[PTRINT]], 127
+ // CHECK-SANITIZE-NEXT: %[[MASKCOND:.*]] = icmp eq i64 %[[MASKEDPTR]], 0
// CHECK-SANITIZE-NEXT: %[[PTRINT_DUP:.*]] = ptrtoint i8** %[[X_RETURNED]] to i64, !nosanitize
// CHECK-SANITIZE-NEXT: br i1 %[[MASKCOND]], label %[[CONT:.*]], label %[[HANDLER_ALIGNMENT_ASSUMPTION:[^,]+]],{{.*}} !nosanitize
// CHECK-SANITIZE: [[HANDLER_ALIGNMENT_ASSUMPTION]]:
- // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize
- // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 2147483648, i64 0){{.*}}, !nosanitize
+ // CHECK-SANITIZE-NORECOVER-NEXT: call void @__ubsan_handle_alignment_assumption_abort(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 128, i64 0){{.*}}, !nosanitize
+ // CHECK-SANITIZE-RECOVER-NEXT: call void @__ubsan_handle_alignment_assumption(i8* bitcast ({ {{{.*}}}, {{{.*}}}, {{{.*}}}* }* @[[LINE_100_ALIGNMENT_ASSUMPTION]] to i8*), i64 %[[PTRINT_DUP]], i64 128, i64 0){{.*}}, !nosanitize
// CHECK-SANITIZE-TRAP-NEXT: call void @llvm.trap(){{.*}}, !nosanitize
// CHECK-SANITIZE-UNREACHABLE-NEXT: unreachable, !nosanitize
// CHECK-SANITIZE: [[CONT]]:
- // CHECK-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
+ // CHECK-SANITIZE-NEXT: call void @llvm.assume(i1 %[[MASKCOND]])
// CHECK-NEXT: ret i8** %[[X_RETURNED]]
// CHECK-NEXT: }
#line 100
Index: clang/test/CodeGen/builtin-assume-aligned.c
===================================================================
--- clang/test/CodeGen/builtin-assume-aligned.c
+++ clang/test/CodeGen/builtin-assume-aligned.c
@@ -44,13 +44,14 @@
int *m1() __attribute__((assume_aligned(64)));
-// CHECK-LABEL: @test5
+// CHECK-LABEL: @test5(
+// CHECK-NEXT: entry:
+// CHECK-NEXT: [[CALL:%.*]] = call align 64 i32* (...) @m1()
+// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[CALL]], align 4
+// CHECK-NEXT: ret i32 [[TMP0]]
+//
int test5() {
return *m1();
-// CHECK: [[PTRINT5:%.+]] = ptrtoint
-// CHECK: [[MASKEDPTR5:%.+]] = and i64 [[PTRINT5]], 63
-// CHECK: [[MASKCOND5:%.+]] = icmp eq i64 [[MASKEDPTR5]], 0
-// CHECK: call void @llvm.assume(i1 [[MASKCOND5]])
}
int *m2() __attribute__((assume_aligned(64, 12)));
Index: clang/test/CodeGen/assume-aligned-and-alloc-align-attributes.c
===================================================================
--- clang/test/CodeGen/assume-aligned-and-alloc-align-attributes.c
+++ clang/test/CodeGen/assume-aligned-and-alloc-align-attributes.c
@@ -5,15 +5,11 @@
// CHECK-LABEL: @t0_immediate0(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[CALL:%.*]] = call i8* @my_aligned_alloc(i32 320, i32 16)
+// CHECK-NEXT: [[CALL:%.*]] = call align 32 i8* @my_aligned_alloc(i32 320, i32 16)
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 15
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
-// CHECK-NEXT: [[PTRINT1:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR2:%.*]] = and i64 [[PTRINT1]], 15
-// CHECK-NEXT: [[MASKCOND3:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0
-// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND3]])
// CHECK-NEXT: ret i8* [[CALL]]
//
void *t0_immediate0() {
@@ -22,15 +18,11 @@
// CHECK-LABEL: @t1_immediate1(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[CALL:%.*]] = call i8* @my_aligned_alloc(i32 320, i32 32)
+// CHECK-NEXT: [[CALL:%.*]] = call align 32 i8* @my_aligned_alloc(i32 320, i32 32)
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
-// CHECK-NEXT: [[PTRINT1:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR2:%.*]] = and i64 [[PTRINT1]], 31
-// CHECK-NEXT: [[MASKCOND3:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0
-// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND3]])
// CHECK-NEXT: ret i8* [[CALL]]
//
void *t1_immediate1() {
@@ -39,15 +31,11 @@
// CHECK-LABEL: @t2_immediate2(
// CHECK-NEXT: entry:
-// CHECK-NEXT: [[CALL:%.*]] = call i8* @my_aligned_alloc(i32 320, i32 64)
+// CHECK-NEXT: [[CALL:%.*]] = call align 32 i8* @my_aligned_alloc(i32 320, i32 64)
// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
+// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 63
// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
-// CHECK-NEXT: [[PTRINT1:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR2:%.*]] = and i64 [[PTRINT1]], 63
-// CHECK-NEXT: [[MASKCOND3:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0
-// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND3]])
// CHECK-NEXT: ret i8* [[CALL]]
//
void *t2_immediate2() {
@@ -59,17 +47,13 @@
// CHECK-NEXT: [[ALIGNMENT_ADDR:%.*]] = alloca i32, align 4
// CHECK-NEXT: store i32 [[ALIGNMENT:%.*]], i32* [[ALIGNMENT_ADDR]], align 4
// CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[ALIGNMENT_ADDR]], align 4
-// CHECK-NEXT: [[CALL:%.*]] = call i8* @my_aligned_alloc(i32 320, i32 [[TMP0]])
-// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
-// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
-// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
+// CHECK-NEXT: [[CALL:%.*]] = call align 32 i8* @my_aligned_alloc(i32 320, i32 [[TMP0]])
// CHECK-NEXT: [[ALIGNMENTCAST:%.*]] = zext i32 [[TMP0]] to i64
// CHECK-NEXT: [[MASK:%.*]] = sub i64 [[ALIGNMENTCAST]], 1
-// CHECK-NEXT: [[PTRINT1:%.*]] = ptrtoint i8* [[CALL]] to i64
-// CHECK-NEXT: [[MASKEDPTR2:%.*]] = and i64 [[PTRINT1]], [[MASK]]
-// CHECK-NEXT: [[MASKCOND3:%.*]] = icmp eq i64 [[MASKEDPTR2]], 0
-// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND3]])
+// CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint i8* [[CALL]] to i64
+// CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], [[MASK]]
+// CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
+// CHECK-NEXT: call void @llvm.assume(i1 [[MASKCOND]])
// CHECK-NEXT: ret i8* [[CALL]]
//
void *t3_variable(int alignment) {
Index: clang/lib/CodeGen/CGCall.cpp
===================================================================
--- clang/lib/CodeGen/CGCall.cpp
+++ clang/lib/CodeGen/CGCall.cpp
@@ -3809,6 +3809,90 @@
DeferredReplacements.push_back(std::make_pair(Old, New));
}
+namespace {
+
+/// Specify given \p NewAlign as the alignment of return value attribute. If
+/// such attribute already exists, re-set it to the maximal one of two options.
+LLVM_NODISCARD llvm::AttributeList
+maybeRaiseRetAlignmentAttribute(llvm::LLVMContext &Ctx,
+ const llvm::AttributeList &Attrs,
+ llvm::Align NewAlign) {
+ llvm::Align CurAlign = Attrs.getRetAlignment().valueOrOne();
+ if (CurAlign >= NewAlign)
+ return Attrs;
+ llvm::Attribute AlignAttr = llvm::Attribute::getWithAlignment(Ctx, NewAlign);
+ return Attrs
+ .removeAttribute(Ctx, llvm::AttributeList::ReturnIndex,
+ llvm::Attribute::AttrKind::Alignment)
+ .addAttribute(Ctx, llvm::AttributeList::ReturnIndex, AlignAttr);
+}
+
+template <typename AlignedAttrTy> class AbstractAssumeAlignedAttrEmitter {
+protected:
+ CodeGenFunction &CGF;
+
+ /// We do nothing if this is, or becomes, nullptr.
+ const AlignedAttrTy *AA = nullptr;
+
+ llvm::Value *Alignment = nullptr; // May or may not be a constant.
+ llvm::ConstantInt *OffsetCI = nullptr; // Constant, hopefully zero.
+
+ AbstractAssumeAlignedAttrEmitter(CodeGenFunction &CGF_, const Decl *FuncDecl)
+ : CGF(CGF_) {
+ if (!FuncDecl)
+ return;
+ AA = FuncDecl->getAttr<AlignedAttrTy>();
+ }
+
+public:
+ /// If we can, materialize the alignment as an attribute on return value.
+ LLVM_NODISCARD llvm::AttributeList
+ TryEmitAsCallSiteAttribute(const llvm::AttributeList &Attrs) {
+ if (!AA || OffsetCI || CGF.SanOpts.has(SanitizerKind::Alignment))
+ return Attrs;
+ const auto *AlignmentCI = dyn_cast<llvm::ConstantInt>(Alignment);
+ if (!AlignmentCI)
+ return Attrs;
+ llvm::AttributeList NewAttrs = maybeRaiseRetAlignmentAttribute(
+ CGF.getLLVMContext(), Attrs,
+ llvm::Align(
+ AlignmentCI->getLimitedValue(llvm::Value::MaximumAlignment)));
+ AA = nullptr; // We're done. Disallow doing anything else.
+ return NewAttrs;
+ }
+
+ /// Emit alignment assumption.
+ /// This is a general fallback that we take if either there is an offset,
+ /// or the alignment is variable or we are sanitizing for alignment.
+ void EmitAsAnAssumption(SourceLocation Loc, QualType RetTy, RValue &Ret) {
+ if (!AA)
+ return;
+ CGF.EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc,
+ AA->getLocation(), Alignment, OffsetCI);
+ AA = nullptr; // We're done. Disallow doing anything else.
+ }
+};
+
+/// Helper data structure to emit `AssumeAlignedAttr`.
+class AssumeAlignedAttrEmitter final
+ : public AbstractAssumeAlignedAttrEmitter<AssumeAlignedAttr> {
+public:
+ AssumeAlignedAttrEmitter(CodeGenFunction &CGF_, const Decl *FuncDecl)
+ : AbstractAssumeAlignedAttrEmitter(CGF_, FuncDecl) {
+ if (!AA)
+ return;
+ // It is guaranteed that the alignment/offset are constants.
+ Alignment = cast<llvm::ConstantInt>(CGF.EmitScalarExpr(AA->getAlignment()));
+ if (Expr *Offset = AA->getOffset()) {
+ OffsetCI = cast<llvm::ConstantInt>(CGF.EmitScalarExpr(Offset));
+ if (OffsetCI->isNullValue()) // Canonicalize zero offset to no offset.
+ OffsetCI = nullptr;
+ }
+ }
+};
+
+} // namespace
+
RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
const CGCallee &Callee,
ReturnValueSlot ReturnValue,
@@ -4400,6 +4484,9 @@
Attrs.addAttribute(getLLVMContext(), llvm::AttributeList::FunctionIndex,
llvm::Attribute::StrictFP);
+ AssumeAlignedAttrEmitter AssumeAlignedAttrEmitter(*this, TargetDecl);
+ Attrs = AssumeAlignedAttrEmitter.TryEmitAsCallSiteAttribute(Attrs);
+
// Emit the actual call/invoke instruction.
llvm::CallBase *CI;
if (!InvokeDest) {
@@ -4618,16 +4705,8 @@
// Emit the assume_aligned check on the return value.
if (Ret.isScalar() && TargetDecl) {
- if (const auto *AA = TargetDecl->getAttr<AssumeAlignedAttr>()) {
- llvm::Value *OffsetValue = nullptr;
- if (const auto *Offset = AA->getOffset())
- OffsetValue = EmitScalarExpr(Offset);
+ AssumeAlignedAttrEmitter.EmitAsAnAssumption(Loc, RetTy, Ret);
- llvm::Value *Alignment = EmitScalarExpr(AA->getAlignment());
- llvm::ConstantInt *AlignmentCI = cast<llvm::ConstantInt>(Alignment);
- EmitAlignmentAssumption(Ret.getScalarVal(), RetTy, Loc, AA->getLocation(),
- AlignmentCI, OffsetValue);
- }
if (const auto *AA = TargetDecl->getAttr<AllocAlignAttr>()) {
llvm::Value *AlignmentVal = CallArgs[AA->getParamIndex().getLLVMIndex()]
.getRValue(*this)
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits