// See if the alias was forward referenced, if so, prepare to replace the
// forward reference.
if (!Name.empty()) {
- GVal = M->getNamedValue(Name);
- if (GVal) {
- if (!ForwardRefVals.erase(Name))
- return error(NameLoc, "redefinition of global '@" + Name + "'");
+ auto I = ForwardRefVals.find(Name);
+ if (I != ForwardRefVals.end()) {
+ GVal = I->second.first;
+ ForwardRefVals.erase(Name);
+ } else if (M->getNamedValue(Name)) {
+ return error(NameLoc, "redefinition of global '@" + Name + "'");
}
} else {
auto I = ForwardRefValIDs.find(NumberedVals.size());
// See if the global was forward referenced, if so, use the global.
if (!Name.empty()) {
- GVal = M->getNamedValue(Name);
- if (GVal) {
- if (!ForwardRefVals.erase(Name))
- return error(NameLoc, "redefinition of global '@" + Name + "'");
+ auto I = ForwardRefVals.find(Name);
+ if (I != ForwardRefVals.end()) {
+ GVal = I->second.first;
+ ForwardRefVals.erase(I);
+ } else if (M->getNamedValue(Name)) {
+ return error(NameLoc, "redefinition of global '@" + Name + "'");
}
} else {
auto I = ForwardRefValIDs.find(NumberedVals.size());
}
}
- GlobalVariable *GV;
- if (!GVal) {
- GV = new GlobalVariable(*M, Ty, false, GlobalValue::ExternalLinkage, nullptr,
- Name, nullptr, GlobalVariable::NotThreadLocal,
- AddrSpace);
- } else {
- if (GVal->getValueType() != Ty)
- return error(
- TyLoc,
- "forward reference and definition of global have different types");
-
- GV = cast<GlobalVariable>(GVal);
-
- // Move the forward-reference to the correct spot in the module.
- M->getGlobalList().splice(M->global_end(), M->getGlobalList(), GV);
- }
+ GlobalVariable *GV = new GlobalVariable(
+ *M, Ty, false, GlobalValue::ExternalLinkage, nullptr, Name, nullptr,
+ GlobalVariable::NotThreadLocal, AddrSpace);
if (Name.empty())
NumberedVals.push_back(GV);
GV->setThreadLocalMode(TLM);
GV->setUnnamedAddr(UnnamedAddr);
+ if (GVal) {
+ if (!GVal->getType()->isOpaque() && GVal->getValueType() != Ty)
+ return error(
+ TyLoc,
+ "forward reference and definition of global have different types");
+
+ GVal->replaceAllUsesWith(GV);
+ GVal->eraseFromParent();
+ }
+
// parse attributes on the global.
while (Lex.getKind() == lltok::comma) {
Lex.Lex();
// GlobalValue Reference/Resolution Routines.
//===----------------------------------------------------------------------===//
-static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy,
- const std::string &Name) {
- if (auto *FT = dyn_cast<FunctionType>(PTy->getElementType()))
+static inline GlobalValue *createGlobalFwdRef(Module *M, PointerType *PTy) {
+ // For opaque pointers, the used global type does not matter. We will later
+ // RAUW it with a global/function of the correct type.
+ if (PTy->isOpaque())
+ return new GlobalVariable(*M, Type::getInt8Ty(M->getContext()), false,
+ GlobalValue::ExternalWeakLinkage, nullptr, "",
+ nullptr, GlobalVariable::NotThreadLocal,
+ PTy->getAddressSpace());
+
+ if (auto *FT = dyn_cast<FunctionType>(PTy->getPointerElementType()))
return Function::Create(FT, GlobalValue::ExternalWeakLinkage,
- PTy->getAddressSpace(), Name, M);
+ PTy->getAddressSpace(), "", M);
else
- return new GlobalVariable(*M, PTy->getElementType(), false,
- GlobalValue::ExternalWeakLinkage, nullptr, Name,
+ return new GlobalVariable(*M, PTy->getPointerElementType(), false,
+ GlobalValue::ExternalWeakLinkage, nullptr, "",
nullptr, GlobalVariable::NotThreadLocal,
PTy->getAddressSpace());
}
checkValidVariableType(Loc, "@" + Name, Ty, Val, IsCall));
// Otherwise, create a new forward reference for this value and remember it.
- GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, Name);
+ GlobalValue *FwdVal = createGlobalFwdRef(M, PTy);
ForwardRefVals[Name] = std::make_pair(FwdVal, Loc);
return FwdVal;
}
checkValidVariableType(Loc, "@" + Twine(ID), Ty, Val, IsCall));
// Otherwise, create a new forward reference for this value and remember it.
- GlobalValue *FwdVal = createGlobalFwdRef(M, PTy, "");
+ GlobalValue *FwdVal = createGlobalFwdRef(M, PTy);
ForwardRefValIDs[ID] = std::make_pair(FwdVal, Loc);
return FwdVal;
}
PointerType *PFT = PointerType::get(FT, AddrSpace);
Fn = nullptr;
+ GlobalValue *FwdFn = nullptr;
if (!FunctionName.empty()) {
// If this was a definition of a forward reference, remove the definition
// from the forward reference table and fill in the forward ref.
auto FRVI = ForwardRefVals.find(FunctionName);
if (FRVI != ForwardRefVals.end()) {
- Fn = M->getFunction(FunctionName);
- if (!Fn)
- return error(FRVI->second.second, "invalid forward reference to "
- "function as global value!");
- if (Fn->getType() != PFT)
- return error(FRVI->second.second,
- "invalid forward reference to "
- "function '" +
- FunctionName +
- "' with wrong type: "
- "expected '" +
- getTypeString(PFT) + "' but was '" +
- getTypeString(Fn->getType()) + "'");
+ FwdFn = FRVI->second.first;
+ if (!FwdFn->getType()->isOpaque()) {
+ if (!FwdFn->getType()->getPointerElementType()->isFunctionTy())
+ return error(FRVI->second.second, "invalid forward reference to "
+ "function as global value!");
+ if (FwdFn->getType() != PFT)
+ return error(FRVI->second.second,
+ "invalid forward reference to "
+ "function '" +
+ FunctionName +
+ "' with wrong type: "
+ "expected '" +
+ getTypeString(PFT) + "' but was '" +
+ getTypeString(FwdFn->getType()) + "'");
+ }
ForwardRefVals.erase(FRVI);
} else if ((Fn = M->getFunction(FunctionName))) {
// Reject redefinitions.
// types agree.
auto I = ForwardRefValIDs.find(NumberedVals.size());
if (I != ForwardRefValIDs.end()) {
- Fn = cast<Function>(I->second.first);
- if (Fn->getType() != PFT)
+ FwdFn = cast<Function>(I->second.first);
+ if (!FwdFn->getType()->isOpaque() && FwdFn->getType() != PFT)
return error(NameLoc, "type of definition and forward reference of '@" +
Twine(NumberedVals.size()) +
"' disagree: "
"expected '" +
getTypeString(PFT) + "' but was '" +
- getTypeString(Fn->getType()) + "'");
+ getTypeString(FwdFn->getType()) + "'");
ForwardRefValIDs.erase(I);
}
}
- if (!Fn)
- Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace,
- FunctionName, M);
- else // Move the forward-reference to the correct spot in the module.
- M->getFunctionList().splice(M->end(), M->getFunctionList(), Fn);
+ Fn = Function::Create(FT, GlobalValue::ExternalLinkage, AddrSpace,
+ FunctionName, M);
assert(Fn->getAddressSpace() == AddrSpace && "Created function in wrong AS");
"redefinition of argument '%" + ArgList[i].Name + "'");
}
+ if (FwdFn) {
+ FwdFn->replaceAllUsesWith(Fn);
+ FwdFn->eraseFromParent();
+ }
+
if (IsDefine)
return false;
// We may have lost some users.
return {};
- bool GetsReversed =
- !isa<GlobalVariable>(V) && !isa<Function>(V) && !isa<BasicBlock>(V);
+ // When referencing a value before its declaration, a temporary value is
+ // created, which will later be RAUWed with the actual value. This reverses
+ // the use list. This happens for all values apart from basic blocks.
+ bool GetsReversed = !isa<BasicBlock>(V);
if (auto *BA = dyn_cast<BlockAddress>(V))
ID = OM.lookup(BA->getBasicBlock());
llvm::sort(List, [&](const Entry &L, const Entry &R) {
; WARNING: warning: prototype-less function used with conflicting signatures: foo
; CHECK-LABEL: @call_with_conflicting_prototypes
-; CHECK: %call1 = call i64 bitcast (i64 (i32, i32)* @foo to i64 (i32)*)(i32 42)
-; CHECK: %call2 = call i64 @foo(i32 42, i32 43)
+; CHECK: %call1 = call i64 @foo(i32 42)
+; CHECK: %call2 = call i64 bitcast (i64 (i32)* @foo to i64 (i32, i32)*)(i32 42, i32 43)
define void @call_with_conflicting_prototypes() {
%call1 = call i64 bitcast (i64 (...)* @foo to i64 (i32)*)(i32 42)
%call2 = call i64 bitcast (i64 (...)* @foo to i64 (i32, i32)*)(i32 42, i32 43)
ret void
}
-; CHECK: declare extern_weak i64 @foo(i32, i32)
+; CHECK: declare extern_weak i64 @foo(i32)
declare extern_weak i64 @foo(...) #1
; CHECK-NOT: attributes {{.*}} = { {{.*}}"no-prototype"{{.*}} }
; CHECK-LABEL: define {{[^@]+}}@f
; CHECK-SAME: (ptr [[P:%.*]]) {
; CHECK-NEXT: [[A:%.*]] = alloca i17, align 4
+; CHECK-NEXT: call void @fn.fwd(i32 0)
+; CHECK-NEXT: store i32 0, ptr @g.fwd, align 4
; CHECK-NEXT: ret void
;
%a = alloca i17
+ call void @fn.fwd(i32 0)
+ store i32 0, i32* @g.fwd
ret void
}
+
+@g.fwd = global i32 0
+declare void @fn.fwd(i32)
; IS__TUNIT____-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR0]], !range [[RNG0:![0-9]+]]
; IS__TUNIT____-NEXT: ret i64 [[CALL2]]
;
-; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
-; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2
-; IS__CGSCC____-SAME: () #[[ATTR0:[0-9]+]] {
-; IS__CGSCC____-NEXT: entry:
-; IS__CGSCC____-NEXT: ret i64 undef
+; IS__CGSCC_OPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_OPM-LABEL: define {{[^@]+}}@fn2
+; IS__CGSCC_OPM-SAME: () #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_OPM-NEXT: entry:
+; IS__CGSCC_OPM-NEXT: [[CONV:%.*]] = sext i32 undef to i64
+; IS__CGSCC_OPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__CGSCC_OPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]]
+; IS__CGSCC_OPM-NEXT: ret i64 [[CALL2]]
+;
+; IS__CGSCC_NPM: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
+; IS__CGSCC_NPM-LABEL: define {{[^@]+}}@fn2
+; IS__CGSCC_NPM-SAME: () #[[ATTR0:[0-9]+]] {
+; IS__CGSCC_NPM-NEXT: entry:
+; IS__CGSCC_NPM-NEXT: [[CONV:%.*]] = sext i32 undef to i64
+; IS__CGSCC_NPM-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
+; IS__CGSCC_NPM-NEXT: [[CALL2:%.*]] = call i64 @fn1(i64 undef) #[[ATTR1:[0-9]+]], !range [[RNG0:![0-9]+]]
+; IS__CGSCC_NPM-NEXT: ret i64 [[CALL2]]
;
entry:
%conv = sext i32 undef to i64
;
; IS__CGSCC____: Function Attrs: nofree norecurse nosync nounwind readnone willreturn
; IS__CGSCC____-LABEL: define {{[^@]+}}@fn2b
-; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0]] {
+; IS__CGSCC____-SAME: (i32 [[ARG:%.*]]) #[[ATTR0:[0-9]+]] {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[CONV:%.*]] = sext i32 [[ARG]] to i64
; IS__CGSCC____-NEXT: [[DIV:%.*]] = sdiv i64 8, [[CONV]]
; IS__CGSCC____-SAME: (void (i8*)* noundef nonnull [[FP:%.*]]) {
; IS__CGSCC____-NEXT: entry:
; IS__CGSCC____-NEXT: [[A:%.*]] = alloca i32, align 4
+; IS__CGSCC____-NEXT: [[TMP:%.*]] = bitcast i32* [[A]] to i8*
; IS__CGSCC____-NEXT: call void @foo(i32* noalias nocapture nofree noundef nonnull writeonly align 4 dereferenceable(4) [[A]]) #[[ATTR1:[0-9]+]]
; IS__CGSCC____-NEXT: call void [[FP]](i8* bitcast (void (i32*)* @foo to i8*))
; IS__CGSCC____-NEXT: call void @callback1(void (i32*)* noundef nonnull @foo)
define dso_local i32 @bar(i32 %x, i32 %y) {
; COMMON-LABEL: @bar
-; FORCE: %call = call i32 @foo.2(i32 %x, i32* @A)
-; FORCE: %call1 = call i32 @foo.1(i32 %y, i32* @B)
+; FORCE: %call = call i32 @foo.1(i32 %x, i32* @A)
+; FORCE: %call1 = call i32 @foo.2(i32 %y, i32* @B)
; DISABLED-NOT: %call1 = call i32 @foo.1(
entry:
%tobool = icmp ne i32 %x, 0
; FORCE: define internal i32 @foo.1(i32 %x, i32* %b) {
; FORCE-NEXT: entry:
-; FORCE-NEXT: %0 = load i32, i32* @B, align 4
+; FORCE-NEXT: %0 = load i32, i32* @A, align 4
; FORCE-NEXT: %add = add nsw i32 %x, %0
; FORCE-NEXT: ret i32 %add
; FORCE-NEXT: }
; FORCE: define internal i32 @foo.2(i32 %x, i32* %b) {
; FORCE-NEXT: entry:
-; FORCE-NEXT: %0 = load i32, i32* @A, align 4
+; FORCE-NEXT: %0 = load i32, i32* @B, align 4
; FORCE-NEXT: %add = add nsw i32 %x, %0
; FORCE-NEXT: ret i32 %add
; FORCE-NEXT: }
; CHECK: define internal i32 @foo.1(i32 %x, i32* %b, i32* %c) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: %0 = load i32, i32* @B, align 4
+; CHECK-NEXT: %0 = load i32, i32* @A, align 4
; CHECK-NEXT: %add = add nsw i32 %x, %0
; CHECK-NEXT: %1 = load i32, i32* %c, align 4
; CHECK-NEXT: %add1 = add nsw i32 %add, %1
; CHECK: define internal i32 @foo.2(i32 %x, i32* %b, i32* %c) {
; CHECK-NEXT: entry:
-; CHECK-NEXT: %0 = load i32, i32* @A, align 4
+; CHECK-NEXT: %0 = load i32, i32* @B, align 4
; CHECK-NEXT: %add = add nsw i32 %x, %0
; CHECK-NEXT: %1 = load i32, i32* %c, align 4
; CHECK-NEXT: %add1 = add nsw i32 %add, %1
; CHECK: define internal void @__cfi_global_var_init() section ".text.startup" {
; CHECK-NEXT: entry:
-; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8
-; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8
-; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x3, align 8
-; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x2, align 8
; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x, align 8
+; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x2, align 8
+; CHECK-NEXT: store void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()** @x3, align 8
+; CHECK-NEXT: store void ()* bitcast (i8* getelementptr (i8, i8* bitcast (void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null) to i8*), i64 42) to void ()*), void ()** @x4, align 8
+; CHECK-NEXT: store { void ()*, void ()*, i32 } { void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), void ()* select (i1 icmp ne (void ()* @f, void ()* null), void ()* @[[JT]], void ()* null), i32 42 }, { void ()*, void ()*, i32 }* @s, align 8
; CHECK-NEXT: ret void
; CHECK-NEXT: }
target triple = "x86_64-unknown-linux"
; CHECK: @0 = private constant { i32, [0 x i8], i32 } { i32 1, [0 x i8] zeroinitializer, i32 2 }
-; CHECK: @f1 = alias void (), void ()* @.cfi.jumptable
-; CHECK: @f2 = alias void (), bitcast ([8 x i8]* getelementptr inbounds ([2 x [8 x i8]], [2 x [8 x i8]]* bitcast (void ()* @.cfi.jumptable to [2 x [8 x i8]]*), i64 0, i64 1) to void ()*)
; CHECK: @g1 = alias i32, getelementptr inbounds ({ i32, [0 x i8], i32 }, { i32, [0 x i8], i32 }* @0, i32 0, i32 0)
; CHECK: @g2 = alias i32, getelementptr inbounds ({ i32, [0 x i8], i32 }, { i32, [0 x i8], i32 }* @0, i32 0, i32 2)
+; CHECK: @f1 = alias void (), void ()* @.cfi.jumptable
+; CHECK: @f2 = alias void (), bitcast ([8 x i8]* getelementptr inbounds ([2 x [8 x i8]], [2 x [8 x i8]]* bitcast (void ()* @.cfi.jumptable to [2 x [8 x i8]]*), i64 0, i64 1) to void ()*)
@g1 = constant i32 1
@g2 = constant i32 2
;
; This will delete all but the first parallel region
-; CHECK: remark: parallel_deletion_remarks.c:14:1: Parallel region in delete_parallel deleted
-; CHECK: remark: parallel_deletion_remarks.c:12:1: Parallel region in delete_parallel deleted
; CHECK: remark: parallel_deletion_remarks.c:10:1: Parallel region in delete_parallel deleted
+; CHECK: remark: parallel_deletion_remarks.c:12:1: Parallel region in delete_parallel deleted
+; CHECK: remark: parallel_deletion_remarks.c:14:1: Parallel region in delete_parallel deleted
define dso_local void @delete_parallel() local_unnamed_addr !dbg !15 {
call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined. to void (i32*, i32*, ...)*)), !dbg !18
call void (%struct.ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(%struct.ident_t* nonnull @0, i32 0, void (i32*, i32*, ...)* bitcast (void (i32*, i32*)* @.omp_outlined..2 to void (i32*, i32*, ...)*)), !dbg !19
ret i32 %result
}
-; CHECK-LABEL: define internal void @branch_funnel(i8*
-; CHECK: define hidden void @__typeid_typeid1_0_branch_funnel(i8* nest %0, ...)
+; CHECK-LABEL: define hidden void @__typeid_typeid1_0_branch_funnel(i8* nest %0, ...)
; CHECK-NEXT: musttail call void (...) @llvm.icall.branch.funnel(i8* %0, i8* bitcast ([1 x i8*]* {{(nonnull )?}}@vt1_1 to i8*), i32 (i8*, i32)* {{(nonnull )?}}@vf1_1, i8* bitcast ([1 x i8*]* {{(nonnull )?}}@vt1_2 to i8*), i32 (i8*, i32)* {{(nonnull )?}}@vf1_2, ...)
+; CHECK: define internal void @branch_funnel(i8*
+
declare i1 @llvm.type.test(i8*, metadata)
declare void @llvm.assume(i1)
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
-; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
+; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
@vt1 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf1i32 to i8*)
], section "vt1sec", !type !0
-; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
+; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
@vt2 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
], !type !0
-; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [5 x i8], [3 x i8*], [0 x i8] } { [5 x i8] c"\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]]
+; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [5 x i8], [3 x i8*], [0 x i8] } { [5 x i8] c"\03\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, align 1, !type [[T5:![0-9]+]]
@vt3 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf3i32 to i8*)
], align 1, !type !0
-; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x i8*], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]]
+; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [16 x i8], [3 x i8*], [0 x i8] } { [16 x i8] c"\00\00\00\00\00\00\00\00\00\00\00\04\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, align 16, !type [[T16:![0-9]+]]
@vt4 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -5
+ ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -1
; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]]
- ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2
+ ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1
; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: ret i1 [[VTCMP1]]
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -5
+ ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -1
; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]]
- ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1
+ ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2
; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: ret i1 [[VTCMP2]]
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i32 (i8*)*
- ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -4
+ ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -5
; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32*
; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]]
%result = call i32 %fptr_casted(i8* %obj)
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
-; CHECK: remark: <unknown>:0:0: virtual-const-prop: devirtualized a call to vf1i32
-; CHECK: remark: <unknown>:0:0: virtual-const-prop-1-bit: devirtualized a call to vf1i1
; CHECK: remark: <unknown>:0:0: virtual-const-prop-1-bit: devirtualized a call to vf0i1
+; CHECK: remark: <unknown>:0:0: virtual-const-prop-1-bit: devirtualized a call to vf1i1
+; CHECK: remark: <unknown>:0:0: virtual-const-prop: devirtualized a call to vf1i32
; CHECK: remark: <unknown>:0:0: devirtualized vf0i1
; CHECK: remark: <unknown>:0:0: devirtualized vf1i1
; CHECK: remark: <unknown>:0:0: devirtualized vf1i32
; SKIP-ALL-NOT: devirtualized
-; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\01\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
+; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [0 x i8] zeroinitializer }, section "vt1sec", !type [[T8:![0-9]+]]
@vt1 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf1i32 to i8*)
], section "vt1sec", !type !0
-; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\02\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
+; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
@vt2 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
], !type !0
-; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\01\03\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
+; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\03\00\00\00\02", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
@vt3 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i32 (i8*)* @vf3i32 to i8*)
], !type !0
-; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\02\04\00\00\00", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
+; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [8 x i8], [3 x i8*], [0 x i8] } { [8 x i8] c"\00\00\00\04\00\00\00\01", [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [0 x i8] zeroinitializer }, !type [[T8]]
@vt4 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
%pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 0, metadata !"typeid")
%fptr = extractvalue {i8*, i1} %pair, 0
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -5
+ ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 -1
; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]]
- ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2
+ ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1
; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: [[AND1:%[^ ]*]] = and i1 [[VTCMP1]], true
%pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 8, metadata !"typeid")
%fptr = extractvalue {i8*, i1} %pair, 0
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -5
+ ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 -1
; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]]
- ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1
+ ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2
; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: [[AND2:%[^ ]*]] = and i1 [[VTCMP2]], true
%pair = call {i8*, i1} @llvm.type.checked.load(i8* %vtablei8, i32 16, metadata !"typeid")
%fptr = extractvalue {i8*, i1} %pair, 0
%fptr_casted = bitcast i8* %fptr to i32 (i8*)*
- ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -4
+ ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 -5
; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32*
; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]]
%result = call i32 %fptr_casted(i8* %obj)
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
-; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [5 x i8] c"\01\00\00\00\01" }, !type [[T8:![0-9]+]]
+; CHECK: [[VT1DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf1i32 to i8*)], [5 x i8] c"\02\01\00\00\00" }, !type [[T8:![0-9]+]]
@vt1 = constant [4 x i8*] [
i8* null,
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf1i32 to i8*)
], !type !1
-; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [5 x i8] c"\02\00\00\00\02" }, !type [[T0:![0-9]+]]
+; CHECK: [[VT2DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf2i32 to i8*)], [5 x i8] c"\01\02\00\00\00" }, !type [[T0:![0-9]+]]
@vt2 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf2i32 to i8*)
], !type !0
-; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [5 x i8] c"\03\00\00\00\01" }, !type [[T8]]
+; CHECK: [[VT3DATA:@[^ ]*]] = private constant { [0 x i8], [4 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [4 x i8*] [i8* null, i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i32 (i8*)* @vf3i32 to i8*)], [5 x i8] c"\02\03\00\00\00" }, !type [[T8]]
@vt3 = constant [4 x i8*] [
i8* null,
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
i8* bitcast (i32 (i8*)* @vf3i32 to i8*)
], !type !1
-; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [5 x i8] c"\04\00\00\00\02" }, !type [[T0]]
+; CHECK: [[VT4DATA:@[^ ]*]] = private constant { [0 x i8], [3 x i8*], [5 x i8] } { [0 x i8] zeroinitializer, [3 x i8*] [i8* bitcast (i1 (i8*)* @vf1i1 to i8*), i8* bitcast (i1 (i8*)* @vf0i1 to i8*), i8* bitcast (i32 (i8*)* @vf4i32 to i8*)], [5 x i8] c"\01\04\00\00\00" }, !type [[T0]]
@vt4 = constant [3 x i8*] [
i8* bitcast (i1 (i8*)* @vf1i1 to i8*),
i8* bitcast (i1 (i8*)* @vf0i1 to i8*),
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 0
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 28
+ ; CHECK: [[VTGEP1:%[^ ]*]] = getelementptr i8, i8* [[VT1]], i32 24
; CHECK: [[VTLOAD1:%[^ ]*]] = load i8, i8* [[VTGEP1]]
- ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 2
+ ; CHECK: [[VTAND1:%[^ ]*]] = and i8 [[VTLOAD1]], 1
; CHECK: [[VTCMP1:%[^ ]*]] = icmp ne i8 [[VTAND1]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: ret i1 [[VTCMP1]]
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 1
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i1 (i8*)*
- ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 28
+ ; CHECK: [[VTGEP2:%[^ ]*]] = getelementptr i8, i8* [[VT2]], i32 24
; CHECK: [[VTLOAD2:%[^ ]*]] = load i8, i8* [[VTGEP2]]
- ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 1
+ ; CHECK: [[VTAND2:%[^ ]*]] = and i8 [[VTLOAD2]], 2
; CHECK: [[VTCMP2:%[^ ]*]] = icmp ne i8 [[VTAND2]], 0
%result = call i1 %fptr_casted(i8* %obj)
; CHECK: ret i1 [[VTCMP2]]
%fptrptr = getelementptr [3 x i8*], [3 x i8*]* %vtable, i32 0, i32 2
%fptr = load i8*, i8** %fptrptr
%fptr_casted = bitcast i8* %fptr to i32 (i8*)*
- ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 24
+ ; CHECK: [[VTGEP3:%[^ ]*]] = getelementptr i8, i8* [[VT3]], i32 25
; CHECK: [[VTBC3:%[^ ]*]] = bitcast i8* [[VTGEP3]] to i32*
; CHECK: [[VTLOAD3:%[^ ]*]] = load i32, i32* [[VTBC3]]
%result = call i32 %fptr_casted(i8* %obj)