[InferAlignment] Implement InferAlignmentPass
This pass aims to infer alignment for instructions as a separate pass, to reduce redundant work done by InstCombine running multiple times. It runs late in the pipeline, just before the back-end passes where this information is most useful. Differential Revision: https://reviews.llvm.org/D158529
This commit is contained in:
27
llvm/include/llvm/Transforms/Scalar/InferAlignment.h
Normal file
27
llvm/include/llvm/Transforms/Scalar/InferAlignment.h
Normal file
@@ -0,0 +1,27 @@
|
||||
//===- InferAlignment.h -----------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Infer alignment for load, stores and other memory operations based on
|
||||
// trailing zero known bits information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#ifndef LLVM_TRANSFORMS_SCALAR_INFERALIGNMENT_H
|
||||
#define LLVM_TRANSFORMS_SCALAR_INFERALIGNMENT_H
|
||||
|
||||
#include "llvm/IR/PassManager.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
struct InferAlignmentPass : public PassInfoMixin<InferAlignmentPass> {
|
||||
PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM);
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
#endif // LLVM_TRANSFORMS_SCALAR_INFERALIGNMENT_H
|
||||
@@ -213,6 +213,15 @@ AllocaInst *DemoteRegToStack(Instruction &X,
|
||||
/// deleted and it returns the pointer to the alloca inserted.
|
||||
AllocaInst *DemotePHIToStack(PHINode *P, Instruction *AllocaPoint = nullptr);
|
||||
|
||||
/// If the specified pointer points to an object that we control, try to modify
|
||||
/// the object's alignment to PrefAlign. Returns a minimum known alignment of
|
||||
/// the value after the operation, which may be lower than PrefAlign.
|
||||
///
|
||||
/// Increating value alignment isn't often possible though. If alignment is
|
||||
/// important, a more reliable approach is to simply align all global variables
|
||||
/// and allocation instructions to their preferred alignment from the beginning.
|
||||
Align tryEnforceAlignment(Value *V, Align PrefAlign, const DataLayout &DL);
|
||||
|
||||
/// Try to ensure that the alignment of \p V is at least \p PrefAlign bytes. If
|
||||
/// the owning object can be modified and has an alignment less than \p
|
||||
/// PrefAlign, it will be increased and \p PrefAlign returned. If the alignment
|
||||
|
||||
@@ -171,6 +171,7 @@
|
||||
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
|
||||
#include "llvm/Transforms/Scalar/InductiveRangeCheckElimination.h"
|
||||
#include "llvm/Transforms/Scalar/InferAddressSpaces.h"
|
||||
#include "llvm/Transforms/Scalar/InferAlignment.h"
|
||||
#include "llvm/Transforms/Scalar/InstSimplifyPass.h"
|
||||
#include "llvm/Transforms/Scalar/JumpThreading.h"
|
||||
#include "llvm/Transforms/Scalar/LICM.h"
|
||||
|
||||
@@ -88,6 +88,7 @@
|
||||
#include "llvm/Transforms/Scalar/Float2Int.h"
|
||||
#include "llvm/Transforms/Scalar/GVN.h"
|
||||
#include "llvm/Transforms/Scalar/IndVarSimplify.h"
|
||||
#include "llvm/Transforms/Scalar/InferAlignment.h"
|
||||
#include "llvm/Transforms/Scalar/InstSimplifyPass.h"
|
||||
#include "llvm/Transforms/Scalar/JumpThreading.h"
|
||||
#include "llvm/Transforms/Scalar/LICM.h"
|
||||
@@ -274,6 +275,11 @@ cl::opt<bool> EnableMemProfContextDisambiguation(
|
||||
"enable-memprof-context-disambiguation", cl::init(false), cl::Hidden,
|
||||
cl::ZeroOrMore, cl::desc("Enable MemProf context disambiguation"));
|
||||
|
||||
cl::opt<bool> EnableInferAlignmentPass(
|
||||
"enable-infer-alignment-pass", cl::init(false), cl::Hidden, cl::ZeroOrMore,
|
||||
cl::desc("Enable the InferAlignment pass, disabling alignment inference in "
|
||||
"InstCombine"));
|
||||
|
||||
PipelineTuningOptions::PipelineTuningOptions() {
|
||||
LoopInterleaving = true;
|
||||
LoopVectorization = true;
|
||||
@@ -1140,6 +1146,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
|
||||
FPM.addPass(LoopVectorizePass(
|
||||
LoopVectorizeOptions(!PTO.LoopInterleaving, !PTO.LoopVectorization)));
|
||||
|
||||
if (EnableInferAlignmentPass)
|
||||
FPM.addPass(InferAlignmentPass());
|
||||
if (IsFullLTO) {
|
||||
// The vectorizer may have significantly shortened a loop body; unroll
|
||||
// again. Unroll small loops to hide loop backedge latency and saturate any
|
||||
@@ -1257,6 +1265,8 @@ void PassBuilder::addVectorPasses(OptimizationLevel Level,
|
||||
FPM.addPass(SROAPass(SROAOptions::PreserveCFG));
|
||||
}
|
||||
|
||||
if (EnableInferAlignmentPass)
|
||||
FPM.addPass(InferAlignmentPass());
|
||||
FPM.addPass(InstCombinePass());
|
||||
|
||||
// This is needed for two reasons:
|
||||
|
||||
@@ -337,6 +337,7 @@ FUNCTION_PASS("gvn-hoist", GVNHoistPass())
|
||||
FUNCTION_PASS("gvn-sink", GVNSinkPass())
|
||||
FUNCTION_PASS("helloworld", HelloWorldPass())
|
||||
FUNCTION_PASS("infer-address-spaces", InferAddressSpacesPass())
|
||||
FUNCTION_PASS("infer-alignment", InferAlignmentPass())
|
||||
FUNCTION_PASS("instcount", InstCountPass())
|
||||
FUNCTION_PASS("instsimplify", InstSimplifyPass())
|
||||
FUNCTION_PASS("invalidate<all>", InvalidateAllAnalysesPass())
|
||||
|
||||
@@ -22,6 +22,7 @@ add_llvm_component_library(LLVMScalarOpts
|
||||
InductiveRangeCheckElimination.cpp
|
||||
IndVarSimplify.cpp
|
||||
InferAddressSpaces.cpp
|
||||
InferAlignment.cpp
|
||||
InstSimplifyPass.cpp
|
||||
JumpThreading.cpp
|
||||
LICM.cpp
|
||||
|
||||
91
llvm/lib/Transforms/Scalar/InferAlignment.cpp
Normal file
91
llvm/lib/Transforms/Scalar/InferAlignment.cpp
Normal file
@@ -0,0 +1,91 @@
|
||||
//===- InferAlignment.cpp -------------------------------------------------===//
|
||||
//
|
||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
||||
// See https://llvm.org/LICENSE.txt for license information.
|
||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
//
|
||||
// Infer alignment for load, stores and other memory operations based on
|
||||
// trailing zero known bits information.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "llvm/Transforms/Scalar/InferAlignment.h"
|
||||
#include "llvm/Analysis/AssumptionCache.h"
|
||||
#include "llvm/Analysis/ValueTracking.h"
|
||||
#include "llvm/IR/Instructions.h"
|
||||
#include "llvm/InitializePasses.h"
|
||||
#include "llvm/Support/KnownBits.h"
|
||||
#include "llvm/Transforms/Scalar.h"
|
||||
#include "llvm/Transforms/Utils/Local.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
static bool tryToImproveAlign(
|
||||
const DataLayout &DL, Instruction *I,
|
||||
function_ref<Align(Value *PtrOp, Align OldAlign, Align PrefAlign)> Fn) {
|
||||
if (auto *LI = dyn_cast<LoadInst>(I)) {
|
||||
Value *PtrOp = LI->getPointerOperand();
|
||||
Align OldAlign = LI->getAlign();
|
||||
Align NewAlign = Fn(PtrOp, OldAlign, DL.getPrefTypeAlign(LI->getType()));
|
||||
if (NewAlign > OldAlign) {
|
||||
LI->setAlignment(NewAlign);
|
||||
return true;
|
||||
}
|
||||
} else if (auto *SI = dyn_cast<StoreInst>(I)) {
|
||||
Value *PtrOp = SI->getPointerOperand();
|
||||
Value *ValOp = SI->getValueOperand();
|
||||
Align OldAlign = SI->getAlign();
|
||||
Align NewAlign = Fn(PtrOp, OldAlign, DL.getPrefTypeAlign(ValOp->getType()));
|
||||
if (NewAlign > OldAlign) {
|
||||
SI->setAlignment(NewAlign);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
// TODO: Also handle memory intrinsics.
|
||||
return false;
|
||||
}
|
||||
|
||||
bool inferAlignment(Function &F, AssumptionCache &AC, DominatorTree &DT) {
|
||||
const DataLayout &DL = F.getParent()->getDataLayout();
|
||||
bool Changed = false;
|
||||
|
||||
// Enforce preferred type alignment if possible. We do this as a separate
|
||||
// pass first, because it may improve the alignments we infer below.
|
||||
for (BasicBlock &BB : F) {
|
||||
for (Instruction &I : BB) {
|
||||
Changed |= tryToImproveAlign(
|
||||
DL, &I, [&](Value *PtrOp, Align OldAlign, Align PrefAlign) {
|
||||
if (PrefAlign > OldAlign)
|
||||
return std::max(OldAlign,
|
||||
tryEnforceAlignment(PtrOp, PrefAlign, DL));
|
||||
return OldAlign;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// Compute alignment from known bits.
|
||||
for (BasicBlock &BB : F) {
|
||||
for (Instruction &I : BB) {
|
||||
Changed |= tryToImproveAlign(
|
||||
DL, &I, [&](Value *PtrOp, Align OldAlign, Align PrefAlign) {
|
||||
KnownBits Known = computeKnownBits(PtrOp, DL, 0, &AC, &I, &DT);
|
||||
unsigned TrailZ = std::min(Known.countMinTrailingZeros(),
|
||||
+Value::MaxAlignmentExponent);
|
||||
return Align(1ull << std::min(Known.getBitWidth() - 1, TrailZ));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return Changed;
|
||||
}
|
||||
|
||||
PreservedAnalyses InferAlignmentPass::run(Function &F,
|
||||
FunctionAnalysisManager &AM) {
|
||||
AssumptionCache &AC = AM.getResult<AssumptionAnalysis>(F);
|
||||
DominatorTree &DT = AM.getResult<DominatorTreeAnalysis>(F);
|
||||
inferAlignment(F, AC, DT);
|
||||
// Changes to alignment shouldn't invalidated analyses.
|
||||
return PreservedAnalyses::all();
|
||||
}
|
||||
@@ -1388,15 +1388,8 @@ bool llvm::EliminateDuplicatePHINodes(BasicBlock *BB) {
|
||||
return Changed;
|
||||
}
|
||||
|
||||
/// If the specified pointer points to an object that we control, try to modify
|
||||
/// the object's alignment to PrefAlign. Returns a minimum known alignment of
|
||||
/// the value after the operation, which may be lower than PrefAlign.
|
||||
///
|
||||
/// Increating value alignment isn't often possible though. If alignment is
|
||||
/// important, a more reliable approach is to simply align all global variables
|
||||
/// and allocation instructions to their preferred alignment from the beginning.
|
||||
static Align tryEnforceAlignment(Value *V, Align PrefAlign,
|
||||
const DataLayout &DL) {
|
||||
Align llvm::tryEnforceAlignment(Value *V, Align PrefAlign,
|
||||
const DataLayout &DL) {
|
||||
V = V->stripPointerCasts();
|
||||
|
||||
if (AllocaInst *AI = dyn_cast<AllocaInst>(V)) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; Scalar type
|
||||
@@ -8,11 +8,11 @@
|
||||
define void @alloca_local(i8 %x, i32 %y) {
|
||||
; CHECK-LABEL: define void @alloca_local
|
||||
; CHECK-SAME: (i8 [[X:%.*]], i32 [[Y:%.*]]) {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 1
|
||||
; CHECK-NEXT: [[LOAD_I8:%.*]] = load i8, ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: [[LOAD_I32:%.*]] = load i32, ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: store i8 [[X]], ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: store i32 [[Y]], ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: [[LOAD_I8:%.*]] = load i8, ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: [[LOAD_I32:%.*]] = load i32, ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: store i8 [[X]], ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: store i32 [[Y]], ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%alloca = alloca i32, align 1
|
||||
@@ -38,10 +38,10 @@ define void @alloca_struct(i32 %x) {
|
||||
; CHECK-NEXT: [[ALLOCA_STRUCT:%.*]] = alloca [[STRUCT_PAIR:%.*]], align 8
|
||||
; CHECK-NEXT: [[GEP_0:%.*]] = getelementptr [[STRUCT_PAIR]], ptr [[ALLOCA_STRUCT]], i64 0, i32 1
|
||||
; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr { i32, i32 }, ptr [[GEP_0]], i64 0, i32 1
|
||||
; CHECK-NEXT: [[LOAD_2:%.*]] = load i32, ptr [[GEP_0]], align 1
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP_0]], align 1
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load i32, ptr [[GEP_1]], align 1
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP_1]], align 1
|
||||
; CHECK-NEXT: [[LOAD_2:%.*]] = load i32, ptr [[GEP_0]], align 8
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP_0]], align 8
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load i32, ptr [[GEP_1]], align 4
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP_1]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%alloca.struct = alloca %struct.pair
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt -S < %s -passes=no-op-function | FileCheck %s
|
||||
; RUN: opt -S < %s -passes=infer-alignment | FileCheck %s
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; load/store of null
|
||||
@@ -7,9 +7,9 @@
|
||||
|
||||
define void @load_null() {
|
||||
; CHECK-LABEL: define void @load_null() {
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr null unordered, align 4
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr null monotonic, align 4
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr null seq_cst, align 4
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr null unordered, align 4294967296
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr null monotonic, align 4294967296
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr null seq_cst, align 4294967296
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%x.0 = load atomic i32, ptr null unordered, align 4
|
||||
@@ -20,9 +20,9 @@ define void @load_null() {
|
||||
|
||||
define void @store_null() {
|
||||
; CHECK-LABEL: define void @store_null() {
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null unordered, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null monotonic, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null seq_cst, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null unordered, align 4294967296
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null monotonic, align 4294967296
|
||||
; CHECK-NEXT: store atomic i32 0, ptr null seq_cst, align 4294967296
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
store atomic i32 0, ptr null unordered, align 4
|
||||
@@ -38,9 +38,9 @@ define void @store_null() {
|
||||
|
||||
define void @load_nonnull() {
|
||||
; CHECK-LABEL: define void @load_nonnull() {
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr @c unordered, align 4
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr @c monotonic, align 4
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr @c seq_cst, align 4
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr @c unordered, align 8
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr @c monotonic, align 8
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr @c seq_cst, align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%x.0 = load atomic i32, ptr @c unordered, align 4
|
||||
@@ -51,9 +51,9 @@ define void @load_nonnull() {
|
||||
|
||||
define void @store_nonnull() {
|
||||
; CHECK-LABEL: define void @store_nonnull() {
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c unordered, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c monotonic, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c seq_cst, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c unordered, align 8
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c monotonic, align 8
|
||||
; CHECK-NEXT: store atomic i32 0, ptr @c seq_cst, align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
store atomic i32 0, ptr @c unordered, align 4
|
||||
@@ -69,9 +69,9 @@ define void @store_nonnull() {
|
||||
define void @load_alloca() {
|
||||
; CHECK-LABEL: define void @load_alloca() {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr [[ALLOCA]] unordered, align 1
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr [[ALLOCA]] monotonic, align 1
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr [[ALLOCA]] seq_cst, align 1
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load atomic i32, ptr [[ALLOCA]] unordered, align 4
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load atomic i32, ptr [[ALLOCA]] monotonic, align 4
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load atomic i32, ptr [[ALLOCA]] seq_cst, align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%alloca = alloca i32
|
||||
@@ -84,9 +84,9 @@ define void @load_alloca() {
|
||||
define void @store_alloca() {
|
||||
; CHECK-LABEL: define void @store_alloca() {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] unordered, align 1
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] monotonic, align 1
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] seq_cst, align 1
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] unordered, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] monotonic, align 4
|
||||
; CHECK-NEXT: store atomic i32 0, ptr [[ALLOCA]] seq_cst, align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%alloca = alloca i32
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
define void @attribute(ptr align 32 %a) {
|
||||
; CHECK-LABEL: define void @attribute
|
||||
; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[A]], align 1
|
||||
; CHECK-NEXT: store i32 123, ptr [[A]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: store i32 123, ptr [[A]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%load = load i32, ptr %a, align 1
|
||||
@@ -17,8 +17,8 @@ define void @attribute_through_call(ptr align 32 %a) {
|
||||
; CHECK-LABEL: define void @attribute_through_call
|
||||
; CHECK-SAME: (ptr align 32 [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[RES:%.*]] = call ptr @call(ptr [[A]])
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[RES]], align 1
|
||||
; CHECK-NEXT: store i32 123, ptr [[RES]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[RES]], align 32
|
||||
; CHECK-NEXT: store i32 123, ptr [[RES]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%res = call ptr @call(ptr %a)
|
||||
@@ -31,8 +31,8 @@ define void @attribute_return_value(ptr %a) {
|
||||
; CHECK-LABEL: define void @attribute_return_value
|
||||
; CHECK-SAME: (ptr [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[RES:%.*]] = call align 32 ptr @call(ptr [[A]])
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[RES]], align 1
|
||||
; CHECK-NEXT: store i32 123, ptr [[RES]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load i32, ptr [[RES]], align 32
|
||||
; CHECK-NEXT: store i32 123, ptr [[RES]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%res = call align 32 ptr @call(ptr %a)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
; A multi-dimensional array in a nested loop.inner doing vector stores that
|
||||
; aren't yet aligned. InferAlignment can understand the addressing in the
|
||||
@@ -21,8 +21,8 @@ define void @nested_loop() {
|
||||
; CHECK: loop.inner:
|
||||
; CHECK-NEXT: [[J:%.*]] = phi i64 [ 0, [[LOOP_OUTER]] ], [ [[J_NEXT:%.*]], [[LOOP_INNER_TAIL:%.*]] ]
|
||||
; CHECK-NEXT: [[GEP_1:%.*]] = getelementptr [1001 x [20000 x double]], ptr @Nice, i64 0, i64 [[I]], i64 [[J]]
|
||||
; CHECK-NEXT: store <2 x double> zeroinitializer, ptr [[GEP_1]], align 8
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <2 x double>, ptr [[GEP_1]], align 8
|
||||
; CHECK-NEXT: store <2 x double> zeroinitializer, ptr [[GEP_1]], align 16
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <2 x double>, ptr [[GEP_1]], align 16
|
||||
; CHECK-NEXT: [[GEP_2:%.*]] = getelementptr [1001 x [20001 x double]], ptr @Awkward, i64 0, i64 [[I]], i64 [[J]]
|
||||
; CHECK-NEXT: store <2 x double> zeroinitializer, ptr [[GEP_2]], align 8
|
||||
; CHECK-NEXT: [[LOAD_2:%.*]] = load <2 x double>, ptr [[GEP_2]], align 8
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
|
||||
; RUN: opt -passes=infer-alignment -S < %s | FileCheck %s
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; Array of pair
|
||||
@@ -18,8 +18,8 @@ define void @simple_pair(i64 %idx) {
|
||||
; CHECK-LABEL: define void @simple_pair
|
||||
; CHECK-SAME: (i64 [[IDX:%.*]]) {
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr inbounds [4 x %pair.simple], ptr @array.simple, i64 0, i64 [[IDX]], i32 1
|
||||
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: [[RES:%.*]] = load i32, ptr [[GEP]], align 8
|
||||
; CHECK-NEXT: store i32 0, ptr [[GEP]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%gep = getelementptr inbounds [4 x %pair.simple], ptr @array.simple, i64 0, i64 %idx, i32 1
|
||||
@@ -39,11 +39,11 @@ define void @simple_pair(i64 %idx) {
|
||||
|
||||
define void @load_nested() {
|
||||
; CHECK-LABEL: define void @load_nested() {
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load i32, ptr @array.array, align 4
|
||||
; CHECK-NEXT: [[X_0:%.*]] = load i32, ptr @array.array, align 16
|
||||
; CHECK-NEXT: [[X_1:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
|
||||
; CHECK-NEXT: [[X_2:%.*]] = load i32, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8
|
||||
; CHECK-NEXT: [[X_3:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
|
||||
; CHECK-NEXT: [[X_4:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
|
||||
; CHECK-NEXT: [[X_4:%.*]] = load i32, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%x.0 = load i32, ptr @array.array, align 4
|
||||
@@ -56,11 +56,11 @@ define void @load_nested() {
|
||||
|
||||
define void @store_nested() {
|
||||
; CHECK-LABEL: define void @store_nested() {
|
||||
; CHECK-NEXT: store i32 1, ptr @array.array, align 4
|
||||
; CHECK-NEXT: store i32 1, ptr @array.array, align 16
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 1), align 4
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 4
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr inbounds ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 2), align 8
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 3), align 4
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 4
|
||||
; CHECK-NEXT: store i32 1, ptr getelementptr ([3 x %pair.array], ptr @array.array, i64 0, i64 0, i32 0, i64 4), align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
store i32 1, ptr @array.array, align 4
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
define void @non_pow2_size(i177 %X) {
|
||||
; CHECK-LABEL: define void @non_pow2_size
|
||||
; CHECK-SAME: (i177 [[X:%.*]]) {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i177, align 1
|
||||
; CHECK-NEXT: [[L1:%.*]] = load i177, ptr [[A]], align 1
|
||||
; CHECK-NEXT: store i177 [[X]], ptr [[A]], align 1
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca i177, align 8
|
||||
; CHECK-NEXT: [[L1:%.*]] = load i177, ptr [[A]], align 8
|
||||
; CHECK-NEXT: store i177 [[X]], ptr [[A]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%A = alloca i177, align 1
|
||||
@@ -27,13 +27,13 @@ define void @load_vector_i4(i4 %X) {
|
||||
; CHECK-NEXT: [[PTR_2:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 4
|
||||
; CHECK-NEXT: [[PTR_3:%.*]] = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 8
|
||||
; CHECK-NEXT: [[RES_0:%.*]] = load i4, ptr [[PTR_0]], align 1
|
||||
; CHECK-NEXT: [[RES_1:%.*]] = load i4, ptr [[PTR_1]], align 1
|
||||
; CHECK-NEXT: [[RES_2:%.*]] = load i4, ptr [[PTR_2]], align 1
|
||||
; CHECK-NEXT: [[RES_3:%.*]] = load i4, ptr [[PTR_3]], align 1
|
||||
; CHECK-NEXT: [[RES_1:%.*]] = load i4, ptr [[PTR_1]], align 2
|
||||
; CHECK-NEXT: [[RES_2:%.*]] = load i4, ptr [[PTR_2]], align 4
|
||||
; CHECK-NEXT: [[RES_3:%.*]] = load i4, ptr [[PTR_3]], align 8
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_0]], align 1
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_1]], align 1
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_2]], align 1
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_3]], align 1
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_1]], align 2
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_2]], align 4
|
||||
; CHECK-NEXT: store i4 [[X]], ptr [[PTR_3]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%ptr.0 = getelementptr [16 x <2 x i4>], ptr @vector_i4, i64 0, i64 1
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; Simple test
|
||||
@@ -12,8 +12,8 @@ define void @simple_forwardpropagate(ptr %a) {
|
||||
; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
|
||||
; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
|
||||
; CHECK-NEXT: tail call void @llvm.assume(i1 [[MASKCOND]])
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%ptrint = ptrtoint ptr %a to i64
|
||||
@@ -30,8 +30,8 @@ define void @simple_forwardpropagate(ptr %a) {
|
||||
define void @simple_backpropagate(ptr %a) {
|
||||
; CHECK-LABEL: define void @simple_backpropagate
|
||||
; CHECK-SAME: (ptr [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 32
|
||||
; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
|
||||
; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
|
||||
; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
|
||||
@@ -53,8 +53,8 @@ define void @simple_forwardpropagate_bundle(ptr %a) {
|
||||
; CHECK-LABEL: define void @simple_forwardpropagate_bundle
|
||||
; CHECK-SAME: (ptr [[A:%.*]]) {
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
call void @llvm.assume(i1 true) ["align"(ptr %a, i32 32)]
|
||||
@@ -66,8 +66,8 @@ define void @simple_forwardpropagate_bundle(ptr %a) {
|
||||
define void @simple_backpropagate_bundle(ptr %a) {
|
||||
; CHECK-LABEL: define void @simple_backpropagate_bundle
|
||||
; CHECK-SAME: (ptr [[A:%.*]]) {
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: store i32 345, ptr [[A]], align 32
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
@@ -97,10 +97,10 @@ define void @loop_forwardpropagate(ptr %a, ptr %b) {
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ]
|
||||
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]]
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 4
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 64
|
||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1
|
||||
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]]
|
||||
; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 4
|
||||
; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 64
|
||||
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 16
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
|
||||
@@ -149,10 +149,10 @@ define void @loop_forwardpropagate_bundle(ptr %a, ptr %b) {
|
||||
; CHECK: for.body:
|
||||
; CHECK-NEXT: [[I:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[I_NEXT:%.*]], [[FOR_BODY]] ]
|
||||
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i32, ptr [[B]], i64 [[I]]
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 4
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[GEP_B]], align 64
|
||||
; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[LOAD_B]], 1
|
||||
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i32, ptr [[A]], i64 [[I]]
|
||||
; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 4
|
||||
; CHECK-NEXT: store i32 [[ADD]], ptr [[GEP_A]], align 64
|
||||
; CHECK-NEXT: [[I_NEXT]] = add nuw nsw i64 [[I]], 16
|
||||
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i64 [[I_NEXT]], 1648
|
||||
; CHECK-NEXT: br i1 [[CMP]], label [[FOR_BODY]], label [[FOR_END:%.*]]
|
||||
@@ -190,11 +190,11 @@ define void @complex_backpropagate(ptr %a, ptr %b, ptr %c) {
|
||||
; CHECK-LABEL: define void @complex_backpropagate
|
||||
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i64, align 8
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4
|
||||
; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 32
|
||||
; CHECK-NEXT: [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false)
|
||||
; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 8
|
||||
; CHECK-NEXT: [[PTRINT:%.*]] = ptrtoint ptr [[A]] to i64
|
||||
; CHECK-NEXT: [[MASKEDPTR:%.*]] = and i64 [[PTRINT]], 31
|
||||
; CHECK-NEXT: [[MASKCOND:%.*]] = icmp eq i64 [[MASKEDPTR]], 0
|
||||
@@ -222,11 +222,11 @@ define void @complex_backpropagate_bundle(ptr %a, ptr %b, ptr %c) {
|
||||
; CHECK-LABEL: define void @complex_backpropagate_bundle
|
||||
; CHECK-SAME: (ptr [[A:%.*]], ptr [[B:%.*]], ptr [[C:%.*]]) {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca i64, align 8
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load i32, ptr [[A]], align 32
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load i32, ptr [[B]], align 4
|
||||
; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 4
|
||||
; CHECK-NEXT: store i32 [[LOAD_B]], ptr [[A]], align 32
|
||||
; CHECK-NEXT: [[OBJ_SIZE:%.*]] = call i64 @llvm.objectsize.i64.p0(ptr [[C]], i1 false, i1 false, i1 false)
|
||||
; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 4
|
||||
; CHECK-NEXT: store i64 [[OBJ_SIZE]], ptr [[ALLOCA]], align 8
|
||||
; CHECK-NEXT: tail call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i32 32) ]
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
; ------------------------------------------------------------------------------
|
||||
; load instructions
|
||||
@@ -11,9 +11,9 @@ define void @load(ptr align 1 %ptr) {
|
||||
; CHECK-NEXT: [[ALIGNED_0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -2)
|
||||
; CHECK-NEXT: [[ALIGNED_1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -4)
|
||||
; CHECK-NEXT: [[ALIGNED_2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
|
||||
; CHECK-NEXT: [[LOAD_0:%.*]] = load <16 x i8>, ptr [[ALIGNED_0]], align 1
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <16 x i8>, ptr [[ALIGNED_1]], align 1
|
||||
; CHECK-NEXT: [[LOAD_2:%.*]] = load <16 x i8>, ptr [[ALIGNED_2]], align 1
|
||||
; CHECK-NEXT: [[LOAD_0:%.*]] = load <16 x i8>, ptr [[ALIGNED_0]], align 2
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <16 x i8>, ptr [[ALIGNED_1]], align 4
|
||||
; CHECK-NEXT: [[LOAD_2:%.*]] = load <16 x i8>, ptr [[ALIGNED_2]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%aligned.0 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -2)
|
||||
@@ -37,9 +37,9 @@ define void @store(ptr align 1 %ptr) {
|
||||
; CHECK-NEXT: [[ALIGNED_0:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -2)
|
||||
; CHECK-NEXT: [[ALIGNED_1:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -4)
|
||||
; CHECK-NEXT: [[ALIGNED_2:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_0]], align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_1]], align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_2]], align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_0]], align 2
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_1]], align 4
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED_2]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%aligned.0 = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -2)
|
||||
@@ -62,8 +62,8 @@ define void @ptrmask_overaligned(ptr align 16 %ptr) {
|
||||
; CHECK-LABEL: define void @ptrmask_overaligned
|
||||
; CHECK-SAME: (ptr align 16 [[PTR:%.*]]) {
|
||||
; CHECK-NEXT: [[ALIGNED:%.*]] = call ptr @llvm.ptrmask.p0.i64(ptr [[PTR]], i64 -8)
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <16 x i8>, ptr [[ALIGNED]], align 16
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[ALIGNED]], align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%aligned = call ptr @llvm.ptrmask.p0.i64(ptr %ptr, i64 -8)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
|
||||
; RUN: opt -passes=infer-alignment -S < %s | FileCheck %s
|
||||
|
||||
define void @load_undef_null(ptr %P) {
|
||||
; CHECK-LABEL: define void @load_undef_null
|
||||
; CHECK-SAME: (ptr [[P:%.*]]) {
|
||||
; CHECK-NEXT: [[RET_0:%.*]] = load i32, ptr undef, align 4
|
||||
; CHECK-NEXT: [[RET_1:%.*]] = load i32, ptr null, align 4
|
||||
; CHECK-NEXT: [[RET_1:%.*]] = load i32, ptr null, align 4294967296
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%ret.0 = load i32, ptr undef
|
||||
@@ -17,7 +17,7 @@ define void @store_undef_null(ptr %P) {
|
||||
; CHECK-LABEL: define void @store_undef_null
|
||||
; CHECK-SAME: (ptr [[P:%.*]]) {
|
||||
; CHECK-NEXT: store i32 123, ptr undef, align 4
|
||||
; CHECK-NEXT: store i32 124, ptr null, align 4
|
||||
; CHECK-NEXT: store i32 124, ptr null, align 4294967296
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
store i32 123, ptr undef
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
; InferAlignment should be able to prove vector alignment in the
|
||||
; presence of a few mild address computation tricks.
|
||||
@@ -12,8 +12,8 @@ define void @alloca(<2 x i64> %y) {
|
||||
; CHECK-LABEL: define void @alloca
|
||||
; CHECK-SAME: (<2 x i64> [[Y:%.*]]) {
|
||||
; CHECK-NEXT: [[ALLOCA:%.*]] = alloca <2 x i64>, align 16
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[ALLOCA]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[ALLOCA]], align 16
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[ALLOCA]], align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%alloca = alloca <2 x i64>
|
||||
@@ -31,8 +31,8 @@ define void @alloca(<2 x i64> %y) {
|
||||
define void @global(<2 x i64> %y) {
|
||||
; CHECK-LABEL: define void @global
|
||||
; CHECK-SAME: (<2 x i64> [[Y:%.*]]) {
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr @x.vector, align 1
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr @x.vector, align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr @x.vector, align 16
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr @x.vector, align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%load = load <2 x i64>, ptr @x.vector, align 1
|
||||
@@ -55,8 +55,8 @@ define void @vector_singular(i32 %i, <2 x i64> %y) {
|
||||
; CHECK-LABEL: define void @vector_singular
|
||||
; CHECK-SAME: (i32 [[I:%.*]], <2 x i64> [[Y:%.*]]) {
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr <2 x i64>, ptr @vector, i32 [[I]]
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%gep = getelementptr <2 x i64>, ptr @vector, i32 %i
|
||||
@@ -73,8 +73,8 @@ define void @vector_array(i32 %i, i32 %j, <2 x i64> %y) {
|
||||
; CHECK-LABEL: define void @vector_array
|
||||
; CHECK-SAME: (i32 [[I:%.*]], i32 [[J:%.*]], <2 x i64> [[Y:%.*]]) {
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [13 x <2 x i64>], ptr @vector.arr, i32 [[I]], i32 [[J]]
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <2 x i64>, ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: store <2 x i64> [[Y]], ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%gep = getelementptr [13 x <2 x i64>], ptr @vector.arr, i32 %i, i32 %j
|
||||
@@ -93,11 +93,11 @@ define void @vector_array(i32 %i, i32 %j, <2 x i64> %y) {
|
||||
|
||||
define void @nonvector_array() {
|
||||
; CHECK-LABEL: define void @nonvector_array() {
|
||||
; CHECK-NEXT: [[LOAD_0:%.*]] = load <16 x i8>, ptr @x.array, align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr @x.array, align 1
|
||||
; CHECK-NEXT: [[LOAD_0:%.*]] = load <16 x i8>, ptr @x.array, align 16
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr @x.array, align 16
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr [4 x i32], ptr @x.array, i16 0, i16 2
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <16 x i8>, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[GEP]], align 1
|
||||
; CHECK-NEXT: [[LOAD_1:%.*]] = load <16 x i8>, ptr [[GEP]], align 8
|
||||
; CHECK-NEXT: store <16 x i8> zeroinitializer, ptr [[GEP]], align 8
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%load.0 = load <16 x i8>, ptr @x.array, align 1
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt < %s -passes=no-op-function -S | FileCheck %s
|
||||
; RUN: opt < %s -passes=infer-alignment -S | FileCheck %s
|
||||
|
||||
define void @load_volatile() {
|
||||
; CHECK-LABEL: define void @load_volatile() {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca { i32 }, align 8
|
||||
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load volatile i32, ptr [[A]], align 4
|
||||
; CHECK-NEXT: [[LOAD_A:%.*]] = load volatile i32, ptr [[A]], align 8
|
||||
; CHECK-NEXT: [[LOAD_B:%.*]] = load volatile i32, ptr [[B]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
@@ -20,7 +20,7 @@ define void @store_volatile() {
|
||||
; CHECK-LABEL: define void @store_volatile() {
|
||||
; CHECK-NEXT: [[A:%.*]] = alloca { i32 }, align 8
|
||||
; CHECK-NEXT: [[B:%.*]] = alloca i32, align 4
|
||||
; CHECK-NEXT: store volatile i32 123, ptr [[A]], align 4
|
||||
; CHECK-NEXT: store volatile i32 123, ptr [[A]], align 8
|
||||
; CHECK-NEXT: store volatile i32 123, ptr [[B]], align 4
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 2
|
||||
; RUN: opt -passes=no-op-function -S < %s | FileCheck %s
|
||||
; RUN: opt -passes=infer-alignment -S < %s | FileCheck %s
|
||||
|
||||
; <4 x i32> -> 16 byte alignment
|
||||
define void @alignment_sustain(ptr align 16 %ptr) {
|
||||
@@ -23,8 +23,8 @@ define void @alignment_increase(ptr align 32 %ptr) {
|
||||
; CHECK-LABEL: define void @alignment_increase
|
||||
; CHECK-SAME: (ptr align 32 [[PTR:%.*]]) {
|
||||
; CHECK-NEXT: [[GEP:%.*]] = getelementptr <vscale x 8 x i32>, ptr [[PTR]], i32 3
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <8 x i32>, ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: store <8 x i32> zeroinitializer, ptr [[GEP]], align 16
|
||||
; CHECK-NEXT: [[LOAD:%.*]] = load <8 x i32>, ptr [[GEP]], align 32
|
||||
; CHECK-NEXT: store <8 x i32> zeroinitializer, ptr [[GEP]], align 32
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
%gep = getelementptr <vscale x 8 x i32>, ptr %ptr, i32 3
|
||||
|
||||
Reference in New Issue
Block a user