Index: llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndex.h @@ -510,6 +510,12 @@ /// - 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 Index: llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h =================================================================== --- llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h +++ llvm/trunk/include/llvm/IR/ModuleSummaryIndexYAML.h @@ -51,6 +51,8 @@ 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); } }; Index: llvm/trunk/lib/LTO/LTO.cpp =================================================================== --- llvm/trunk/lib/LTO/LTO.cpp +++ llvm/trunk/lib/LTO/LTO.cpp @@ -230,6 +230,8 @@ AddUint64(Arg); AddUnsigned(ByArg.second.TheKind); AddUint64(ByArg.second.Info); + AddUnsigned(ByArg.second.Byte); + AddUnsigned(ByArg.second.Bit); } } }; Index: llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp =================================================================== --- llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp +++ llvm/trunk/lib/Transforms/IPO/WholeProgramDevirt.cpp @@ -467,16 +467,23 @@ std::string getGlobalName(VTableSlot Slot, ArrayRef 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 Args, StringRef Name, Constant *C); + void exportConstant(VTableSlot Slot, ArrayRef 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 Args, - StringRef Name, unsigned AbsWidth = 0); + StringRef Name); + Constant *importConstant(VTableSlot Slot, ArrayRef Args, + StringRef Name, IntegerType *IntTy, + uint32_t Storage); void applyUniqueRetValOpt(CallSiteInfo &CSInfo, StringRef FnName, bool IsOne, Constant *UniqueMemberAddr); @@ -856,6 +863,12 @@ 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 Args, StringRef Name, Constant *C) { GlobalAlias *GA = GlobalAlias::create(Int8Ty, 0, GlobalValue::ExternalLinkage, @@ -863,27 +876,55 @@ GA->setVisibility(GlobalValue::HiddenVisibility); } +void DevirtModule::exportConstant(VTableSlot Slot, ArrayRef 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 Args, - StringRef Name, unsigned AbsWidth) { + StringRef Name) { Constant *C = M.getOrInsertGlobal(getGlobalName(Slot, Args, Name), Int8Ty); auto *GV = dyn_cast(C); + if (GV) + GV->setVisibility(GlobalValue::HiddenVisibility); + return C; +} + +Constant *DevirtModule::importConstant(VTableSlot Slot, ArrayRef Args, + StringRef Name, IntegerType *IntTy, + uint32_t Storage) { + if (!shouldExportConstantsAsAbsoluteSymbols()) + return ConstantInt::get(IntTy, Storage); + + Constant *C = importGlobal(Slot, Args, Name); + auto *GV = cast(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, @@ -1059,18 +1100,18 @@ 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); } @@ -1301,10 +1342,10 @@ 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: Index: llvm/trunk/test/Transforms/WholeProgramDevirt/Inputs/import-vcp.yaml =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/Inputs/import-vcp.yaml +++ llvm/trunk/test/Transforms/WholeProgramDevirt/Inputs/import-vcp.yaml @@ -8,6 +8,8 @@ 1: Kind: VirtualConstProp Info: 0 + Byte: 42 + Bit: 0 typeid2: WPDRes: 8: @@ -16,4 +18,6 @@ 3: Kind: VirtualConstProp Info: 0 + Byte: 43 + Bit: 128 ... Index: llvm/trunk/test/Transforms/WholeProgramDevirt/export-uniform-ret-val.ll =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/export-uniform-ret-val.ll +++ llvm/trunk/test/Transforms/WholeProgramDevirt/export-uniform-ret-val.ll @@ -16,6 +16,8 @@ ; 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 Index: llvm/trunk/test/Transforms/WholeProgramDevirt/export-unique-ret-val.ll =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/export-unique-ret-val.ll +++ llvm/trunk/test/Transforms/WholeProgramDevirt/export-unique-ret-val.ll @@ -16,6 +16,8 @@ ; 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 @@ -28,6 +30,8 @@ ; 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 Index: llvm/trunk/test/Transforms/WholeProgramDevirt/export-vcp.ll =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/export-vcp.ll +++ llvm/trunk/test/Transforms/WholeProgramDevirt/export-vcp.ll @@ -1,8 +1,10 @@ -; 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: @@ -17,6 +19,10 @@ ; 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 @@ -29,6 +35,10 @@ ; 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 @@ -48,10 +58,11 @@ ; 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) Index: llvm/trunk/test/Transforms/WholeProgramDevirt/import-indir.ll =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/import-indir.ll +++ llvm/trunk/test/Transforms/WholeProgramDevirt/import-indir.ll @@ -44,12 +44,18 @@ ; 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" Index: llvm/trunk/test/Transforms/WholeProgramDevirt/import.ll =================================================================== --- llvm/trunk/test/Transforms/WholeProgramDevirt/import.ll +++ llvm/trunk/test/Transforms/WholeProgramDevirt/import.ll @@ -2,16 +2,17 @@ ; 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. @@ -31,7 +32,8 @@ ; 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]] @@ -82,9 +84,11 @@ ; 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