auto VisitValueCB = [&](Value &V, const Instruction *,
AAMemoryLocation::StateType &T,
bool Stripped) -> bool {
+ // TODO: recognize the TBAA used for constant accesses.
MemoryLocationsKind MLK = NO_LOCATIONS;
assert(!isa<GEPOperator>(V) && "GEPs should have been stripped.");
if (isa<UndefValue>(V))
else
MLK = NO_ARGUMENT_MEM;
} else if (auto *GV = dyn_cast<GlobalValue>(&V)) {
+ // Reading constant memory is not treated as a read "effect" by the
+ // function attr pass so we won't neither. Constants defined by TBAA are
+ // similar. (We know we do not write it because it is constant.)
+ if (auto *GVar = dyn_cast<GlobalVariable>(GV))
+ if (GVar->isConstant())
+ return true;
+
if (GV->hasLocalLinkage())
MLK = NO_GLOBAL_INTERNAL_MEM;
else
@G = constant %T { i32 0, i32 0, i32 17, i32 25 }
define internal i32 @test(%T* %p) {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readonly willreturn
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@test
; IS__TUNIT____-SAME: () [[ATTR0:#.*]] {
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[V:%.*]] = add i32 [[A]], [[B]]
; IS__TUNIT____-NEXT: ret i32 [[V]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@test
; IS__CGSCC____-SAME: () [[ATTR0:#.*]] {
; IS__CGSCC____-NEXT: entry:
}
define i32 @caller() {
-; IS__TUNIT____: Function Attrs: nofree nosync nounwind readonly willreturn
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
; IS__TUNIT____-LABEL: define {{[^@]+}}@caller
; IS__TUNIT____-SAME: () [[ATTR0]] {
; IS__TUNIT____-NEXT: entry:
; IS__TUNIT____-NEXT: [[V:%.*]] = call i32 @test() [[ATTR0]]
; IS__TUNIT____-NEXT: ret i32 [[V]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readonly willreturn
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@caller
; IS__CGSCC____-SAME: () [[ATTR0]] {
; IS__CGSCC____-NEXT: entry:
@G = constant i32 0
define internal i32 @a(i32* %x) {
-; CHECK: Function Attrs: nofree nosync nounwind readonly willreturn
+; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK-LABEL: define {{[^@]+}}@a
; CHECK-SAME: () [[ATTR0:#.*]] {
; CHECK-NEXT: entry:
}
define i32 @b() {
-; CHECK: Function Attrs: nofree nosync nounwind readonly willreturn
+; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK-LABEL: define {{[^@]+}}@b
; CHECK-SAME: () [[ATTR0]] {
; CHECK-NEXT: entry:
}
define i32 @c() {
-; CHECK: Function Attrs: nofree nosync nounwind readonly willreturn
+; CHECK: Function Attrs: nofree nosync nounwind readnone willreturn
; CHECK-LABEL: define {{[^@]+}}@c
; CHECK-SAME: () [[ATTR0]] {
; CHECK-NEXT: entry:
call void @escape_i8(i8* %abc9)
ret void
}
+
+@constant_mem = external dso_local constant i32, align 4
+define i32 @read_only_constant_mem() {
+; IS__TUNIT____: Function Attrs: nofree nosync nounwind readnone willreturn
+; IS__TUNIT____-LABEL: define {{[^@]+}}@read_only_constant_mem
+; IS__TUNIT____-SAME: () [[ATTR1]] {
+; IS__TUNIT____-NEXT: [[L:%.*]] = load i32, i32* @constant_mem, align 4
+; IS__TUNIT____-NEXT: ret i32 [[L]]
+;
+; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC____-LABEL: define {{[^@]+}}@read_only_constant_mem
+; IS__CGSCC____-SAME: () [[ATTR1]] {
+; IS__CGSCC____-NEXT: [[L:%.*]] = load i32, i32* @constant_mem, align 4
+; IS__CGSCC____-NEXT: ret i32 [[L]]
+;
+ %l = load i32, i32* @constant_mem
+ ret i32 %l
+}