/// - UniqueRetVal: the return value associated with the unique vtable (0 or
/// 1).
uint64_t Info = 0;
+
+ // The following fields are only used if the target does not support the use
+ // of absolute symbols to store constants.
+
+ uint32_t Byte = 0;
+ uint32_t Bit = 0;
};
/// Resolutions for calls with all constant integer arguments (excluding the
static void mapping(IO &io, WholeProgramDevirtResolution::ByArg &res) {
io.mapOptional("Kind", res.TheKind);
io.mapOptional("Info", res.Info);
+ io.mapOptional("Byte", res.Byte);
+ io.mapOptional("Bit", res.Bit);
}
};
AddUint64(Arg);
AddUnsigned(ByArg.second.TheKind);
AddUint64(ByArg.second.Info);
+ AddUnsigned(ByArg.second.Byte);
+ AddUnsigned(ByArg.second.Bit);
}
}
};
std::string getGlobalName(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name);
+ bool shouldExportConstantsAsAbsoluteSymbols();
+
// This function is called during the export phase to create a symbol
// definition containing information about the given vtable slot and list of
// arguments.
void exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
Constant *C);
+ void exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args, StringRef Name,
+ uint32_t Const, uint32_t &Storage);
// This function is called during the import phase to create a reference to
// the symbol definition created during the export phase.
Constant *importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
- StringRef Name, unsigned AbsWidth = 0);
+ StringRef Name);
+ Constant *importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
+ StringRef Name, IntegerType *IntTy,
+ uint32_t Storage);
void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne,
Constant *UniqueMemberAddr);
return OS.str();
}
+bool DevirtModule::shouldExportConstantsAsAbsoluteSymbols() {
+ Triple T(M.getTargetTriple());
+ return (T.getArch() == Triple::x86 || T.getArch() == Triple::x86_64) &&
+ T.getObjectFormat() == Triple::ELF;
+}
+
void DevirtModule::exportGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
StringRef Name, Constant *C) {
GlobalAlias *GA = GlobalAlias::create(Int8Ty, 0, GlobalValue::ExternalLinkage,
GA->setVisibility(GlobalValue::HiddenVisibility);
}
+void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
+ StringRef Name, uint32_t Const,
+ uint32_t &Storage) {
+ if (shouldExportConstantsAsAbsoluteSymbols()) {
+ exportGlobal(
+ Slot, Args, Name,
+ ConstantExpr::getIntToPtr(ConstantInt::get(Int32Ty, Const), Int8PtrTy));
+ return;
+ }
+
+ Storage = Const;
+}
+
Constant *DevirtModule::importGlobal(VTableSlot Slot, ArrayRef<uint64_t> Args,
- StringRef Name, unsigned AbsWidth) {
+ StringRef Name) {
Constant *C = M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Ty);
auto *GV = dyn_cast<GlobalVariable>(C);
+ if (GV)
+ GV->setVisibility(GlobalValue::HiddenVisibility);
+ return C;
+}
+
+Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef<uint64_t> Args,
+ StringRef Name, IntegerType *IntTy,
+ uint32_t Storage) {
+ if (!shouldExportConstantsAsAbsoluteSymbols())
+ return ConstantInt::get(IntTy, Storage);
+
+ Constant *C = importGlobal(Slot, Args, Name);
+ auto *GV = cast<GlobalVariable>(C->stripPointerCasts());
+ C = ConstantExpr::getPtrToInt(C, IntTy);
+
// We only need to set metadata if the global is newly created, in which
// case it would not have hidden visibility.
- if (!GV || GV->getVisibility() == GlobalValue::HiddenVisibility)
+ if (GV->getMetadata(LLVMContext::MD_absolute_symbol))
return C;
- GV->setVisibility(GlobalValue::HiddenVisibility);
auto SetAbsRange = [&](uint64_t Min, uint64_t Max) {
auto *MinC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Min));
auto *MaxC = ConstantAsMetadata::get(ConstantInt::get(IntPtrTy, Max));
GV->setMetadata(LLVMContext::MD_absolute_symbol,
MDNode::get(M.getContext(), {MinC, MaxC}));
};
+ unsigned AbsWidth = IntTy->getBitWidth();
if (AbsWidth == IntPtrTy->getBitWidth())
SetAbsRange(~0ull, ~0ull); // Full set.
- else if (AbsWidth)
+ else
SetAbsRange(0, 1ull << AbsWidth);
- return GV;
+ return C;
}
void DevirtModule::applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName,
for (auto &&Target : TargetsForSlot)
Target.WasDevirt = true;
- Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);
- Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
if (CSByConstantArg.second.isExported()) {
ResByArg->TheKind = WholeProgramDevirtResolution::ByArg::VirtualConstProp;
- exportGlobal(Slot, CSByConstantArg.first, "byte",
- ConstantExpr::getIntToPtr(ByteConst, Int8PtrTy));
- exportGlobal(Slot, CSByConstantArg.first, "bit",
- ConstantExpr::getIntToPtr(BitConst, Int8PtrTy));
+ exportConstant(Slot, CSByConstantArg.first, "byte", OffsetByte,
+ ResByArg->Byte);
+ exportConstant(Slot, CSByConstantArg.first, "bit", 1ULL << OffsetBit,
+ ResByArg->Bit);
}
// Rewrite each call to a load from OffsetByte/OffsetBit.
+ Constant *ByteConst = ConstantInt::get(Int32Ty, OffsetByte);
+ Constant *BitConst = ConstantInt::get(Int8Ty, 1ULL << OffsetBit);
applyVirtualConstProp(CSByConstantArg.second,
TargetsForSlot[0].Fn->getName(), ByteConst, BitConst);
}
break;
}
case WholeProgramDevirtResolution::ByArg::VirtualConstProp: {
- Constant *Byte = importGlobal(Slot, CSByConstantArg.first, "byte", 32);
- Byte = ConstantExpr::getPtrToInt(Byte, Int32Ty);
- Constant *Bit = importGlobal(Slot, CSByConstantArg.first, "bit", 8);
- Bit = ConstantExpr::getPtrToInt(Bit, Int8Ty);
+ Constant *Byte = importConstant(Slot, CSByConstantArg.first, "byte",
+ Int32Ty, ResByArg.Byte);
+ Constant *Bit = importConstant(Slot, CSByConstantArg.first, "bit", Int8Ty,
+ ResByArg.Bit);
applyVirtualConstProp(CSByConstantArg.second, "", Byte, Bit);
}
default:
1:
Kind: VirtualConstProp
Info: 0
+ Byte: 42
+ Bit: 0
typeid2:
WPDRes:
8:
3:
Kind: VirtualConstProp
Info: 0
+ Byte: 43
+ Bit: 128
...
; SUMMARY-NEXT: 24,12:
; SUMMARY-NEXT: Kind: UniformRetVal
; SUMMARY-NEXT: Info: 36
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
; CHECK: @vt4a = constant i32 (i8*, i32, i32)* @vf4a
@vt4a = constant i32 (i8*, i32, i32)* @vf4a, !type !0
; SUMMARY-NEXT: 12,24:
; SUMMARY-NEXT: Kind: UniqueRetVal
; SUMMARY-NEXT: Info: 0
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
; SUMMARY-NEXT: typeid4:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: 24,12:
; SUMMARY-NEXT: Kind: UniqueRetVal
; SUMMARY-NEXT: Info: 1
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
; CHECK: @vt3a = constant i1 (i8*, i32, i32)* @vf3a
@vt3a = constant i1 (i8*, i32, i32)* @vf3a, !type !0
-; RUN: opt -wholeprogramdevirt -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck %s
-; RUN: FileCheck --check-prefix=SUMMARY %s < %t
+; RUN: opt -mtriple=x86_64-unknown-linux-gnu -wholeprogramdevirt -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck --check-prefixes=CHECK,X86 %s
+; RUN: FileCheck --check-prefixes=SUMMARY,SUMMARY-X86 %s < %t
+
+; RUN: opt -mtriple=armv7-unknown-linux-gnu -wholeprogramdevirt -wholeprogramdevirt-summary-action=export -wholeprogramdevirt-read-summary=%S/Inputs/export.yaml -wholeprogramdevirt-write-summary=%t -S -o - %s | FileCheck --check-prefixes=CHECK,ARM %s
+; RUN: FileCheck --check-prefixes=SUMMARY,SUMMARY-ARM %s < %t
target datalayout = "e-p:64:64"
-target triple = "x86_64-unknown-linux-gnu"
; SUMMARY: TypeIdMap:
; SUMMARY-NEXT: typeid3:
; SUMMARY-NEXT: 12,24:
; SUMMARY-NEXT: Kind: VirtualConstProp
; SUMMARY-NEXT: Info: 0
+; SUMMARY-X86-NEXT: Byte: 0
+; SUMMARY-X86-NEXT: Bit: 0
+; SUMMARY-ARM-NEXT: Byte: 4294967295
+; SUMMARY-ARM-NEXT: Bit: 1
; SUMMARY-NEXT: typeid4:
; SUMMARY-NEXT: TTRes:
; SUMMARY-NEXT: Kind: Unsat
; SUMMARY-NEXT: 24,12:
; SUMMARY-NEXT: Kind: VirtualConstProp
; SUMMARY-NEXT: Info: 0
+; SUMMARY-X86-NEXT: Byte: 0
+; SUMMARY-X86-NEXT: Bit: 0
+; SUMMARY-ARM-NEXT: Byte: 4294967292
+; SUMMARY-ARM-NEXT: Bit: 1
; CHECK: [[CVT3A:.*]] = private constant { [8 x i8], i1 (i8*, i32, i32)*, [0 x i8] } { [8 x i8] zeroinitializer, i1 (i8*, i32, i32)* @vf0i1, [0 x i8] zeroinitializer }, !type !0
@vt3a = constant i1 (i8*, i32, i32)* @vf0i1, !type !0
; CHECK: [[CVT4B:.*]] = private constant { [8 x i8], i32 (i8*, i32, i32)*, [0 x i8] } { [8 x i8] c"\00\00\00\00\02\00\00\00", i32 (i8*, i32, i32)* @vf2i32, [0 x i8] zeroinitializer }, !type !1
@vt4b = constant i32 (i8*, i32, i32)* @vf2i32, !type !1
-; CHECK: @__typeid_typeid3_0_12_24_byte = hidden alias i8, inttoptr (i32 -1 to i8*)
-; CHECK: @__typeid_typeid3_0_12_24_bit = hidden alias i8, inttoptr (i8 1 to i8*)
-; CHECK: @__typeid_typeid4_0_24_12_byte = hidden alias i8, inttoptr (i32 -4 to i8*)
-; CHECK: @__typeid_typeid4_0_24_12_bit = hidden alias i8, inttoptr (i8 1 to i8*)
+; X86: @__typeid_typeid3_0_12_24_byte = hidden alias i8, inttoptr (i32 -1 to i8*)
+; X86: @__typeid_typeid3_0_12_24_bit = hidden alias i8, inttoptr (i32 1 to i8*)
+; X86: @__typeid_typeid4_0_24_12_byte = hidden alias i8, inttoptr (i32 -4 to i8*)
+; X86: @__typeid_typeid4_0_24_12_bit = hidden alias i8, inttoptr (i32 1 to i8*)
+; ARM-NOT: alias {{.*}} inttoptr
; CHECK: @vt3a = alias i1 (i8*, i32, i32)*, getelementptr inbounds ({ [8 x i8], i1 (i8*, i32, i32)*, [0 x i8] }, { [8 x i8], i1 (i8*, i32, i32)*, [0 x i8] }* [[CVT3A]], i32 0, i32 1)
; CHECK: @vt3b = alias i1 (i8*, i32, i32)*, getelementptr inbounds ({ [8 x i8], i1 (i8*, i32, i32)*, [0 x i8] }, { [8 x i8], i1 (i8*, i32, i32)*, [0 x i8] }* [[CVT3B]], i32 0, i32 1)
; SUMMARY-NEXT: :
; SUMMARY-NEXT: Kind: UniformRetVal
; SUMMARY-NEXT: Info: 12
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
; SUMMARY-NEXT: 12:
; SUMMARY-NEXT: Kind: UniformRetVal
; SUMMARY-NEXT: Info: 24
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
; SUMMARY-NEXT: 12,24:
; SUMMARY-NEXT: Kind: UniformRetVal
; SUMMARY-NEXT: Info: 48
+; SUMMARY-NEXT: Byte: 0
+; SUMMARY-NEXT: Bit: 0
target datalayout = "e-p:32:32"
; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-uniform-ret-val.yaml < %s | FileCheck --check-prefixes=CHECK,UNIFORM-RET-VAL %s
; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-unique-ret-val0.yaml < %s | FileCheck --check-prefixes=CHECK,UNIQUE-RET-VAL0 %s
; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-unique-ret-val1.yaml < %s | FileCheck --check-prefixes=CHECK,UNIQUE-RET-VAL1 %s
-; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp.yaml < %s | FileCheck --check-prefixes=CHECK,VCP,VCP64 %s
-; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp.yaml -mtriple=i686-unknown-linux -data-layout=e-p:32:32 < %s | FileCheck --check-prefixes=CHECK,VCP,VCP32 %s
+; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp.yaml < %s | FileCheck --check-prefixes=CHECK,VCP,VCP-X86,VCP64 %s
+; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp.yaml -mtriple=i686-unknown-linux -data-layout=e-p:32:32 < %s | FileCheck --check-prefixes=CHECK,VCP,VCP-X86,VCP32 %s
+; RUN: opt -S -wholeprogramdevirt -wholeprogramdevirt-summary-action=import -wholeprogramdevirt-read-summary=%S/Inputs/import-vcp.yaml -mtriple=armv7-unknown-linux -data-layout=e-p:32:32 < %s | FileCheck --check-prefixes=CHECK,VCP,VCP-ARM %s
target datalayout = "e-p:64:64"
target triple = "x86_64-unknown-linux-gnu"
-; VCP: @__typeid_typeid1_0_1_byte = external hidden global i8, !absolute_symbol !0
-; VCP: @__typeid_typeid1_0_1_bit = external hidden global i8, !absolute_symbol !1
-; VCP: @__typeid_typeid2_8_3_byte = external hidden global i8, !absolute_symbol !0
-; VCP: @__typeid_typeid2_8_3_bit = external hidden global i8, !absolute_symbol !1
+; VCP-X86: @__typeid_typeid1_0_1_byte = external hidden global i8, !absolute_symbol !0
+; VCP-X86: @__typeid_typeid1_0_1_bit = external hidden global i8, !absolute_symbol !1
+; VCP-X86: @__typeid_typeid2_8_3_byte = external hidden global i8, !absolute_symbol !0
+; VCP-X86: @__typeid_typeid2_8_3_bit = external hidden global i8, !absolute_symbol !1
; Test cases where the argument values are known and we can apply virtual
; constant propagation.
; UNIFORM-RET-VAL: ret i32 42
; VCP: {{.*}} = bitcast {{.*}} to i8*
; VCP: [[VT1:%.*]] = bitcast {{.*}} to i8*
- ; VCP: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 ptrtoint (i8* @__typeid_typeid1_0_1_byte to i32)
+ ; VCP-X86: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 ptrtoint (i8* @__typeid_typeid1_0_1_byte to i32)
+ ; VCP-ARM: [[GEP1:%.*]] = getelementptr i8, i8* [[VT1]], i32 42
; VCP: [[BC1:%.*]] = bitcast i8* [[GEP1]] to i32*
; VCP: [[LOAD1:%.*]] = load i32, i32* [[BC1]]
; VCP: ret i32 [[LOAD1]]
; UNIQUE-RET-VAL0: icmp ne i8* %vtablei8, @__typeid_typeid2_8_3_unique_member
; UNIQUE-RET-VAL1: icmp eq i8* %vtablei8, @__typeid_typeid2_8_3_unique_member
; VCP: [[VT2:%.*]] = bitcast {{.*}} to i8*
- ; VCP: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 ptrtoint (i8* @__typeid_typeid2_8_3_byte to i32)
+ ; VCP-X86: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 ptrtoint (i8* @__typeid_typeid2_8_3_byte to i32)
+ ; VCP-ARM: [[GEP2:%.*]] = getelementptr i8, i8* [[VT2]], i32 43
; VCP: [[LOAD2:%.*]] = load i8, i8* [[GEP2]]
- ; VCP: [[AND2:%.*]] = and i8 [[LOAD2]], ptrtoint (i8* @__typeid_typeid2_8_3_bit to i8)
+ ; VCP-X86: [[AND2:%.*]] = and i8 [[LOAD2]], ptrtoint (i8* @__typeid_typeid2_8_3_bit to i8)
+ ; VCP-ARM: [[AND2:%.*]] = and i8 [[LOAD2]], -128
; VCP: [[ICMP2:%.*]] = icmp ne i8 [[AND2]], 0
; VCP: ret i1 [[ICMP2]]
ret i1 %result