From llvm-branch-commits at lists.llvm.org Mon May 3 16:42:42 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:42:42 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 907a751 - [NFC][InstCombine] Add test for PR49778 Message-ID: <60908a72.1c69fb81.48ed0.c3a6@mx.google.com> Author: Roman Lebedev Date: 2021-05-03T16:41:30-07:00 New Revision: 907a751a38fff8d05b288ab52b19ba4e2cc1fc38 URL: https://github.com/llvm/llvm-project/commit/907a751a38fff8d05b288ab52b19ba4e2cc1fc38 DIFF: https://github.com/llvm/llvm-project/commit/907a751a38fff8d05b288ab52b19ba4e2cc1fc38.diff LOG: [NFC][InstCombine] Add test for PR49778 (cherry picked from commit 5352490ce613f1bdedaf478765b089b1f0a8be0d) Added: llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll Modified: Removed: ################################################################################ diff --git a/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll new file mode 100644 index 0000000000000..4865afa56a037 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll @@ -0,0 +1,15 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instcombine -S | FileCheck %s + +; PR49778: this should not be folded to 0. +define i32 @src(i1 %x2) { +; CHECK-LABEL: @src( +; CHECK-NEXT: ret i32 0 +; + %x13 = zext i1 %x2 to i32 + %_7 = shl i32 4294967295, %x13 + %mask = xor i32 %_7, 4294967295 + %_8 = and i32 %mask, %x13 + %_9 = shl i32 %_8, %x13 + ret i32 %_9 +} From llvm-branch-commits at lists.llvm.org Mon May 3 16:42:44 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:42:44 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 4a4b1c7 - [NFC][InstCombine] Extract canTryToConstantAddTwoShiftAmounts() as helper Message-ID: <60908a74.1c69fb81.98a5c.d6a6@mx.google.com> Author: Roman Lebedev Date: 2021-05-03T16:41:31-07:00 New Revision: 4a4b1c75a1ea3f1ca90ef45470c42debb81ffc90 URL: https://github.com/llvm/llvm-project/commit/4a4b1c75a1ea3f1ca90ef45470c42debb81ffc90 DIFF: https://github.com/llvm/llvm-project/commit/4a4b1c75a1ea3f1ca90ef45470c42debb81ffc90.diff LOG: [NFC][InstCombine] Extract canTryToConstantAddTwoShiftAmounts() as helper (cherry picked from commit dceb3e599668496420d41b993100d23eeb7c0ada) Added: Modified: llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp Removed: ################################################################################ diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 7295369365c49..52f064e178206 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -21,6 +21,30 @@ using namespace PatternMatch; #define DEBUG_TYPE "instcombine" +bool canTryToConstantAddTwoShiftAmounts(Value *Sh0, Value *ShAmt0, Value *Sh1, + Value *ShAmt1) { + // We have two shift amounts from two diff erent shifts. The types of those + // shift amounts may not match. If that's the case let's bailout now.. + if (ShAmt0->getType() != ShAmt1->getType()) + return false; + + // As input, we have the following pattern: + // Sh0 (Sh1 X, Q), K + // We want to rewrite that as: + // Sh x, (Q+K) iff (Q+K) u< bitwidth(x) + // While we know that originally (Q+K) would not overflow + // (because 2 * (N-1) u<= iN -1), we have looked past extensions of + // shift amounts. so it may now overflow in smaller bitwidth. + // To ensure that does not happen, we need to ensure that the total maximal + // shift amount is still representable in that smaller bit width. + unsigned MaximalPossibleTotalShiftAmount = + (Sh0->getType()->getScalarSizeInBits() - 1) + + (Sh1->getType()->getScalarSizeInBits() - 1); + APInt MaximalRepresentableShiftAmount = + APInt::getAllOnesValue(ShAmt0->getType()->getScalarSizeInBits()); + return MaximalRepresentableShiftAmount.uge(MaximalPossibleTotalShiftAmount); +} + // Given pattern: // (x shiftopcode Q) shiftopcode K // we should rewrite it as @@ -57,26 +81,8 @@ Value *InstCombinerImpl::reassociateShiftAmtsOfTwoSameDirectionShifts( if (!match(Sh1, m_Shift(m_Value(X), m_ZExtOrSelf(m_Value(ShAmt1))))) return nullptr; - // We have two shift amounts from two diff erent shifts. The types of those - // shift amounts may not match. If that's the case let's bailout now.. - if (ShAmt0->getType() != ShAmt1->getType()) - return nullptr; - - // As input, we have the following pattern: - // Sh0 (Sh1 X, Q), K - // We want to rewrite that as: - // Sh x, (Q+K) iff (Q+K) u< bitwidth(x) - // While we know that originally (Q+K) would not overflow - // (because 2 * (N-1) u<= iN -1), we have looked past extensions of - // shift amounts. so it may now overflow in smaller bitwidth. - // To ensure that does not happen, we need to ensure that the total maximal - // shift amount is still representable in that smaller bit width. - unsigned MaximalPossibleTotalShiftAmount = - (Sh0->getType()->getScalarSizeInBits() - 1) + - (Sh1->getType()->getScalarSizeInBits() - 1); - APInt MaximalRepresentableShiftAmount = - APInt::getAllOnesValue(ShAmt0->getType()->getScalarSizeInBits()); - if (MaximalRepresentableShiftAmount.ult(MaximalPossibleTotalShiftAmount)) + // Verify that it would be safe to try to add those two shift amounts. + if (!canTryToConstantAddTwoShiftAmounts(Sh0, ShAmt0, Sh1, ShAmt1)) return nullptr; // We are only looking for signbit extraction if we have two right shifts. From llvm-branch-commits at lists.llvm.org Mon May 3 16:42:46 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:42:46 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] c27ad80 - [InstCombine] dropRedundantMaskingOfLeftShiftInput(): check that adding shift amounts doesn't overflow (PR49778) Message-ID: <60908a76.1c69fb81.556ab.cbbe@mx.google.com> Author: Roman Lebedev Date: 2021-05-03T16:41:31-07:00 New Revision: c27ad80507bfea35da07681fd4ec9972ca698015 URL: https://github.com/llvm/llvm-project/commit/c27ad80507bfea35da07681fd4ec9972ca698015 DIFF: https://github.com/llvm/llvm-project/commit/c27ad80507bfea35da07681fd4ec9972ca698015.diff LOG: [InstCombine] dropRedundantMaskingOfLeftShiftInput(): check that adding shift amounts doesn't overflow (PR49778) This is identical to 781d077afb0ed9771c513d064c40170c1ccd21c9, but for the other function. For certain shift amount bit widths, we must first ensure that adding shift amounts is safe, that the sum won't have an unsigned overflow. Fixes https://bugs.llvm.org/show_bug.cgi?id=49778 (cherry picked from commit 2760a808b9916a2839513b7fd7314a464f52481e) Added: Modified: llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll Removed: ################################################################################ diff --git a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp index 52f064e17820..127bf8080959 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineShifts.cpp @@ -226,9 +226,9 @@ dropRedundantMaskingOfLeftShiftInput(BinaryOperator *OuterShift, // Peek through an optional zext of the shift amount. match(MaskShAmt, m_ZExtOrSelf(m_Value(MaskShAmt))); - // We have two shift amounts from two diff erent shifts. The types of those - // shift amounts may not match. If that's the case let's bailout now. - if (MaskShAmt->getType() != ShiftShAmt->getType()) + // Verify that it would be safe to try to add those two shift amounts. + if (!canTryToConstantAddTwoShiftAmounts(OuterShift, ShiftShAmt, Masked, + MaskShAmt)) return nullptr; // Can we simplify (MaskShAmt+ShiftShAmt) ? @@ -258,9 +258,9 @@ dropRedundantMaskingOfLeftShiftInput(BinaryOperator *OuterShift, // Peek through an optional zext of the shift amount. match(MaskShAmt, m_ZExtOrSelf(m_Value(MaskShAmt))); - // We have two shift amounts from two diff erent shifts. The types of those - // shift amounts may not match. If that's the case let's bailout now. - if (MaskShAmt->getType() != ShiftShAmt->getType()) + // Verify that it would be safe to try to add those two shift amounts. + if (!canTryToConstantAddTwoShiftAmounts(OuterShift, ShiftShAmt, Masked, + MaskShAmt)) return nullptr; // Can we simplify (ShiftShAmt-MaskShAmt) ? diff --git a/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll index 4865afa56a03..8d70733ed03d 100644 --- a/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll +++ b/llvm/test/Transforms/InstCombine/redundant-left-shift-input-masking-pr49778.ll @@ -4,7 +4,12 @@ ; PR49778: this should not be folded to 0. define i32 @src(i1 %x2) { ; CHECK-LABEL: @src( -; CHECK-NEXT: ret i32 0 +; CHECK-NEXT: [[X13:%.*]] = zext i1 [[X2:%.*]] to i32 +; CHECK-NEXT: [[_7:%.*]] = shl i32 -1, [[X13]] +; CHECK-NEXT: [[MASK:%.*]] = xor i32 [[_7]], -1 +; CHECK-NEXT: [[_8:%.*]] = and i32 [[MASK]], [[X13]] +; CHECK-NEXT: [[_9:%.*]] = shl i32 [[_8]], [[X13]] +; CHECK-NEXT: ret i32 [[_9]] ; %x13 = zext i1 %x2 to i32 %_7 = shl i32 4294967295, %x13 From llvm-branch-commits at lists.llvm.org Mon May 3 16:48:43 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:48:43 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 3568d61 - BPF: Implement TTI.IntImmCost() properly Message-ID: <60908bdb.1c69fb81.45199.244d@mx.google.com> Author: Yonghong Song Date: 2021-05-03T16:48:10-07:00 New Revision: 3568d61f11e2eb0017c7b65707bee7bf4111c8ca URL: https://github.com/llvm/llvm-project/commit/3568d61f11e2eb0017c7b65707bee7bf4111c8ca DIFF: https://github.com/llvm/llvm-project/commit/3568d61f11e2eb0017c7b65707bee7bf4111c8ca.diff LOG: BPF: Implement TTI.IntImmCost() properly This patch implemented TTI.IntImmCost() properly. Each BPF insn has 32bit immediate space, so for any immediate which can be represented as 32bit signed int, the cost is technically free. If an int cannot be presented as a 32bit signed int, a ld_imm64 instruction is needed and a TCC_Basic is returned. This change is motivated when we observed that several bpf selftests failed with latest llvm trunk, e.g., #10/16 strobemeta.o:FAIL #10/17 strobemeta_nounroll1.o:FAIL #10/18 strobemeta_nounroll2.o:FAIL #10/19 strobemeta_subprogs.o:FAIL #96 snprintf_btf:FAIL The reason of the failure is due to that SpeculateAroundPHIsPass did aggressive transformation which alters control flow for which currently verifer cannot handle well. In llvm12, SpeculateAroundPHIsPass is not called. SpeculateAroundPHIsPass relied on TTI.getIntImmCost() and TTI.getIntImmCostInst() for profitability analysis. This patch implemented TTI.getIntImmCost() properly for BPF backend which also prevented transformation which caused the above test failures. Differential Revision: https://reviews.llvm.org/D96448 (cherry picked from commit a260ae716030d5d2644a2af649501277d326bb21) Added: llvm/lib/Target/BPF/BPFTargetTransformInfo.h Modified: llvm/lib/Target/BPF/BPFTargetMachine.cpp llvm/lib/Target/BPF/BPFTargetMachine.h Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.cpp b/llvm/lib/Target/BPF/BPFTargetMachine.cpp index c0244b9f2c749..a8fef2517b03e 100644 --- a/llvm/lib/Target/BPF/BPFTargetMachine.cpp +++ b/llvm/lib/Target/BPF/BPFTargetMachine.cpp @@ -12,6 +12,7 @@ #include "BPFTargetMachine.h" #include "BPF.h" +#include "BPFTargetTransformInfo.h" #include "MCTargetDesc/BPFMCAsmInfo.h" #include "TargetInfo/BPFTargetInfo.h" #include "llvm/CodeGen/Passes.h" @@ -145,6 +146,11 @@ void BPFPassConfig::addIRPasses() { TargetPassConfig::addIRPasses(); } +TargetTransformInfo +BPFTargetMachine::getTargetTransformInfo(const Function &F) { + return TargetTransformInfo(BPFTTIImpl(this, F)); +} + // Install an instruction selector pass using // the ISelDag to gen BPF code. bool BPFPassConfig::addInstSelector() { diff --git a/llvm/lib/Target/BPF/BPFTargetMachine.h b/llvm/lib/Target/BPF/BPFTargetMachine.h index 5243a15eb7b05..61c8a44cc4024 100644 --- a/llvm/lib/Target/BPF/BPFTargetMachine.h +++ b/llvm/lib/Target/BPF/BPFTargetMachine.h @@ -34,6 +34,8 @@ class BPFTargetMachine : public LLVMTargetMachine { TargetPassConfig *createPassConfig(PassManagerBase &PM) override; + TargetTransformInfo getTargetTransformInfo(const Function &F) override; + TargetLoweringObjectFile *getObjFileLowering() const override { return TLOF.get(); } diff --git a/llvm/lib/Target/BPF/BPFTargetTransformInfo.h b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h new file mode 100644 index 0000000000000..622da9a0a3f7d --- /dev/null +++ b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h @@ -0,0 +1,49 @@ +//===------ BPFTargetTransformInfo.h - BPF specific TTI ---------*- 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 +// +//===----------------------------------------------------------------------===// +// +// This file uses the target's specific information to +// provide more precise answers to certain TTI queries, while letting the +// target independent and default TTI implementations handle the rest. +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H +#define LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H + +#include "BPFTargetMachine.h" +#include "llvm/Analysis/TargetTransformInfo.h" +#include "llvm/CodeGen/BasicTTIImpl.h" + +namespace llvm { +class BPFTTIImpl : public BasicTTIImplBase { + typedef BasicTTIImplBase BaseT; + typedef TargetTransformInfo TTI; + friend BaseT; + + const BPFSubtarget *ST; + const BPFTargetLowering *TLI; + + const BPFSubtarget *getST() const { return ST; } + const BPFTargetLowering *getTLI() const { return TLI; } + +public: + explicit BPFTTIImpl(const BPFTargetMachine *TM, const Function &F) + : BaseT(TM, F.getParent()->getDataLayout()), ST(TM->getSubtargetImpl(F)), + TLI(ST->getTargetLowering()) {} + + int getIntImmCost(const APInt &Imm, Type *Ty, TTI::TargetCostKind CostKind) { + if (Imm.getBitWidth() <= 64 && isInt<32>(Imm.getSExtValue())) + return TTI::TCC_Free; + + return TTI::TCC_Basic; + } +}; + +} // end namespace llvm + +#endif // LLVM_LIB_TARGET_BPF_BPFTARGETTRANSFORMINFO_H From llvm-branch-commits at lists.llvm.org Mon May 3 16:48:45 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:48:45 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] f9efff3 - BPF: Add LLVMAnalysis in CMakefile LINK_COMPONENTS Message-ID: <60908bdd.1c69fb81.834c7.b3a9@mx.google.com> Author: Yonghong Song Date: 2021-05-03T16:48:10-07:00 New Revision: f9efff398c1159b15964b166368b232f562e6cfc URL: https://github.com/llvm/llvm-project/commit/f9efff398c1159b15964b166368b232f562e6cfc DIFF: https://github.com/llvm/llvm-project/commit/f9efff398c1159b15964b166368b232f562e6cfc.diff LOG: BPF: Add LLVMAnalysis in CMakefile LINK_COMPONENTS buildbot reported a build error like below: BPFTargetMachine.cpp:(.text._ZN4llvm19TargetTransformInfo5ModelINS_10BPFTTIImplEED2Ev [_ZN4llvm19TargetTransformInfo5ModelINS_10BPFTTIImplEED2Ev]+0x14): undefined reference to `llvm::TargetTransformInfo::Concept::~Concept()' lib/Target/BPF/CMakeFiles/LLVMBPFCodeGen.dir/BPFTargetMachine.cpp.o: In function `llvm::TargetTransformInfo::Model::~Model()': Commit a260ae716030 ("BPF: Implement TTI.IntImmCost() properly") added TargetTransformInfo to BPF, which requires LLVMAnalysis dependence. In certain cmake configurations, lacking explicit LLVMAnalysis dependency may cause compilation error. Similar to other targets, this patch added LLVMAnalysis in CMakefile LINK_COMPONENTS explicitly. (cherry picked from commit 74975d35b47631da0c7911561f16d3ffd1af142a) Added: Modified: llvm/lib/Target/BPF/CMakeLists.txt Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index 24c6c5e1255e..189a3a84c3df 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -35,6 +35,7 @@ add_llvm_target(BPFCodeGen BTFDebug.cpp LINK_COMPONENTS + Analysis AsmPrinter CodeGen Core From llvm-branch-commits at lists.llvm.org Mon May 3 16:48:47 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:48:47 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 2460947 - BPF: Implement TTI.getCmpSelInstrCost() properly Message-ID: <60908bdf.1c69fb81.2a33f.222a@mx.google.com> Author: Yonghong Song Date: 2021-05-03T16:48:11-07:00 New Revision: 2460947eefc2176693a4aa4d05cd9733e38c7ffe URL: https://github.com/llvm/llvm-project/commit/2460947eefc2176693a4aa4d05cd9733e38c7ffe DIFF: https://github.com/llvm/llvm-project/commit/2460947eefc2176693a4aa4d05cd9733e38c7ffe.diff LOG: BPF: Implement TTI.getCmpSelInstrCost() properly The Select insn in BPF is expensive as BPF backend needs to resolve with conditionals. This patch set the getCmpSelInstrCost() to SCEVCheapExpansionBudget for Select insn to prevent some Select insn related optimizations. This change is motivated during bcc code review for https://github.com/iovisor/bcc/pull/3270 where IndVarSimplifyPass eventually caused generating the following asm code: ; for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) { 14: 16 05 40 00 00 00 00 00 if w5 == 0 goto +64 15: bc 51 00 00 00 00 00 00 w1 = w5 16: 04 01 00 00 ff ff ff ff w1 += -1 17: 67 05 00 00 20 00 00 00 r5 <<= 32 18: 77 05 00 00 20 00 00 00 r5 >>= 32 19: a6 01 01 00 05 00 00 00 if w1 < 5 goto +1 20: b7 05 00 00 06 00 00 00 r5 = 6 00000000000000a8 : 21: b7 02 00 00 00 00 00 00 r2 = 0 22: b7 01 00 00 00 00 00 00 r1 = 0 ; for (i = 0; (i < VIRTIO_MAX_SGS) && (i < num); i++) { 23: 7b 1a e0 ff 00 00 00 00 *(u64 *)(r10 - 32) = r1 24: 7b 5a c0 ff 00 00 00 00 *(u64 *)(r10 - 64) = r5 Note that insn #15 has w1 = w5 and w1 is refined later but r5(w5) is eventually saved on stack at insn #24 for later use. This cause later verifier failures. With this change, IndVarSimplifyPass won't do the above transformation any more. Differential Revision: https://reviews.llvm.org/D97479 (cherry picked from commit 1959ead525b8830cc8a345f45e1c3ef9902d3229) Added: Modified: llvm/lib/Target/BPF/BPFTargetTransformInfo.h Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/BPFTargetTransformInfo.h b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h index 622da9a0a3f7..62055497e685 100644 --- a/llvm/lib/Target/BPF/BPFTargetTransformInfo.h +++ b/llvm/lib/Target/BPF/BPFTargetTransformInfo.h @@ -18,6 +18,7 @@ #include "BPFTargetMachine.h" #include "llvm/Analysis/TargetTransformInfo.h" #include "llvm/CodeGen/BasicTTIImpl.h" +#include "llvm/Transforms/Utils/ScalarEvolutionExpander.h" namespace llvm { class BPFTTIImpl : public BasicTTIImplBase { @@ -42,6 +43,17 @@ class BPFTTIImpl : public BasicTTIImplBase { return TTI::TCC_Basic; } + + int getCmpSelInstrCost(unsigned Opcode, Type *ValTy, Type *CondTy, + CmpInst::Predicate VecPred, + TTI::TargetCostKind CostKind, + const llvm::Instruction *I = nullptr) { + if (Opcode == Instruction::Select) + return SCEVCheapExpansionBudget; + + return BaseT::getCmpSelInstrCost(Opcode, ValTy, CondTy, VecPred, CostKind, + I); + } }; } // end namespace llvm From llvm-branch-commits at lists.llvm.org Mon May 3 16:48:49 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 16:48:49 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 6fe7c37 - BPF: Add LLVMTransformUtils in CMakefile LINK_COMPONENTS Message-ID: <60908be1.1c69fb81.705b9.29d1@mx.google.com> Author: Yonghong Song Date: 2021-05-03T16:48:11-07:00 New Revision: 6fe7c3728d1e98e05c67ceb03f429cb04a30e151 URL: https://github.com/llvm/llvm-project/commit/6fe7c3728d1e98e05c67ceb03f429cb04a30e151 DIFF: https://github.com/llvm/llvm-project/commit/6fe7c3728d1e98e05c67ceb03f429cb04a30e151.diff LOG: BPF: Add LLVMTransformUtils in CMakefile LINK_COMPONENTS Commit 1959ead525b8 ("BPF: Implement TTI.getCmpSelInstrCost() properly") introduced a dependency on LLVMTransformUtils library. Let us encode this dependency explicitly in CMakefile to avoid build error. (cherry picked from commit 6d102f15a3af0a44cf2e26677e260bee425312f3) Added: Modified: llvm/lib/Target/BPF/CMakeLists.txt Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/CMakeLists.txt b/llvm/lib/Target/BPF/CMakeLists.txt index 189a3a84c3df..2d804ca8a73e 100644 --- a/llvm/lib/Target/BPF/CMakeLists.txt +++ b/llvm/lib/Target/BPF/CMakeLists.txt @@ -47,6 +47,7 @@ add_llvm_target(BPFCodeGen SelectionDAG Support Target + TransformUtils ADD_TO_COMPONENT BPF From llvm-branch-commits at lists.llvm.org Mon May 3 17:18:26 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:18:26 -0700 (PDT) Subject: [llvm-branch-commits] [polly] b8e4d4e - [PollyACC] Fix implicit function definitions. NFC. Message-ID: <609092d2.1c69fb81.61edb.bc3b@mx.google.com> Author: Michael Kruse Date: 2021-05-03T17:18:07-07:00 New Revision: b8e4d4eafeded48f3c07797a2d8ccc950394085e URL: https://github.com/llvm/llvm-project/commit/b8e4d4eafeded48f3c07797a2d8ccc950394085e DIFF: https://github.com/llvm/llvm-project/commit/b8e4d4eafeded48f3c07797a2d8ccc950394085e.diff LOG: [PollyACC] Fix implicit function definitions. NFC. The isl_id_* have been in used without including the correspodning isl/id.h header. According to rules in C, a function is defined implicitly when first used with an assumed int return type (32 bits on 64 bit systems). But the implementation returns a pointer (64 bits on 64 bit systems). Is usually has no consequence because the return value is stored in a registers that is 64 bits (RAX) and the optimizer does not truncate its value before using it again as a pointer value. However, LTO optimizers will be rightfull;y confused. Fix by including This fixes llvm.org/PR50021 (cherry picked from commit 90e5ce0b0d6b0e72fdc034cbb612f67d67de0fdd) Added: Modified: polly/lib/External/ppcg/print.c Removed: ################################################################################ diff --git a/polly/lib/External/ppcg/print.c b/polly/lib/External/ppcg/print.c index 79aaf2b00d237..dd839e48e51ba 100644 --- a/polly/lib/External/ppcg/print.c +++ b/polly/lib/External/ppcg/print.c @@ -9,6 +9,7 @@ #include #include +#include #include "print.h" #include "util.h" From llvm-branch-commits at lists.llvm.org Mon May 3 17:18:28 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:18:28 -0700 (PDT) Subject: [llvm-branch-commits] [polly] 8b2c019 - [PollyACC] Fix declaration/stub definition mismatch. NFC. Message-ID: <609092d4.1c69fb81.b4520.c344@mx.google.com> Author: Michael Kruse Date: 2021-05-03T17:18:08-07:00 New Revision: 8b2c019ace3c2e04108b550c5a2b60fc1c63865f URL: https://github.com/llvm/llvm-project/commit/8b2c019ace3c2e04108b550c5a2b60fc1c63865f DIFF: https://github.com/llvm/llvm-project/commit/8b2c019ace3c2e04108b550c5a2b60fc1c63865f.diff LOG: [PollyACC] Fix declaration/stub definition mismatch. NFC. external.c defines stub functions that are never used because of how Polly uses PPCG. Unfortunately, they are declared as functions without return values or parameters which does not match their declarations. Since they are never called, this was usually not a problem, but an LTO build gets confused with differently declared functions, or in case of pet_options_args, a global variable declaration that is defined as a function Resolve by including the declaring headers in external.c which forces the declaration and definition to match at compile-time. This fixes llvm.org/50021 (cherry picked from commit 89b59345ee29d2cc1afa1f60445916ae2e74be6d) Added: Modified: polly/lib/External/ppcg/external.c Removed: ################################################################################ diff --git a/polly/lib/External/ppcg/external.c b/polly/lib/External/ppcg/external.c index 3a63ffbd97e55..c5ef6320e64fb 100644 --- a/polly/lib/External/ppcg/external.c +++ b/polly/lib/External/ppcg/external.c @@ -1,181 +1,192 @@ -#include "assert.h" -#include "stdio.h" -#include "stdlib.h" +#include +#include +#include +#include +#include "cpu.h" +#include "opencl.h" + #define die() { \ fprintf(stderr, "Dummy function %s called\n", __FUNCTION__); \ abort(); \ } -void pet_scop_compute_outer_to_any(){ +__isl_give isl_union_map *pet_scop_compute_outer_to_any( + __isl_keep pet_scop *scop) { die(); } -void pet_scop_compute_outer_to_inner(){ +__isl_give isl_union_map *pet_scop_compute_outer_to_inner( + __isl_keep pet_scop *scop) { die(); } -void pet_tree_get_type(){ +enum pet_tree_type pet_tree_get_type(__isl_keep pet_tree *tree) { die(); } -void pet_tree_foreach_access_expr(){ +int pet_tree_foreach_access_expr(__isl_keep pet_tree *tree, + int (*fn)(__isl_keep pet_expr *expr, void *user), void *user) { die(); } -void pet_expr_get_ctx(){ +isl_ctx *pet_expr_get_ctx(__isl_keep pet_expr *expr) { die(); } -void pet_expr_access_is_read(){ +isl_bool pet_expr_access_is_read(__isl_keep pet_expr *expr) { die(); } -void pet_expr_access_is_write(){ +isl_bool pet_expr_access_is_write(__isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_tagged_may_read(){ +__isl_give isl_union_map *pet_expr_access_get_tagged_may_read( + __isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_tagged_may_write(){ +__isl_give isl_union_map *pet_expr_access_get_tagged_may_write( + __isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_must_write(){ +__isl_give isl_union_map *pet_expr_access_get_must_write( + __isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_index(){ +__isl_give isl_multi_pw_aff *pet_expr_access_get_index( + __isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_ref_id(){ +__isl_give isl_id *pet_expr_access_get_ref_id(__isl_keep pet_expr *expr) { die(); } -void print_cpu(){ +__isl_give isl_printer *print_cpu(__isl_take isl_printer *p, + struct ppcg_scop *ps, struct ppcg_options *options) { die(); } -void pet_stmt_print_body(){ - die(); -} -void pet_loc_get_start(){ - die(); -} -void pet_loc_get_end(){ - die(); -} -void pet_scop_collect_tagged_may_reads(){ - die(); -} -void pet_scop_collect_may_reads(){ +__isl_give isl_printer *pet_stmt_print_body(struct pet_stmt *stmt, + __isl_take isl_printer *p, __isl_keep isl_id_to_ast_expr *ref2expr) { die(); } -void pet_scop_collect_tagged_may_writes(){ +unsigned pet_loc_get_start(__isl_keep pet_loc *loc) { die(); } -void pet_scop_collect_may_writes(){ +unsigned pet_loc_get_end(__isl_keep pet_loc *loc) { die(); } -void pet_scop_collect_tagged_must_writes(){ +int pet_transform_C_source(isl_ctx *ctx, const char *input, FILE *output, + __isl_give isl_printer *(*transform)(__isl_take isl_printer *p, + __isl_take pet_scop *scop, void *user), void *user) { die(); } -void pet_scop_collect_must_writes(){ +__isl_give isl_printer *pet_scop_print_original(__isl_keep pet_scop *scop, + __isl_take isl_printer *p) { die(); } -void pet_scop_collect_tagged_must_kills(){ +__isl_null pet_scop *pet_scop_free(__isl_take pet_scop *scop) { die(); } -void pet_transform_C_source(){ +__isl_give pet_scop *pet_scop_align_params(__isl_take pet_scop *scop) { die(); } -void pet_scop_print_original(){ +int pet_scop_can_build_ast_exprs(__isl_keep pet_scop *scop) { die(); } -void pet_scop_free(){ +int pet_scop_has_data_dependent_conditions(__isl_keep pet_scop *scop) { die(); } -void pet_scop_align_params(){ +int pet_tree_foreach_expr(__isl_keep pet_tree *tree, + int (*fn)(__isl_keep pet_expr *expr, void *user), void *user) { die(); } -void pet_scop_can_build_ast_exprs(){ +int pet_expr_foreach_call_expr(__isl_keep pet_expr *expr, + int (*fn)(__isl_keep pet_expr *expr, void *user), void *user) { die(); } -void pet_scop_has_data_dependent_conditions(){ +int pet_stmt_is_kill(struct pet_stmt *stmt) { die(); } -void pet_tree_foreach_expr(){ +struct isl_args pet_options_args; +const char *ppcg_version(void) { die(); } -void pet_expr_foreach_call_expr(){ +int pet_options_set_encapsulate_dynamic_control(isl_ctx *ctx, int val) { die(); } -void pet_stmt_is_kill(){ +int generate_opencl(isl_ctx *ctx, struct ppcg_options *options, + const char *input, const char *output) { die(); } -void pet_options_args() { +int generate_cpu(isl_ctx *ctx, struct ppcg_options *options, + const char *input, const char *output) { die(); } -void ppcg_print_guarded() { +__isl_give isl_id_to_ast_expr *pet_stmt_build_ast_exprs(struct pet_stmt *stmt, + __isl_keep isl_ast_build *build, + __isl_give isl_multi_pw_aff *(*fn_index)( + __isl_take isl_multi_pw_aff *mpa, __isl_keep isl_id *id, + void *user), void *user_index, + __isl_give isl_ast_expr *(*fn_expr)(__isl_take isl_ast_expr *expr, + __isl_keep isl_id *id, void *user), void *user_expr) { die(); } -void ppcg_version() { +__isl_give isl_union_map *pet_scop_get_tagged_may_reads( + __isl_keep pet_scop *scop) { die(); } -void pet_options_set_encapsulate_dynamic_control() { +__isl_give isl_union_map *pet_scop_get_may_reads(__isl_keep pet_scop *scop) { die(); } -void generate_opencl() { +__isl_give isl_union_map *pet_scop_get_may_writes(__isl_keep pet_scop *scop) { die(); } -void generate_cpu() { +__isl_give isl_union_map *pet_scop_get_must_writes(__isl_keep pet_scop *scop) { die(); } -void pet_stmt_build_ast_exprs() { +__isl_give isl_union_map *pet_scop_get_tagged_may_writes( + __isl_keep pet_scop *scop) { die(); } - void pet_scop_get_tagged_may_reads() { +__isl_give isl_union_map *pet_scop_get_tagged_must_writes( + __isl_keep pet_scop *scop) { die(); } - void pet_scop_get_may_reads() { - die(); -} -void pet_scop_get_may_writes() { - die(); -} -void pet_scop_get_must_writes() { - die(); -} -void pet_scop_get_tagged_may_writes() { - die(); -} -void pet_scop_get_tagged_must_writes() { -die(); -} -void pet_scop_get_must_kills() { +__isl_give isl_union_map *pet_scop_get_must_kills(__isl_keep pet_scop *scop) { die(); } -void pet_scop_get_tagged_must_kills() { +__isl_give isl_union_map *pet_scop_get_tagged_must_kills( + __isl_keep pet_scop *scop) { die(); } -void pet_expr_call_get_name() { +__isl_keep const char *pet_expr_call_get_name(__isl_keep pet_expr *expr) { die(); } -void pet_expr_call_set_name() { +__isl_give pet_expr *pet_expr_call_set_name(__isl_take pet_expr *expr, + __isl_keep const char *name) { die(); } -void pet_expr_get_arg() { +__isl_give pet_expr *pet_expr_get_arg(__isl_keep pet_expr *expr, int pos) { die(); } -void pet_expr_new_cast() { +__isl_give pet_expr *pet_expr_new_cast(const char *type_name, + __isl_take pet_expr *arg) { die(); } -void pet_expr_set_arg() { +__isl_give pet_expr *pet_expr_set_arg(__isl_take pet_expr *expr, int pos, + __isl_take pet_expr *arg) { die(); } -void pet_tree_copy() { +__isl_give pet_tree *pet_tree_copy(__isl_keep pet_tree *tree) { die(); } -void pet_tree_free() { +__isl_null pet_tree *pet_tree_free(__isl_take pet_tree *tree) { die(); } -void pet_tree_map_call_expr() { +__isl_give pet_tree *pet_tree_map_call_expr(__isl_take pet_tree *tree, + __isl_give pet_expr *(*fn)(__isl_take pet_expr *expr, void *user), + void *user) { die(); } -void pet_expr_access_get_may_read() { +__isl_give isl_union_map *pet_expr_access_get_may_read( + __isl_keep pet_expr *expr) { die(); } -void pet_expr_access_get_may_write() { +__isl_give isl_union_map *pet_expr_access_get_may_write( + __isl_keep pet_expr *expr) { die(); } From llvm-branch-commits at lists.llvm.org Mon May 3 17:23:30 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:23:30 -0700 (PDT) Subject: [llvm-branch-commits] [clang] 3263c81 - Partially Revert "scan-view: Remove Reporter.py and associated AppleScript files" Message-ID: <60909402.1c69fb81.8c0f3.c7c9@mx.google.com> Author: Tom Stellard Date: 2021-05-03T17:23:00-07:00 New Revision: 3263c81589eca689341ab5084723bdb7fe4a1286 URL: https://github.com/llvm/llvm-project/commit/3263c81589eca689341ab5084723bdb7fe4a1286 DIFF: https://github.com/llvm/llvm-project/commit/3263c81589eca689341ab5084723bdb7fe4a1286.diff LOG: Partially Revert "scan-view: Remove Reporter.py and associated AppleScript files" This reverts some of commit dbb01536f6f49fa428f170e34466072ef439b3e9. The Reporter module was still being used by the ScanView.py module and deleting it caused scan-view to fail. This commit adds back Reporter.py but removes the code the references the AppleScript files which were removed in dbb01536f6f49fa428f170e34466072ef439b3e9. Reviewed By: NoQ Differential Revision: https://reviews.llvm.org/D96367 (cherry picked from commit e3cd3a3c91524c957e06bb0170343548f02b6842) Added: clang/tools/scan-view/share/Reporter.py Modified: clang/tools/scan-view/CMakeLists.txt Removed: ################################################################################ diff --git a/clang/tools/scan-view/CMakeLists.txt b/clang/tools/scan-view/CMakeLists.txt index dd3d33439299a..eccc6b83195b6 100644 --- a/clang/tools/scan-view/CMakeLists.txt +++ b/clang/tools/scan-view/CMakeLists.txt @@ -5,6 +5,7 @@ set(BinFiles set(ShareFiles ScanView.py + Reporter.py startfile.py bugcatcher.ico) diff --git a/clang/tools/scan-view/share/Reporter.py b/clang/tools/scan-view/share/Reporter.py new file mode 100644 index 0000000000000..31a14fb0cf74e --- /dev/null +++ b/clang/tools/scan-view/share/Reporter.py @@ -0,0 +1,183 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Methods for reporting bugs.""" + +import subprocess, sys, os + +__all__ = ['ReportFailure', 'BugReport', 'getReporters'] + +# + +class ReportFailure(Exception): + """Generic exception for failures in bug reporting.""" + def __init__(self, value): + self.value = value + +# Collect information about a bug. + +class BugReport(object): + def __init__(self, title, description, files): + self.title = title + self.description = description + self.files = files + +# Reporter interfaces. + +import os + +import email, mimetypes, smtplib +from email import encoders +from email.message import Message +from email.mime.base import MIMEBase +from email.mime.multipart import MIMEMultipart +from email.mime.text import MIMEText + +#===------------------------------------------------------------------------===# +# ReporterParameter +#===------------------------------------------------------------------------===# + +class ReporterParameter(object): + def __init__(self, n): + self.name = n + def getName(self): + return self.name + def getValue(self,r,bugtype,getConfigOption): + return getConfigOption(r.getName(),self.getName()) + def saveConfigValue(self): + return True + +class TextParameter (ReporterParameter): + def getHTML(self,r,bugtype,getConfigOption): + return """\ + +%s: + +"""%(self.getName(),r.getName(),self.getName(),self.getValue(r,bugtype,getConfigOption)) + +class SelectionParameter (ReporterParameter): + def __init__(self, n, values): + ReporterParameter.__init__(self,n) + self.values = values + + def getHTML(self,r,bugtype,getConfigOption): + default = self.getValue(r,bugtype,getConfigOption) + return """\ + +%s:"""%(self.getName(),r.getName(),self.getName(),'\n'.join(["""\ +"""%(o[0], + o[0] == default and ' selected="selected"' or '', + o[1]) for o in self.values])) + +#===------------------------------------------------------------------------===# +# Reporters +#===------------------------------------------------------------------------===# + +class EmailReporter(object): + def getName(self): + return 'Email' + + def getParameters(self): + return [TextParameter(x) for x in ['To', 'From', 'SMTP Server', 'SMTP Port']] + + # Lifted from python email module examples. + def attachFile(self, outer, path): + # Guess the content type based on the file's extension. Encoding + # will be ignored, although we should check for simple things like + # gzip'd or compressed files. + ctype, encoding = mimetypes.guess_type(path) + if ctype is None or encoding is not None: + # No guess could be made, or the file is encoded (compressed), so + # use a generic bag-of-bits type. + ctype = 'application/octet-stream' + maintype, subtype = ctype.split('/', 1) + if maintype == 'text': + fp = open(path) + # Note: we should handle calculating the charset + msg = MIMEText(fp.read(), _subtype=subtype) + fp.close() + else: + fp = open(path, 'rb') + msg = MIMEBase(maintype, subtype) + msg.set_payload(fp.read()) + fp.close() + # Encode the payload using Base64 + encoders.encode_base64(msg) + # Set the filename parameter + msg.add_header('Content-Disposition', 'attachment', filename=os.path.basename(path)) + outer.attach(msg) + + def fileReport(self, report, parameters): + mainMsg = """\ +BUG REPORT +--- +Title: %s +Description: %s +"""%(report.title, report.description) + + if not parameters.get('To'): + raise ReportFailure('No "To" address specified.') + if not parameters.get('From'): + raise ReportFailure('No "From" address specified.') + + msg = MIMEMultipart() + msg['Subject'] = 'BUG REPORT: %s'%(report.title) + # FIXME: Get config parameters + msg['To'] = parameters.get('To') + msg['From'] = parameters.get('From') + msg.preamble = mainMsg + + msg.attach(MIMEText(mainMsg, _subtype='text/plain')) + for file in report.files: + self.attachFile(msg, file) + + try: + s = smtplib.SMTP(host=parameters.get('SMTP Server'), + port=parameters.get('SMTP Port')) + s.sendmail(msg['From'], msg['To'], msg.as_string()) + s.close() + except: + raise ReportFailure('Unable to send message via SMTP.') + + return "Message sent!" + +class BugzillaReporter(object): + def getName(self): + return 'Bugzilla' + + def getParameters(self): + return [TextParameter(x) for x in ['URL','Product']] + + def fileReport(self, report, parameters): + raise NotImplementedError + + +class RadarClassificationParameter(SelectionParameter): + def __init__(self): + SelectionParameter.__init__(self,"Classification", + [['1', 'Security'], ['2', 'Crash/Hang/Data Loss'], + ['3', 'Performance'], ['4', 'UI/Usability'], + ['6', 'Serious Bug'], ['7', 'Other']]) + + def saveConfigValue(self): + return False + + def getValue(self,r,bugtype,getConfigOption): + if bugtype.find("leak") != -1: + return '3' + elif bugtype.find("dereference") != -1: + return '2' + elif bugtype.find("missing ivar release") != -1: + return '3' + else: + return '7' + +### + +def getReporters(): + reporters = [] + reporters.append(EmailReporter()) + return reporters + From llvm-branch-commits at lists.llvm.org Mon May 3 17:30:13 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:30:13 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] c1831fc - [RISCV] Fix isel pattern of masked vmslt[u] Message-ID: <60909595.1c69fb81.4278c.c213@mx.google.com> Author: ShihPo Hung Date: 2021-05-03T17:29:55-07:00 New Revision: c1831fc655979a0501a792f730d84d68e15a888e URL: https://github.com/llvm/llvm-project/commit/c1831fc655979a0501a792f730d84d68e15a888e DIFF: https://github.com/llvm/llvm-project/commit/c1831fc655979a0501a792f730d84d68e15a888e.diff LOG: [RISCV] Fix isel pattern of masked vmslt[u] This patch changes the operand order of masked vmslt[u] from (mask, rs1, scalar, maskedoff, vl) to (maskedoff, rs1, scalar, mask, vl). Reviewed By: craig.topper Differential Revision: https://reviews.llvm.org/D98839 (cherry picked from commit fca5d63aa8d43a21557874d9bc040e944ab0500d) Added: Modified: llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td llvm/test/CodeGen/RISCV/rvv/vmslt-rv32.ll llvm/test/CodeGen/RISCV/rvv/vmslt-rv64.ll llvm/test/CodeGen/RISCV/rvv/vmsltu-rv32.ll llvm/test/CodeGen/RISCV/rvv/vmsltu-rv64.ll Removed: ################################################################################ diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td index 60bd1b24cab85..5c228820f0cc8 100644 --- a/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td +++ b/llvm/lib/Target/RISCV/RISCVInstrInfoVPseudos.td @@ -3909,10 +3909,10 @@ foreach vti = AllIntegerVectors in { (DecImm simm5_plus1:$rs2), GPR:$vl, vti.SEW)>; - def : Pat<(vti.Mask (int_riscv_vmslt_mask (vti.Mask V0), + def : Pat<(vti.Mask (int_riscv_vmslt_mask (vti.Mask VR:$merge), (vti.Vector vti.RegClass:$rs1), (vti.Scalar simm5_plus1:$rs2), - (vti.Mask VR:$merge), + (vti.Mask V0), (XLenVT (VLOp GPR:$vl)))), (!cast("PseudoVMSLE_VI_"#vti.LMul.MX#"_MASK") VR:$merge, @@ -3922,17 +3922,17 @@ foreach vti = AllIntegerVectors in { GPR:$vl, vti.SEW)>; - def : Pat<(vti.Mask (int_riscv_vmsltu (vti.Vector vti.RegClass:$rs1), + def : Pat<(vti.Mask (int_riscv_vmsltu (vti.Vector vti.RegClass:$rs1), (vti.Scalar simm5_plus1:$rs2), (XLenVT (VLOp GPR:$vl)))), (!cast("PseudoVMSLEU_VI_"#vti.LMul.MX) vti.RegClass:$rs1, (DecImm simm5_plus1:$rs2), GPR:$vl, vti.SEW)>; - def : Pat<(vti.Mask (int_riscv_vmsltu_mask (vti.Mask V0), + def : Pat<(vti.Mask (int_riscv_vmsltu_mask (vti.Mask VR:$merge), (vti.Vector vti.RegClass:$rs1), (vti.Scalar simm5_plus1:$rs2), - (vti.Mask VR:$merge), + (vti.Mask V0), (XLenVT (VLOp GPR:$vl)))), (!cast("PseudoVMSLEU_VI_"#vti.LMul.MX#"_MASK") VR:$merge, @@ -3950,11 +3950,11 @@ foreach vti = AllIntegerVectors in { vti.RegClass:$rs1, GPR:$vl, vti.SEW)>; - def : Pat<(vti.Mask (int_riscv_vmsltu_mask (vti.Mask V0), - (vti.Vector vti.RegClass:$rs1), - (vti.Scalar 0), - (vti.Mask VR:$merge), - (XLenVT (VLOp GPR:$vl)))), + def : Pat<(vti.Mask (int_riscv_vmsltu_mask (vti.Mask VR:$merge), + (vti.Vector vti.RegClass:$rs1), + (vti.Scalar 0), + (vti.Mask V0), + (XLenVT (VLOp GPR:$vl)))), (!cast("PseudoVMSNE_VV_"#vti.LMul.MX#"_MASK") VR:$merge, vti.RegClass:$rs1, diff --git a/llvm/test/CodeGen/RISCV/rvv/vmslt-rv32.ll b/llvm/test/CodeGen/RISCV/rvv/vmslt-rv32.ll index 894a232a167db..a51949573c979 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmslt-rv32.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmslt-rv32.ll @@ -1504,9 +1504,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf8,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -15, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -15, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i8.i8( @@ -1537,9 +1539,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf4,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -13, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -13, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i8.i8( @@ -1570,9 +1574,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -11, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -11, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i8.i8( @@ -1603,9 +1609,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -9, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -9, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i8.i8( @@ -1636,9 +1644,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv16i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv16i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, -7, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, -7, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv16i8.i8( @@ -1669,9 +1679,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv32i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv32i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, -5, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, -5, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv32i8.i8( @@ -1702,9 +1714,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf4,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -3, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -3, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i16.i16( @@ -1735,9 +1749,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -1, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -1, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i16.i16( @@ -1768,9 +1784,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 0, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 0, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i16.i16( @@ -1801,9 +1819,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, 2, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, 2, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i16.i16( @@ -1834,9 +1854,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv16i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv16i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, 4, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, 4, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv16i16.i16( @@ -1867,9 +1889,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 6, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 6, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i32.i32( @@ -1900,9 +1924,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i32.i32( @@ -1933,9 +1959,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, 10, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, 10, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i32.i32( @@ -1966,9 +1994,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, 12, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, 12, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i32.i32( diff --git a/llvm/test/CodeGen/RISCV/rvv/vmslt-rv64.ll b/llvm/test/CodeGen/RISCV/rvv/vmslt-rv64.ll index 7802c2a84ff81..c75f37c440d50 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmslt-rv64.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmslt-rv64.ll @@ -1801,9 +1801,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf8,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -15, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -15, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i8.i8( @@ -1834,9 +1836,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf4,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -13, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -13, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i8.i8( @@ -1867,9 +1871,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -11, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -11, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i8.i8( @@ -1900,9 +1906,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -9, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -9, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i8.i8( @@ -1933,9 +1941,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv16i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv16i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, -7, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, -7, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv16i8.i8( @@ -1966,9 +1976,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv32i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv32i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, -5, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, -5, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv32i8.i8( @@ -1999,9 +2011,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf4,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -3, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -3, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i16.i16( @@ -2032,9 +2046,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, -1, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, -1, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i16.i16( @@ -2065,9 +2081,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 0, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 0, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i16.i16( @@ -2098,9 +2116,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, 2, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, 2, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i16.i16( @@ -2131,9 +2151,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv16i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv16i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, 4, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, 4, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv16i16.i16( @@ -2164,9 +2186,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,mf2,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 6, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 6, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i32.i32( @@ -2197,9 +2221,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i32.i32( @@ -2230,9 +2256,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, 10, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, 10, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i32.i32( @@ -2263,9 +2291,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv8i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv8i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, 12, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, 12, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv8i32.i32( @@ -2296,9 +2326,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv1i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv1i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m1,tu,mu -; CHECK-NEXT: vmsle.vi v9, v8, 14, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsle.vi v25, v8, 14, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv1i64.i64( @@ -2329,9 +2361,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv2i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv2i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m2,tu,mu -; CHECK-NEXT: vmsle.vi v10, v8, -16, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsle.vi v25, v8, -16, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv2i64.i64( @@ -2362,9 +2396,11 @@ entry: define @intrinsic_vmslt_mask_vi_nxv4i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmslt_mask_vi_nxv4i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m4,tu,mu -; CHECK-NEXT: vmsle.vi v12, v8, -14, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsle.vi v25, v8, -14, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmslt.mask.nxv4i64.i64( diff --git a/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv32.ll b/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv32.ll index 8cd17ead0234a..ca78411b24c24 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv32.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv32.ll @@ -1504,9 +1504,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf8,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -15, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -15, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i8.i8( @@ -1537,9 +1539,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf4,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -13, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -13, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i8.i8( @@ -1570,9 +1574,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf2,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -11, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -11, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i8.i8( @@ -1603,9 +1609,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -9, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -9, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i8.i8( @@ -1636,9 +1644,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv16i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv16i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, -7, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, -7, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv16i8.i8( @@ -1669,9 +1679,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv32i8_i8( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv32i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, -5, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, -5, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv32i8.i8( @@ -1702,9 +1714,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf4,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -3, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -3, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i16.i16( @@ -1735,9 +1749,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf2,tu,mu -; CHECK-NEXT: vmsne.vv v9, v8, v8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsne.vv v25, v8, v8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i16.i16( @@ -1768,9 +1784,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 0, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 0, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i16.i16( @@ -1801,9 +1819,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, 2, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, 2, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i16.i16( @@ -1834,9 +1854,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv16i16_i16( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv16i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, 4, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, 4, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv16i16.i16( @@ -1867,9 +1889,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,mf2,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 6, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 6, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i32.i32( @@ -1900,9 +1924,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i32.i32( @@ -1933,9 +1959,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, 10, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, 10, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i32.i32( @@ -1966,9 +1994,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i32_i32( %0, %1, %2, i32 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, 12, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, 12, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i32.i32( diff --git a/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv64.ll b/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv64.ll index 83dc531750eed..a145dd684bacd 100644 --- a/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv64.ll +++ b/llvm/test/CodeGen/RISCV/rvv/vmsltu-rv64.ll @@ -1801,9 +1801,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf8,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -15, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -15, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i8.i8( @@ -1834,9 +1836,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf4,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -13, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -13, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i8.i8( @@ -1867,9 +1871,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,mf2,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -11, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -11, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i8.i8( @@ -1900,9 +1906,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -9, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -9, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i8.i8( @@ -1933,9 +1941,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv16i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv16i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, -7, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, -7, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv16i8.i8( @@ -1966,9 +1976,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv32i8_i8( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv32i8_i8: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e8,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, -5, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, -5, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv32i8.i8( @@ -1999,9 +2011,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf4,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, -3, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, -3, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i16.i16( @@ -2032,9 +2046,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,mf2,tu,mu -; CHECK-NEXT: vmsne.vv v9, v8, v8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsne.vv v25, v8, v8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i16.i16( @@ -2065,9 +2081,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 0, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 0, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i16.i16( @@ -2098,9 +2116,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, 2, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, 2, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i16.i16( @@ -2131,9 +2151,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv16i16_i16( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv16i16_i16: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e16,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, 4, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, 4, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv16i16.i16( @@ -2164,9 +2186,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,mf2,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 6, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 6, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i32.i32( @@ -2197,9 +2221,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 8, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 8, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i32.i32( @@ -2230,9 +2256,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, 10, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, 10, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i32.i32( @@ -2263,9 +2291,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv8i32_i32( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv8i32_i32: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e32,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, 12, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, 12, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv8i32.i32( @@ -2296,9 +2326,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv1i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv1i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m1,tu,mu -; CHECK-NEXT: vmsleu.vi v9, v8, 14, v0.t ; CHECK-NEXT: vmv1r.v v0, v9 +; CHECK-NEXT: vmsleu.vi v25, v8, 14, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv1i64.i64( @@ -2329,9 +2361,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv2i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv2i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m2,tu,mu -; CHECK-NEXT: vmsleu.vi v10, v8, -16, v0.t ; CHECK-NEXT: vmv1r.v v0, v10 +; CHECK-NEXT: vmsleu.vi v25, v8, -16, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv2i64.i64( @@ -2362,9 +2396,11 @@ entry: define @intrinsic_vmsltu_mask_vi_nxv4i64_i64( %0, %1, %2, i64 %3) nounwind { ; CHECK-LABEL: intrinsic_vmsltu_mask_vi_nxv4i64_i64: ; CHECK: # %bb.0: # %entry +; CHECK-NEXT: vmv1r.v v25, v0 ; CHECK-NEXT: vsetvli a0, a0, e64,m4,tu,mu -; CHECK-NEXT: vmsleu.vi v12, v8, -14, v0.t ; CHECK-NEXT: vmv1r.v v0, v12 +; CHECK-NEXT: vmsleu.vi v25, v8, -14, v0.t +; CHECK-NEXT: vmv1r.v v0, v25 ; CHECK-NEXT: jalr zero, 0(ra) entry: %a = call @llvm.riscv.vmsltu.mask.nxv4i64.i64( From llvm-branch-commits at lists.llvm.org Mon May 3 17:32:44 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:32:44 -0700 (PDT) Subject: [llvm-branch-commits] [clang] e0fe1c5 - [OpenCL] Respect calling convention for builtin Message-ID: <6090962c.1c69fb81.93f49.2a12@mx.google.com> Author: Luke Drummond Date: 2021-05-03T17:32:26-07:00 New Revision: e0fe1c58acfa0bde36afde8354cb31fc1e0b75e2 URL: https://github.com/llvm/llvm-project/commit/e0fe1c58acfa0bde36afde8354cb31fc1e0b75e2 DIFF: https://github.com/llvm/llvm-project/commit/e0fe1c58acfa0bde36afde8354cb31fc1e0b75e2.diff LOG: [OpenCL] Respect calling convention for builtin `__translate_sampler_initializer` has a calling convention of `spir_func`, but clang generated calls to it using the default CC. Instruction Combining was lowering these mismatching calling conventions to `store i1* undef` which itself was subsequently lowered to a trap instruction by simplifyCFG resulting in runtime `SIGILL` There are arguably two bugs here: but whether there's any wisdom in converting an obviously invalid call into a runtime crash over aborting with a sensible error message will require further discussion. So for now it's enough to set the right calling convention on the runtime helper. Reviewed By: svenh, bader Differential Revision: https://reviews.llvm.org/D98411 (cherry picked from commit fcfd3fda71905d7c48f75a531c2265ad3b9876ea) Added: Modified: clang/lib/CodeGen/CodeGenModule.cpp clang/test/CodeGenOpenCL/sampler.cl Removed: ################################################################################ diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 31afbc6b42628..9c9bd4e374af7 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -6215,15 +6215,17 @@ llvm::SanitizerStatReport &CodeGenModule::getSanStats() { return *SanStats; } + llvm::Value * CodeGenModule::createOpenCLIntToSamplerConversion(const Expr *E, CodeGenFunction &CGF) { llvm::Constant *C = ConstantEmitter(CGF).emitAbstract(E, E->getType()); - auto SamplerT = getOpenCLRuntime().getSamplerType(E->getType().getTypePtr()); - auto FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false); - return CGF.Builder.CreateCall(CreateRuntimeFunction(FTy, - "__translate_sampler_initializer"), - {C}); + auto *SamplerT = getOpenCLRuntime().getSamplerType(E->getType().getTypePtr()); + auto *FTy = llvm::FunctionType::get(SamplerT, {C->getType()}, false); + auto *Call = CGF.Builder.CreateCall( + CreateRuntimeFunction(FTy, "__translate_sampler_initializer"), {C}); + Call->setCallingConv(Call->getCalledFunction()->getCallingConv()); + return Call; } CharUnits CodeGenModule::getNaturalPointeeTypeAlignment( diff --git a/clang/test/CodeGenOpenCL/sampler.cl b/clang/test/CodeGenOpenCL/sampler.cl index e6bda49f51c8d..5ad8d0dbbf376 100644 --- a/clang/test/CodeGenOpenCL/sampler.cl +++ b/clang/test/CodeGenOpenCL/sampler.cl @@ -39,7 +39,7 @@ kernel void foo(sampler_t smp_par) { // Case 2b sampler_t smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_NEAREST; // CHECK: [[smp_ptr:%[A-Za-z0-9_\.]+]] = alloca %opencl.sampler_t addrspace(2)* - // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 19) + // CHECK: [[SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 19) // CHECK: store %opencl.sampler_t addrspace(2)* [[SAMP]], %opencl.sampler_t addrspace(2)** [[smp_ptr]] // Case 1b @@ -56,12 +56,12 @@ kernel void foo(sampler_t smp_par) { // Case 1a/2a fnc4smp(glb_smp); - // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) + // CHECK: [[SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) // CHECK: call spir_func void [[FUNCNAME]](%opencl.sampler_t addrspace(2)* [[SAMP]]) // Case 1a/2c fnc4smp(glb_smp_const); - // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) + // CHECK: [[SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) // CHECK: call spir_func void [[FUNCNAME]](%opencl.sampler_t addrspace(2)* [[SAMP]]) // Case 1c @@ -70,12 +70,12 @@ kernel void foo(sampler_t smp_par) { // CHECK: call spir_func void [[FUNCNAME]](%opencl.sampler_t addrspace(2)* [[SAMP]]) fnc4smp(5); - // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 5) + // CHECK: [[SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 5) // CHECK: call spir_func void [[FUNCNAME]](%opencl.sampler_t addrspace(2)* [[SAMP]]) const sampler_t const_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR; fnc4smp(const_smp); - // CHECK: [[CONST_SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) + // CHECK: [[CONST_SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) // CHECK: store %opencl.sampler_t addrspace(2)* [[CONST_SAMP]], %opencl.sampler_t addrspace(2)** [[CONST_SMP_PTR:%[a-zA-Z0-9]+]] fnc4smp(const_smp); // CHECK: [[SAMP:%[0-9]+]] = load %opencl.sampler_t addrspace(2)*, %opencl.sampler_t addrspace(2)** [[CONST_SMP_PTR]] @@ -83,7 +83,7 @@ kernel void foo(sampler_t smp_par) { constant sampler_t constant_smp = CLK_ADDRESS_CLAMP_TO_EDGE | CLK_NORMALIZED_COORDS_TRUE | CLK_FILTER_LINEAR; fnc4smp(constant_smp); - // CHECK: [[SAMP:%[0-9]+]] = call %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) + // CHECK: [[SAMP:%[0-9]+]] = call spir_func %opencl.sampler_t addrspace(2)* @__translate_sampler_initializer(i32 35) // CHECK: call spir_func void [[FUNCNAME]](%opencl.sampler_t addrspace(2)* [[SAMP]]) // TODO: enable sampler initialization with non-constant integer. From llvm-branch-commits at lists.llvm.org Mon May 3 17:38:14 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:38:14 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] a5a6cfe - BPF: permit type modifiers for __builtin_btf_type_id() relocation Message-ID: <60909776.1c69fb81.551d.26a0@mx.google.com> Author: Yonghong Song Date: 2021-05-03T17:37:51-07:00 New Revision: a5a6cfe2f030e81e689ed9af4e95ddf95c4d8675 URL: https://github.com/llvm/llvm-project/commit/a5a6cfe2f030e81e689ed9af4e95ddf95c4d8675 DIFF: https://github.com/llvm/llvm-project/commit/a5a6cfe2f030e81e689ed9af4e95ddf95c4d8675.diff LOG: BPF: permit type modifiers for __builtin_btf_type_id() relocation Lorenz Bauer from Cloudflare tried to use "const struct " as the type for __builtin_btf_type_id(*(const struct )0, 1) relocation and hit a llvm BPF fatal error. https://lore.kernel.org/bpf/a3782f71-3f6b-1e75-17a9-1827822c2030 at fb.com/ ... fatal error: error in backend: Empty type name for BTF_TYPE_ID_REMOTE reloc Currently, we require the debuginfo type itself must have a name. In this case, the debuginfo type is "const" which points to "struct ". The "const" type does not have a name, hence the above fatal error will be triggered. Let us permit "const" and "volatile" type modifiers. We skip modifiers in some other cases as well like structure member type tracing. This can aviod the above fatal error. Differential Revision: https://reviews.llvm.org/D97986 (cherry picked from commit 9c0274cdeae904089806be6faee72b9126d2cf5b) Added: llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id-2.ll Modified: llvm/lib/Target/BPF/BPFPreserveDIType.cpp Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/BPFPreserveDIType.cpp b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp index 18a4f60c171ae..0348e2200acbc 100644 --- a/llvm/lib/Target/BPF/BPFPreserveDIType.cpp +++ b/llvm/lib/Target/BPF/BPFPreserveDIType.cpp @@ -85,8 +85,17 @@ static bool BPFPreserveDITypeImpl(Function &F) { } else { Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE; DIType *Ty = cast(MD); + while (auto *DTy = dyn_cast(Ty)) { + unsigned Tag = DTy->getTag(); + if (Tag != dwarf::DW_TAG_const_type && + Tag != dwarf::DW_TAG_volatile_type) + break; + Ty = DTy->getBaseType(); + } + if (Ty->getName().empty()) report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc"); + MD = Ty; } BasicBlock *BB = Call->getParent(); diff --git a/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id-2.ll b/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id-2.ll new file mode 100644 index 0000000000000..63c56c4dfec57 --- /dev/null +++ b/llvm/test/CodeGen/BPF/BTF/builtin-btf-type-id-2.ll @@ -0,0 +1,73 @@ +; RUN: opt -O2 -mtriple=bpf-pc-linux -S -o %t1 %s +; RUN: llc -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; RUN: llc -mattr=+alu32 -filetype=asm -o - %t1 | FileCheck -check-prefixes=CHECK %s +; Source code: +; struct s { +; int a; +; }; +; int test(void) { +; return __builtin_btf_type_id(*(const struct s *)0, 1); +; } +; Compilation flag: +; clang -target bpf -O2 -g -S -emit-llvm -Xclang -disable-llvm-passes test.c + +; Function Attrs: nounwind +define dso_local i32 @test() #0 !dbg !7 { +entry: + %0 = call i64 @llvm.bpf.btf.type.id(i32 0, i64 1), !dbg !11, !llvm.preserve.access.index !12 + %conv = trunc i64 %0 to i32, !dbg !11 + ret i32 %conv, !dbg !16 +} + +; CHECK: .long 1 # BTF_KIND_INT(id = 2) +; CHECK-NEXT: .long 16777216 # 0x1000000 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 16777248 # 0x1000020 + +; CHECK: .long 16 # BTF_KIND_STRUCT(id = 4) +; CHECK-NEXT: .long 67108865 # 0x4000001 +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 18 +; CHECK-NEXT: .long 2 + +; CHECK: .ascii "int" # string offset=1 +; CHECK: .ascii ".text" # string offset=10 +; CHECK: .byte 115 # string offset=16 +; CHECK: .byte 97 # string offset=18 +; CHECK: .byte 48 # string offset=20 + +; CHECK: .long 16 # FieldReloc +; CHECK-NEXT: .long 10 # Field reloc section string offset=10 +; CHECK-NEXT: .long 1 +; CHECK-NEXT: .long .Ltmp{{[0-9]+}} +; CHECK-NEXT: .long 4 +; CHECK-NEXT: .long 20 +; CHECK-NEXT: .long 7 + +; Function Attrs: nounwind readnone +declare i64 @llvm.bpf.btf.type.id(i32, i64) #1 + +attributes #0 = { nounwind "frame-pointer"="all" "no-trapping-math"="true" "stack-protector-buffer-size"="8" } +attributes #1 = { nounwind readnone } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C99, file: !1, producer: "clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9783e2098800b954c55ae598a1ce5c4b93444fc0)", isOptimized: true, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, nameTableKind: None) +!1 = !DIFile(filename: "test.c", directory: "/tmp/home/yhs/bpf/test") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 13.0.0 (https://github.com/llvm/llvm-project.git 9783e2098800b954c55ae598a1ce5c4b93444fc0)"} +!7 = distinct !DISubprogram(name: "test", scope: !1, file: !1, line: 4, type: !8, scopeLine: 4, flags: DIFlagPrototyped | DIFlagAllCallsDescribed, spFlags: DISPFlagDefinition | DISPFlagOptimized, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 5, column: 10, scope: !7) +!12 = !DIDerivedType(tag: DW_TAG_const_type, baseType: !13) +!13 = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "s", file: !1, line: 1, size: 32, elements: !14) +!14 = !{!15} +!15 = !DIDerivedType(tag: DW_TAG_member, name: "a", scope: !13, file: !1, line: 2, baseType: !10, size: 32) +!16 = !DILocation(line: 5, column: 3, scope: !7) From llvm-branch-commits at lists.llvm.org Mon May 3 17:39:12 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:39:12 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 6564e0c - BPF: Fix a bug in peephole TRUNC elimination optimization Message-ID: <609097b0.1c69fb81.8dd39.2203@mx.google.com> Author: Yonghong Song Date: 2021-05-03T17:39:00-07:00 New Revision: 6564e0cf7e61518cb15443fca42bc2206a6123e2 URL: https://github.com/llvm/llvm-project/commit/6564e0cf7e61518cb15443fca42bc2206a6123e2 DIFF: https://github.com/llvm/llvm-project/commit/6564e0cf7e61518cb15443fca42bc2206a6123e2.diff LOG: BPF: Fix a bug in peephole TRUNC elimination optimization Andrei Matei reported a llvm11 core dump for his bpf program https://bugs.llvm.org/show_bug.cgi?id=48578 The core dump happens in LiveVariables analysis phase. #4 0x00007fce54356bb0 __restore_rt #5 0x00007fce4d51785e llvm::LiveVariables::HandleVirtRegUse(unsigned int, llvm::MachineBasicBlock*, llvm::MachineInstr&) #6 0x00007fce4d519abe llvm::LiveVariables::runOnInstr(llvm::MachineInstr&, llvm::SmallVectorImpl&) #7 0x00007fce4d519ec6 llvm::LiveVariables::runOnBlock(llvm::MachineBasicBlock*, unsigned int) #8 0x00007fce4d51a4bf llvm::LiveVariables::runOnMachineFunction(llvm::MachineFunction&) The bug can be reproduced with llvm12 and latest trunk as well. Futher analysis shows that there is a bug in BPF peephole TRUNC elimination optimization, which tries to remove unnecessary TRUNC operations (a <<= 32; a >>= 32). Specifically, the compiler did wrong transformation for the following patterns: %1 = LDW ... %2 = SLL_ri %1, 32 %3 = SRL_ri %2, 32 ... %3 ... %4 = SRA_ri %2, 32 ... %4 ... The current transformation did not check how many uses of %2 and did transformation like %1 = LDW ... ... %1 ... %4 = SRL_ri %2, 32 ... %4 ... and pseudo register %2 is used by not defined and caused LiveVariables analysis core dump. To fix the issue, when traversing back from SRL_ri to SLL_ri, check to ensure SLL_ri has only one use. Otherwise, don't do transformation. Differential Revision: https://reviews.llvm.org/D97792 (cherry picked from commit 51cdb780db3b9b46c783efcec672c4da272e9992) Added: llvm/test/CodeGen/BPF/remove_truncate_8.ll Modified: llvm/lib/Target/BPF/BPFMIPeephole.cpp Removed: ################################################################################ diff --git a/llvm/lib/Target/BPF/BPFMIPeephole.cpp b/llvm/lib/Target/BPF/BPFMIPeephole.cpp index df870314fffe3..354980e4bf3ce 100644 --- a/llvm/lib/Target/BPF/BPFMIPeephole.cpp +++ b/llvm/lib/Target/BPF/BPFMIPeephole.cpp @@ -475,6 +475,9 @@ bool BPFMIPeepholeTruncElim::eliminateTruncSeq(void) { if (MI.getOpcode() == BPF::SRL_ri && MI.getOperand(2).getImm() == 32) { SrcReg = MI.getOperand(1).getReg(); + if (!MRI->hasOneNonDBGUse(SrcReg)) + continue; + MI2 = MRI->getVRegDef(SrcReg); DstReg = MI.getOperand(0).getReg(); diff --git a/llvm/test/CodeGen/BPF/remove_truncate_8.ll b/llvm/test/CodeGen/BPF/remove_truncate_8.ll new file mode 100644 index 0000000000000..fb1eabb0f0fd8 --- /dev/null +++ b/llvm/test/CodeGen/BPF/remove_truncate_8.ll @@ -0,0 +1,41 @@ +; RUN: llc < %s -march=bpf -verify-machineinstrs | FileCheck %s +; Source Code: +; struct loc_prog { +; unsigned int ip; +; int len; +; }; +; int exec_prog(struct loc_prog *prog) { +; if (prog->ip < prog->len) { +; int x = prog->ip; +; if (x < 3) +; prog->ip += 2; +; } +; return 3; +; } +; Compilation flag: +; clang -target bpf -O2 -S -emit-llvm t.c + +%struct.loc_prog = type { i32, i32 } + +; Function Attrs: nofree norecurse nounwind willreturn +define dso_local i32 @exec_prog(%struct.loc_prog* nocapture %prog) local_unnamed_addr { +entry: + %ip = getelementptr inbounds %struct.loc_prog, %struct.loc_prog* %prog, i64 0, i32 0 + %0 = load i32, i32* %ip, align 4 + %len = getelementptr inbounds %struct.loc_prog, %struct.loc_prog* %prog, i64 0, i32 1 + %1 = load i32, i32* %len, align 4 + %cmp = icmp ult i32 %0, %1 + %cmp2 = icmp slt i32 %0, 3 + %or.cond = and i1 %cmp2, %cmp +; CHECK: r{{[0-9]+}} <<= 32 +; CHECK: r{{[0-9]+}} s>>= 32 + br i1 %or.cond, label %if.then3, label %if.end5 + +if.then3: ; preds = %entry + %add = add nsw i32 %0, 2 + store i32 %add, i32* %ip, align 4 + br label %if.end5 + +if.end5: ; preds = %if.then3, %entry + ret i32 3 +} From llvm-branch-commits at lists.llvm.org Mon May 3 17:45:32 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 03 May 2021 17:45:32 -0700 (PDT) Subject: [llvm-branch-commits] [clang] e294ece - BPF: fix enum value 0 issue for __builtin_preserve_enum_value() Message-ID: <6090992c.1c69fb81.33e16.2c59@mx.google.com> Author: Yonghong Song Date: 2021-05-03T17:45:16-07:00 New Revision: e294ece42d85191875782ed05cb607451f493944 URL: https://github.com/llvm/llvm-project/commit/e294ece42d85191875782ed05cb607451f493944 DIFF: https://github.com/llvm/llvm-project/commit/e294ece42d85191875782ed05cb607451f493944.diff LOG: BPF: fix enum value 0 issue for __builtin_preserve_enum_value() Lorenz Bauer reported that the following code will have compilation error for bpf target: enum e { TWO }; bpf_core_enum_value_exists(enum e, TWO); The clang emitted the following error message: __builtin_preserve_enum_value argument 1 invalid In SemaChecking, an expression like "*(enum NAME)1" will have cast kind CK_IntegralToPointer, but "*(enum NAME)0" will have cast kind CK_NullToPointer. Current implementation only permits CK_IntegralToPointer, missing enum value 0 case. This patch permits CK_NullToPointer cast kind and the above test case can pass now. Differential Revision: https://reviews.llvm.org/D97659 (cherry picked from commit 283db5f0837d55f91242812003adf6e189ba743e) Added: Modified: clang/lib/Sema/SemaChecking.cpp clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c Removed: ################################################################################ diff --git a/clang/lib/Sema/SemaChecking.cpp b/clang/lib/Sema/SemaChecking.cpp index 2d3d36f4adad0..2b55712d44c27 100644 --- a/clang/lib/Sema/SemaChecking.cpp +++ b/clang/lib/Sema/SemaChecking.cpp @@ -2623,7 +2623,10 @@ static bool isValidBPFPreserveEnumValueArg(Expr *Arg) { return false; const auto *CE = dyn_cast(UO->getSubExpr()); - if (!CE || CE->getCastKind() != CK_IntegralToPointer) + if (!CE) + return false; + if (CE->getCastKind() != CK_IntegralToPointer && + CE->getCastKind() != CK_NullToPointer) return false; // The integer must be from an EnumConstantDecl. diff --git a/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c b/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c index e07c680bb3702..b167b776e385e 100644 --- a/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c +++ b/clang/test/CodeGen/builtins-bpf-preserve-field-info-4.c @@ -4,10 +4,11 @@ #define _(x, y) (__builtin_preserve_enum_value((x), (y))) enum AA { + VAL0 = 0, VAL1 = 2, VAL2 = 0xffffffff80000000UL, }; -typedef enum { VAL10 = -2, VAL11 = 0xffff8000, } __BB; +typedef enum { VAL00, VAL10 = -2, VAL11 = 0xffff8000, } __BB; unsigned unit1() { return _(*(enum AA *)VAL1, 0) + _(*(__BB *)VAL10, 1); @@ -17,10 +18,16 @@ unsigned unit2() { return _(*(enum AA *)VAL2, 0) + _(*(__BB *)VAL11, 1); } +unsigned unit3() { + return _(*(enum AA *)VAL0, 0) + _(*(__BB *)VAL00, 1); +} + // CHECK: @0 = private unnamed_addr constant [7 x i8] c"VAL1:2\00", align 1 // CHECK: @1 = private unnamed_addr constant [9 x i8] c"VAL10:-2\00", align 1 // CHECK: @2 = private unnamed_addr constant [17 x i8] c"VAL2:-2147483648\00", align 1 // CHECK: @3 = private unnamed_addr constant [17 x i8] c"VAL11:4294934528\00", align 1 +// CHECK: @4 = private unnamed_addr constant [7 x i8] c"VAL0:0\00", align 1 +// CHECK: @5 = private unnamed_addr constant [8 x i8] c"VAL00:0\00", align 1 // CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 0, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @0, i32 0, i32 0), i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA:[0-9]+]] // CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 1, i8* getelementptr inbounds ([9 x i8], [9 x i8]* @1, i32 0, i32 0), i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_ENUM:[0-9]+]] @@ -28,5 +35,8 @@ unsigned unit2() { // CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 2, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @2, i32 0, i32 0), i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA]] // CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 3, i8* getelementptr inbounds ([17 x i8], [17 x i8]* @3, i32 0, i32 0), i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_ENUM]] +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 4, i8* getelementptr inbounds ([7 x i8], [7 x i8]* @4, i32 0, i32 0), i64 0), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[ENUM_AA]] +// CHECK: call i64 @llvm.bpf.preserve.enum.value(i32 5, i8* getelementptr inbounds ([8 x i8], [8 x i8]* @5, i32 0, i32 0), i64 1), !dbg !{{[0-9]+}}, !llvm.preserve.access.index ![[TYPEDEF_ENUM]] + // CHECK: ![[ENUM_AA]] = !DICompositeType(tag: DW_TAG_enumeration_type, name: "AA" // CHECK: ![[TYPEDEF_ENUM]] = !DIDerivedType(tag: DW_TAG_typedef, name: "__BB" From llvm-branch-commits at lists.llvm.org Thu May 6 16:51:34 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 16:51:34 -0700 (PDT) Subject: [llvm-branch-commits] [lldb] 6baa5ce - Fix typo, arvm7 -> armv7 Message-ID: <60948106.1c69fb81.cf2e7.91c5@mx.google.com> Author: Brad Smith Date: 2021-05-06T16:51:09-07:00 New Revision: 6baa5ce2e4b70424981ba5632d10681d41f57cfc URL: https://github.com/llvm/llvm-project/commit/6baa5ce2e4b70424981ba5632d10681d41f57cfc DIFF: https://github.com/llvm/llvm-project/commit/6baa5ce2e4b70424981ba5632d10681d41f57cfc.diff LOG: Fix typo, arvm7 -> armv7 (cherry picked from commit 3a62d4fde88544125ce9ceff990db108ee91148a) Added: Modified: lldb/docs/man/lldb.rst lldb/tools/driver/Driver.cpp Removed: ################################################################################ diff --git a/lldb/docs/man/lldb.rst b/lldb/docs/man/lldb.rst index 6dca15fa35dc..b75288db380d 100644 --- a/lldb/docs/man/lldb.rst +++ b/lldb/docs/man/lldb.rst @@ -256,11 +256,11 @@ executable. To disambiguate between arguments passed to lldb and arguments passed to the debugged executable, arguments starting with a - must be passed after --. - lldb --arch x86_64 /path/to/program program argument -- --arch arvm7 + lldb --arch x86_64 /path/to/program program argument -- --arch armv7 For convenience, passing the executable after -- is also supported. - lldb --arch x86_64 -- /path/to/program program argument --arch arvm7 + lldb --arch x86_64 -- /path/to/program program argument --arch armv7 Passing one of the attach options causes :program:`lldb` to immediately attach to the given process. diff --git a/lldb/tools/driver/Driver.cpp b/lldb/tools/driver/Driver.cpp index e4a60127b65e..210a712f9741 100644 --- a/lldb/tools/driver/Driver.cpp +++ b/lldb/tools/driver/Driver.cpp @@ -751,11 +751,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) { arguments passed to the debugged executable, arguments starting with a - must be passed after --. - lldb --arch x86_64 /path/to/program program argument -- --arch arvm7 + lldb --arch x86_64 /path/to/program program argument -- --arch armv7 For convenience, passing the executable after -- is also supported. - lldb --arch x86_64 -- /path/to/program program argument --arch arvm7 + lldb --arch x86_64 -- /path/to/program program argument --arch armv7 Passing one of the attach options causes lldb to immediately attach to the given process. From llvm-branch-commits at lists.llvm.org Thu May 6 17:00:57 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:00:57 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 471a386 - StackProtector: ensure protection does not interfere with tail call frame. Message-ID: <60948339.1c69fb81.fdc8f.a4fc@mx.google.com> Author: Tim Northover Date: 2021-05-06T16:59:08-07:00 New Revision: 471a386a3d348e933d200e1cc01413aa655d508e URL: https://github.com/llvm/llvm-project/commit/471a386a3d348e933d200e1cc01413aa655d508e DIFF: https://github.com/llvm/llvm-project/commit/471a386a3d348e933d200e1cc01413aa655d508e.diff LOG: StackProtector: ensure protection does not interfere with tail call frame. The IR stack protector pass must insert stack checks before the call instead of between it and the return. Similarly, SDAG one should recognize that ADJCALLFRAME instructions could be part of the terminal sequence of a tail call. In this case because such call frames cannot be nested in LLVM the stack protection code must skip over the whole sequence (or risk clobbering argument registers). (cherry picked from commit 5e3d9fcc3a8802cea5b850a3ca40c515d916bf82) Added: llvm/test/CodeGen/AArch64/stack-protector-musttail.ll llvm/test/CodeGen/ARM/Windows/stack-protector-musttail.ll llvm/test/CodeGen/X86/tailcc-ssp.ll Modified: llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp llvm/lib/CodeGen/StackProtector.cpp Removed: ################################################################################ diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp index 7bae5048fc0e..d17dd1c5eccb 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp @@ -1691,9 +1691,9 @@ static bool MIIsInTerminatorSequence(const MachineInstr &MI) { /// terminator, but additionally the copies that move the vregs into the /// physical registers. static MachineBasicBlock::iterator -FindSplitPointForStackProtector(MachineBasicBlock *BB) { +FindSplitPointForStackProtector(MachineBasicBlock *BB, + const TargetInstrInfo &TII) { MachineBasicBlock::iterator SplitPoint = BB->getFirstTerminator(); - // if (SplitPoint == BB->begin()) return SplitPoint; @@ -1701,6 +1701,31 @@ FindSplitPointForStackProtector(MachineBasicBlock *BB) { MachineBasicBlock::iterator Previous = SplitPoint; --Previous; + if (TII.isTailCall(*SplitPoint) && + Previous->getOpcode() == TII.getCallFrameDestroyOpcode()) { + // call itself, then we must insert before the sequence even starts. For + // example: + // + // ADJCALLSTACKDOWN ... + // + // ADJCALLSTACKUP ... + // TAILJMP somewhere + // On the other hand, it could be an unrelated call in which case this tail call + // has to register moves of its own and should be the split point. For example: + // ADJCALLSTACKDOWN + // CALL something_else + // ADJCALLSTACKUP + // + // TAILJMP somewhere + do { + --Previous; + if (Previous->isCall()) + return SplitPoint; + } while(Previous->getOpcode() != TII.getCallFrameSetupOpcode()); + + return Previous; + } + while (MIIsInTerminatorSequence(*Previous)) { SplitPoint = Previous; if (Previous == Start) @@ -1740,7 +1765,7 @@ SelectionDAGISel::FinishBasicBlock() { // Add load and check to the basicblock. FuncInfo->MBB = ParentMBB; FuncInfo->InsertPt = - FindSplitPointForStackProtector(ParentMBB); + FindSplitPointForStackProtector(ParentMBB, *TII); SDB->visitSPDescriptorParent(SDB->SPDescriptor, ParentMBB); CurDAG->setRoot(SDB->getRoot()); SDB->clear(); @@ -1759,7 +1784,7 @@ SelectionDAGISel::FinishBasicBlock() { // register allocation issues caused by us splitting the parent mbb. The // register allocator will clean up said virtual copies later on. MachineBasicBlock::iterator SplitPoint = - FindSplitPointForStackProtector(ParentMBB); + FindSplitPointForStackProtector(ParentMBB, *TII); // Splice the terminator of ParentMBB into SuccessMBB. SuccessMBB->splice(SuccessMBB->end(), ParentMBB, diff --git a/llvm/lib/CodeGen/StackProtector.cpp b/llvm/lib/CodeGen/StackProtector.cpp index 8d91afb6e99d..10c6dcbdb049 100644 --- a/llvm/lib/CodeGen/StackProtector.cpp +++ b/llvm/lib/CodeGen/StackProtector.cpp @@ -470,21 +470,36 @@ bool StackProtector::InsertStackProtectors() { // instrumentation has already been generated. HasIRCheck = true; + // If we're instrumenting a block with a musttail call, the check has to be + // inserted before the call rather than between it and the return. The + // verifier guarantees that a musttail call is either directly before the + // return or with a single correct bitcast of the return value in between so + // we don't need to worry about many situations here. + Instruction *CheckLoc = RI; + Instruction *Prev = RI->getPrevNonDebugInstruction(); + if (Prev && isa(Prev) && cast(Prev)->isMustTailCall()) + CheckLoc = Prev; + else if (Prev) { + Prev = Prev->getPrevNonDebugInstruction(); + if (Prev && isa(Prev) && cast(Prev)->isMustTailCall()) + CheckLoc = Prev; + } + // Generate epilogue instrumentation. The epilogue intrumentation can be // function-based or inlined depending on which mechanism the target is // providing. if (Function *GuardCheck = TLI->getSSPStackGuardCheck(*M)) { // Generate the function-based epilogue instrumentation. // The target provides a guard check function, generate a call to it. - IRBuilder<> B(RI); + IRBuilder<> B(CheckLoc); LoadInst *Guard = B.CreateLoad(B.getInt8PtrTy(), AI, true, "Guard"); CallInst *Call = B.CreateCall(GuardCheck, {Guard}); Call->setAttributes(GuardCheck->getAttributes()); Call->setCallingConv(GuardCheck->getCallingConv()); } else { // Generate the epilogue with inline instrumentation. - // If we do not support SelectionDAG based tail calls, generate IR level - // tail calls. + // If we do not support SelectionDAG based calls, generate IR level + // calls. // // For each block with a return instruction, convert this: // @@ -514,7 +529,8 @@ bool StackProtector::InsertStackProtectors() { BasicBlock *FailBB = CreateFailBB(); // Split the basic block before the return instruction. - BasicBlock *NewBB = BB->splitBasicBlock(RI->getIterator(), "SP_return"); + BasicBlock *NewBB = + BB->splitBasicBlock(CheckLoc->getIterator(), "SP_return"); // Update the dominator tree if we need to. if (DT && DT->isReachableFromEntry(BB)) { diff --git a/llvm/test/CodeGen/AArch64/stack-protector-musttail.ll b/llvm/test/CodeGen/AArch64/stack-protector-musttail.ll new file mode 100644 index 000000000000..8a2e095e6a64 --- /dev/null +++ b/llvm/test/CodeGen/AArch64/stack-protector-musttail.ll @@ -0,0 +1,66 @@ +; RUN: llc -mtriple=arm64-apple-macosx -fast-isel %s -o - -start-before=stack-protector -stop-after=stack-protector | FileCheck %s + + at var = global [2 x i64]* null + +declare void @callee() + +define void @caller1() ssp { +; CHECK-LABEL: define void @caller1() +; Prologue: +; CHECK: @llvm.stackguard + +; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard() +; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}} +; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]] +; CHECK: br i1 [[TST]] + +; CHECK: musttail call void @callee() +; CHECK-NEXT: ret void + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + musttail call void @callee() + ret void +} + +define void @justret() ssp { +; CHECK-LABEL: define void @justret() +; Prologue: +; CHECK: @llvm.stackguard + +; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard() +; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}} +; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]] +; CHECK: br i1 [[TST]] + +; CHECK: ret void + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + br label %retblock + +retblock: + ret void +} + + +declare i64* @callee2() + +define i8* @caller2() ssp { +; CHECK-LABEL: define i8* @caller2() +; Prologue: +; CHECK: @llvm.stackguard + +; CHECK: [[GUARD:%.*]] = call i8* @llvm.stackguard() +; CHECK: [[TOKEN:%.*]] = load volatile i8*, i8** {{%.*}} +; CHECK: [[TST:%.*]] = icmp eq i8* [[GUARD]], [[TOKEN]] +; CHECK: br i1 [[TST]] + +; CHECK: [[TMP:%.*]] = musttail call i64* @callee2() +; CHECK-NEXT: [[RES:%.*]] = bitcast i64* [[TMP]] to i8* +; CHECK-NEXT: ret i8* [[RES]] + + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + %tmp = musttail call i64* @callee2() + %res = bitcast i64* %tmp to i8* + ret i8* %res +} diff --git a/llvm/test/CodeGen/ARM/Windows/stack-protector-musttail.ll b/llvm/test/CodeGen/ARM/Windows/stack-protector-musttail.ll new file mode 100644 index 000000000000..93b601c9369f --- /dev/null +++ b/llvm/test/CodeGen/ARM/Windows/stack-protector-musttail.ll @@ -0,0 +1,56 @@ +; RUN: llc -mtriple=thumbv7-windows-msvc -fast-isel %s -o - -start-before=stack-protector -stop-after=stack-protector | FileCheck %s + + at var = global [2 x i64]* null + +declare void @callee() + +define void @caller1() sspreq { +; CHECK-LABEL: define void @caller1() +; Prologue: + +; CHECK: call void @__security_check_cookie + +; CHECK: musttail call void @callee() +; CHECK-NEXT: ret void + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + musttail call void @callee() + ret void +} + +define void @justret() sspreq { +; CHECK-LABEL: define void @justret() +; Prologue: +; CHECK: @llvm.stackguard + +; CHECK: call void @__security_check_cookie + +; CHECK: ret void + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + br label %retblock + +retblock: + ret void +} + + +declare i64* @callee2() + +define i8* @caller2() sspreq { +; CHECK-LABEL: define i8* @caller2() +; Prologue: +; CHECK: @llvm.stackguard + +; CHECK: call void @__security_check_cookie + +; CHECK: [[TMP:%.*]] = musttail call i64* @callee2() +; CHECK-NEXT: [[RES:%.*]] = bitcast i64* [[TMP]] to i8* +; CHECK-NEXT: ret i8* [[RES]] + + %var = alloca [2 x i64] + store [2 x i64]* %var, [2 x i64]** @var + %tmp = musttail call i64* @callee2() + %res = bitcast i64* %tmp to i8* + ret i8* %res +} diff --git a/llvm/test/CodeGen/X86/tailcc-ssp.ll b/llvm/test/CodeGen/X86/tailcc-ssp.ll new file mode 100644 index 000000000000..b85be6a5e790 --- /dev/null +++ b/llvm/test/CodeGen/X86/tailcc-ssp.ll @@ -0,0 +1,26 @@ +; RUN: llc -mtriple=x86_64-windows-msvc %s -o - -verify-machineinstrs | FileCheck %s + +declare void @h(i8*, i64, i8*) + +define tailcc void @tailcall_frame(i8* %0, i64 %1) sspreq { +; CHECK-LABEL: tailcall_frame: +; CHECK: callq __security_check_cookie +; CHECK: xorl %ecx, %ecx +; CHECK: jmp h + + tail call tailcc void @h(i8* null, i64 0, i8* null) + ret void +} + +declare void @bar() +define void @tailcall_unrelated_frame() sspreq { +; CHECK-LABEL: tailcall_unrelated_frame: +; CHECK: subq [[STACK:\$.*]], %rsp +; CHECK: callq bar +; CHECK: callq __security_check_cookie +; CHECK: addq [[STACK]], %rsp +; CHECK: jmp bar + call void @bar() + tail call void @bar() + ret void +} From llvm-branch-commits at lists.llvm.org Thu May 6 17:10:40 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:10:40 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] ac593de - [LoopReroll] Fix rerolling loop with extra instructions Message-ID: <60948580.1c69fb81.d465b.c19a@mx.google.com> Author: KAWASHIMA Takahiro Date: 2021-05-06T17:10:04-07:00 New Revision: ac593de16cc5282630ce44dd8378ae5b7b91644c URL: https://github.com/llvm/llvm-project/commit/ac593de16cc5282630ce44dd8378ae5b7b91644c DIFF: https://github.com/llvm/llvm-project/commit/ac593de16cc5282630ce44dd8378ae5b7b91644c.diff LOG: [LoopReroll] Fix rerolling loop with extra instructions Fixes PR47627 This fix suppresses rerolling a loop which has an unrerollable instruction. Sample IR for the explanation below: ``` define void @foo([2 x i32]* nocapture %a) { entry: br label %loop loop: ; base instruction %indvar = phi i64 [ 0, %entry ], [ %indvar.next, %loop ] ; unrerollable instructions %stptrx = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %indvar, i64 0 store i32 999, i32* %stptrx, align 4 ; extra simple arithmetic operations, used by root instructions %plus20 = add nuw nsw i64 %indvar, 20 %plus10 = add nuw nsw i64 %indvar, 10 ; root instruction 0 %ldptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 0 %value0 = load i32, i32* %ldptr0, align 4 %stptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 0 store i32 %value0, i32* %stptr0, align 4 ; root instruction 1 %ldptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 1 %value1 = load i32, i32* %ldptr1, align 4 %stptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 1 store i32 %value1, i32* %stptr1, align 4 ; loop-increment and latch %indvar.next = add nuw nsw i64 %indvar, 1 %exitcond = icmp eq i64 %indvar.next, 5 br i1 %exitcond, label %exit, label %loop exit: ret void } ``` In the loop rerolling pass, `%indvar` and `%indvar.next` are appended to the `LoopIncs` vector in the `LoopReroll::DAGRootTracker::findRoots` function. Before this fix, two instructions with `unrerollable instructions` comment above are marked as `IL_All` at the end of the `LoopReroll::DAGRootTracker::collectUsedInstructions` function, as well as instructions with `extra simple arithmetic operations` comment and `loop-increment and latch` comment. It is incorrect because `IL_All` means that the instruction should be executed in all iterations of the rerolled loop but the `store` instruction should not. This fix rejects instructions which may have side effects and don't belong to def-use chains of any root instructions and reductions. See https://bugs.llvm.org/show_bug.cgi?id=47627 for more information. (cherry picked from commit d9a9c992d190dd6645ea911b66cf0cadba0dadc3) Added: llvm/test/Transforms/LoopReroll/extra_instr.ll Modified: llvm/lib/Transforms/Scalar/LoopRerollPass.cpp Removed: ################################################################################ diff --git a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp index b3bae47e96de2..65a6205f03020 100644 --- a/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp +++ b/llvm/lib/Transforms/Scalar/LoopRerollPass.cpp @@ -1081,6 +1081,12 @@ bool LoopReroll::DAGRootTracker::collectUsedInstructions(SmallInstructionSet &Po DenseSet V; collectInLoopUserSet(LoopIncs, Exclude, PossibleRedSet, V); for (auto *I : V) { + if (I->mayHaveSideEffects()) { + LLVM_DEBUG(dbgs() << "LRR: Aborting - " + << "An instruction which does not belong to any root " + << "sets must not have side effects: " << *I); + return false; + } Uses[I].set(IL_All); } diff --git a/llvm/test/Transforms/LoopReroll/extra_instr.ll b/llvm/test/Transforms/LoopReroll/extra_instr.ll new file mode 100644 index 0000000000000..aae29079ade7f --- /dev/null +++ b/llvm/test/Transforms/LoopReroll/extra_instr.ll @@ -0,0 +1,268 @@ +; RUN: opt -S -loop-reroll %s | FileCheck %s +target triple = "aarch64--linux-gnu" + +define void @rerollable1([2 x i32]* nocapture %a) { +entry: + br label %loop + +loop: + +; CHECK-LABEL: loop: +; CHECK-NEXT: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] +; CHECK-NEXT: [[SCEVGEP1:%.*]] = getelementptr [2 x i32], [2 x i32]* %a, i64 20, i64 %iv +; CHECK-NEXT: [[SCEVGEP2:%.*]] = getelementptr [2 x i32], [2 x i32]* %a, i64 10, i64 %iv +; CHECK-NEXT: [[VALUE:%.*]] = load i32, i32* [[SCEVGEP1]], align 4 +; CHECK-NEXT: store i32 [[VALUE]], i32* [[SCEVGEP2]], align 4 + + ; base instruction + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + + ; NO unrerollable instructions + + ; extra simple arithmetic operations, used by root instructions + %plus20 = add nuw nsw i64 %iv, 20 + %plus10 = add nuw nsw i64 %iv, 10 + + ; root instruction 0 + %ldptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 0 + %value0 = load i32, i32* %ldptr0, align 4 + %stptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 0 + store i32 %value0, i32* %stptr0, align 4 + + ; root instruction 1 + %ldptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 1 + %value1 = load i32, i32* %ldptr1, align 4 + %stptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 1 + store i32 %value1, i32* %stptr1, align 4 + + ; loop-increment + %iv.next = add nuw nsw i64 %iv, 1 + + ; latch + %exitcond = icmp eq i64 %iv.next, 5 + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +define void @unrerollable1([2 x i32]* nocapture %a) { +entry: + br label %loop + +loop: + +; CHECK-LABEL: loop: +; CHECK-NEXT: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] +; CHECK-NEXT: %stptrx = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %iv, i64 0 +; CHECK-NEXT: store i32 999, i32* %stptrx, align 4 + + ; base instruction + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + + ; unrerollable instructions using %iv + %stptrx = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %iv, i64 0 + store i32 999, i32* %stptrx, align 4 + + ; extra simple arithmetic operations, used by root instructions + %plus20 = add nuw nsw i64 %iv, 20 + %plus10 = add nuw nsw i64 %iv, 10 + + ; root instruction 0 + %ldptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 0 + %value0 = load i32, i32* %ldptr0, align 4 + %stptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 0 + store i32 %value0, i32* %stptr0, align 4 + + ; root instruction 1 + %ldptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 1 + %value1 = load i32, i32* %ldptr1, align 4 + %stptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 1 + store i32 %value1, i32* %stptr1, align 4 + + ; loop-increment + %iv.next = add nuw nsw i64 %iv, 1 + + ; latch + %exitcond = icmp eq i64 %iv.next, 5 + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +define void @unrerollable2([2 x i32]* nocapture %a) { +entry: + br label %loop + +loop: + +; CHECK-LABEL: loop: +; CHECK-NEXT: %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] +; CHECK-NEXT: %iv.next = add nuw nsw i64 %iv, 1 +; CHECK-NEXT: %stptrx = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %iv.next, i64 0 +; CHECK-NEXT: store i32 999, i32* %stptrx, align 4 + + ; base instruction + %iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] + + ; loop-increment + %iv.next = add nuw nsw i64 %iv, 1 + + ; unrerollable instructions using %iv.next + %stptrx = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %iv.next, i64 0 + store i32 999, i32* %stptrx, align 4 + + ; extra simple arithmetic operations, used by root instructions + %plus20 = add nuw nsw i64 %iv, 20 + %plus10 = add nuw nsw i64 %iv, 10 + + ; root instruction 0 + %ldptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 0 + %value0 = load i32, i32* %ldptr0, align 4 + %stptr0 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 0 + store i32 %value0, i32* %stptr0, align 4 + + ; root instruction 1 + %ldptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus20, i64 1 + %value1 = load i32, i32* %ldptr1, align 4 + %stptr1 = getelementptr inbounds [2 x i32], [2 x i32]* %a, i64 %plus10, i64 1 + store i32 %value1, i32* %stptr1, align 4 + + ; latch + %exitcond = icmp eq i64 %iv.next, 5 + br i1 %exitcond, label %exit, label %loop + +exit: + ret void +} + +define dso_local void @rerollable2() { +entry: + br label %loop + +loop: + +; CHECK-LABEL: loop: +; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] +; CHECK-NEXT: {{%.*}} = add i32 %iv, {{20|24}} +; CHECK-NEXT: {{%.*}} = add i32 %iv, {{20|24}} + + ; induction variable + %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] + + ; scale instruction + %iv.mul3 = mul nuw nsw i32 %iv, 3 + + ; extra simple arithmetic operations, used by root instructions + %iv.scaled = add nuw nsw i32 %iv.mul3, 20 + + ; NO unrerollable instructions + + ; root set 1 + + ; base instruction + %iv.scaled.div5 = udiv i32 %iv.scaled, 5 + tail call void @bar(i32 %iv.scaled.div5) + ; root instruction 0 + %iv.scaled.add1 = add nuw nsw i32 %iv.scaled, 1 + %iv.scaled.add1.div5 = udiv i32 %iv.scaled.add1, 5 + tail call void @bar(i32 %iv.scaled.add1.div5) + ; root instruction 2 + %iv.scaled.add2 = add nuw nsw i32 %iv.scaled, 2 + %iv.scaled.add2.div5 = udiv i32 %iv.scaled.add2, 5 + tail call void @bar(i32 %iv.scaled.add2.div5) + + ; root set 2 + + ; base instruction + %iv.scaled.add4 = add nuw nsw i32 %iv.scaled, 4 + %iv.scaled.add4.div5 = udiv i32 %iv.scaled.add4, 5 + tail call void @bar(i32 %iv.scaled.add4.div5) + ; root instruction 0 + %iv.scaled.add5 = add nuw nsw i32 %iv.scaled, 5 + %iv.scaled.add5.div5 = udiv i32 %iv.scaled.add5, 5 + tail call void @bar(i32 %iv.scaled.add5.div5) + ; root instruction 2 + %iv.scaled.add6 = add nuw nsw i32 %iv.scaled, 6 + %iv.scaled.add6.div5 = udiv i32 %iv.scaled.add6, 5 + tail call void @bar(i32 %iv.scaled.add6.div5) + + ; loop-increment + %iv.next = add nuw nsw i32 %iv, 1 + + ; latch + %cmp = icmp ult i32 %iv.next, 3 + br i1 %cmp, label %loop, label %exit + +exit: + ret void +} + +define dso_local void @unrerollable3() { +entry: + br label %loop + +loop: + +; CHECK-LABEL: loop: +; CHECK-NEXT: %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] +; CHECK-NEXT: %iv.mul3 = mul nuw nsw i32 %iv, 3 +; CHECK-NEXT: %iv.scaled = add nuw nsw i32 %iv.mul3, 20 +; CHECK-NEXT: %iv.mul7 = mul nuw nsw i32 %iv, 7 +; CHECK-NEXT: tail call void @bar(i32 %iv.mul7) + + ; induction variable + %iv = phi i32 [ 0, %entry ], [ %iv.next, %loop ] + + ; scale instruction + %iv.mul3 = mul nuw nsw i32 %iv, 3 + + ; extra simple arithmetic operations, used by root instructions + %iv.scaled = add nuw nsw i32 %iv.mul3, 20 + + ; unrerollable instructions using %iv + %iv.mul7 = mul nuw nsw i32 %iv, 7 + tail call void @bar(i32 %iv.mul7) + + ; root set 1 + + ; base instruction + %iv.scaled.div5 = udiv i32 %iv.scaled, 5 + tail call void @bar(i32 %iv.scaled.div5) + ; root instruction 0 + %iv.scaled.add1 = add nuw nsw i32 %iv.scaled, 1 + %iv.scaled.add1.div5 = udiv i32 %iv.scaled.add1, 5 + tail call void @bar(i32 %iv.scaled.add1.div5) + ; root instruction 2 + %iv.scaled.add2 = add nuw nsw i32 %iv.scaled, 2 + %iv.scaled.add2.div5 = udiv i32 %iv.scaled.add2, 5 + tail call void @bar(i32 %iv.scaled.add2.div5) + + ; root set 2 + + ; base instruction + %iv.scaled.add4 = add nuw nsw i32 %iv.scaled, 4 + %iv.scaled.add4.div5 = udiv i32 %iv.scaled.add4, 5 + tail call void @bar(i32 %iv.scaled.add4.div5) + ; root instruction 0 + %iv.scaled.add5 = add nuw nsw i32 %iv.scaled, 5 + %iv.scaled.add5.div5 = udiv i32 %iv.scaled.add5, 5 + tail call void @bar(i32 %iv.scaled.add5.div5) + ; root instruction 2 + %iv.scaled.add6 = add nuw nsw i32 %iv.scaled, 6 + %iv.scaled.add6.div5 = udiv i32 %iv.scaled.add6, 5 + tail call void @bar(i32 %iv.scaled.add6.div5) + + ; loop-increment + %iv.next = add nuw nsw i32 %iv, 1 + + ; latch + %cmp = icmp ult i32 %iv.next, 3 + br i1 %cmp, label %loop, label %exit + +exit: + ret void +} + +declare dso_local void @bar(i32) From llvm-branch-commits at lists.llvm.org Thu May 6 17:15:35 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:15:35 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 225b775 - [PowerPC] Prevent argument promotion of types with size greater than 128 bits Message-ID: <609486a7.1c69fb81.171ea.9d6e@mx.google.com> Author: Ahsan Saghir Date: 2021-05-06T17:15:09-07:00 New Revision: 225b775620c69fa87c5fd63b29ef8f08c9922fb4 URL: https://github.com/llvm/llvm-project/commit/225b775620c69fa87c5fd63b29ef8f08c9922fb4 DIFF: https://github.com/llvm/llvm-project/commit/225b775620c69fa87c5fd63b29ef8f08c9922fb4.diff LOG: [PowerPC] Prevent argument promotion of types with size greater than 128 bits This patch prevents argument promotion of types having type size greater than 128 bits. Fixes Bugzilla: https://bugs.llvm.org/show_bug.cgi?id=49952 Reviewed By: #powerpc, nemanjai Differential Revision: https://reviews.llvm.org/D101188 (cherry picked from commit 670736a904746e92dde141266b6d4881b56d51a2) Added: llvm/test/CodeGen/PowerPC/arg_promotion.ll Modified: llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h Removed: ################################################################################ diff --git a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp index b3d8100fe016c..c90ff8b7d59d2 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp +++ b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.cpp @@ -1212,6 +1212,27 @@ unsigned PPCTTIImpl::getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, return BaseT::getIntrinsicInstrCost(ICA, CostKind); } +bool PPCTTIImpl::areFunctionArgsABICompatible( + const Function *Caller, const Function *Callee, + SmallPtrSetImpl &Args) const { + + // We need to ensure that argument promotion does not + // attempt to promote pointers to MMA types (__vector_pair + // and __vector_quad) since these types explicitly cannot be + // passed as arguments. Both of these types are larger than + // the 128-bit Altivec vectors and have a scalar size of 1 bit. + if (!BaseT::areFunctionArgsABICompatible(Caller, Callee, Args)) + return false; + + return llvm::none_of(Args, [](Argument *A) { + auto *EltTy = cast(A->getType())->getElementType(); + if (EltTy->isSized()) + return (EltTy->isIntOrIntVectorTy(1) && + EltTy->getPrimitiveSizeInBits() > 128); + return false; + }); +} + bool PPCTTIImpl::canSaveCmp(Loop *L, BranchInst **BI, ScalarEvolution *SE, LoopInfo *LI, DominatorTree *DT, AssumptionCache *AC, TargetLibraryInfo *LibInfo) { diff --git a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h index bc946715156fe..c38ae90bc7dc8 100644 --- a/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h +++ b/llvm/lib/Target/PowerPC/PPCTargetTransformInfo.h @@ -129,6 +129,9 @@ class PPCTTIImpl : public BasicTTIImplBase { unsigned getIntrinsicInstrCost(const IntrinsicCostAttributes &ICA, TTI::TargetCostKind CostKind); + bool areFunctionArgsABICompatible(const Function *Caller, + const Function *Callee, + SmallPtrSetImpl &Args) const; /// @} }; diff --git a/llvm/test/CodeGen/PowerPC/arg_promotion.ll b/llvm/test/CodeGen/PowerPC/arg_promotion.ll new file mode 100644 index 0000000000000..e52d2e47201fd --- /dev/null +++ b/llvm/test/CodeGen/PowerPC/arg_promotion.ll @@ -0,0 +1,108 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -argpromotion -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s +; RUN: opt -S -passes=argpromotion -mtriple=powerpc64le-unknown-linux-gnu < %s | FileCheck %s + +; Test to check that we do not promote arguments when the +; type size is greater than 128 bits. + +define internal fastcc void @print_acc(<512 x i1>* nocapture readonly %a) nounwind { +; CHECK-LABEL: @print_acc( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = load <512 x i1>, <512 x i1>* [[A:%.*]], align 64 +; CHECK-NEXT: [[TMP1:%.*]] = tail call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.ppc.mma.disassemble.acc(<512 x i1> [[TMP0]]) +; CHECK-NEXT: [[TMP2:%.*]] = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } [[TMP1]], 0 +; CHECK-NEXT: ret void +; +entry: + %0 = load <512 x i1>, <512 x i1>* %a, align 64 + %1 = tail call { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.ppc.mma.disassemble.acc(<512 x i1> %0) + %2 = extractvalue { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } %1, 0 + ret void +} + +declare { <16 x i8>, <16 x i8>, <16 x i8>, <16 x i8> } @llvm.ppc.mma.disassemble.acc(<512 x i1>) nounwind + +define dso_local void @test(<512 x i1>* nocapture %a, <16 x i8> %ac) { +; CHECK-LABEL: @test( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = tail call <512 x i1> @llvm.ppc.mma.xvf32ger(<16 x i8> [[AC:%.*]], <16 x i8> [[AC]]) +; CHECK-NEXT: store <512 x i1> [[TMP0]], <512 x i1>* [[A:%.*]], align 64 +; CHECK-NEXT: tail call fastcc void @print_acc(<512 x i1>* nonnull [[A]]) +; CHECK-NEXT: ret void +; +entry: + %0 = tail call <512 x i1> @llvm.ppc.mma.xvf32ger(<16 x i8> %ac, <16 x i8> %ac) + store <512 x i1> %0, <512 x i1>* %a, align 64 + tail call fastcc void @print_acc(<512 x i1>* nonnull %a) + ret void +} + +declare <512 x i1> @llvm.ppc.mma.xvf32ger(<16 x i8>, <16 x i8>) nounwind + + at .str = private unnamed_addr constant [11 x i8] c"Vector: { \00", align 1 + at .str.1 = private unnamed_addr constant [5 x i8] c"%d, \00", align 1 + at .str.2 = private unnamed_addr constant [6 x i8] c"%d }\0A\00", align 1 + +define internal fastcc void @printWideVec(<16 x i32> %ptr.val) nounwind { +; CHECK-LABEL: @printWideVec( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[CALL:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i64 0, i64 0)) +; CHECK-NEXT: [[VECEXT:%.*]] = extractelement <16 x i32> [[PTR_VAL:%.*]], i32 0 +; CHECK-NEXT: [[CALL1:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT]]) +; CHECK-NEXT: [[VECEXT_1:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 1 +; CHECK-NEXT: [[CALL1_1:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_1]]) +; CHECK-NEXT: [[VECEXT_2:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 2 +; CHECK-NEXT: [[CALL1_2:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_2]]) +; CHECK-NEXT: [[VECEXT_3:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 3 +; CHECK-NEXT: [[CALL1_3:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_3]]) +; CHECK-NEXT: [[VECEXT_4:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 4 +; CHECK-NEXT: [[CALL1_4:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_4]]) +; CHECK-NEXT: [[VECEXT_5:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 5 +; CHECK-NEXT: [[CALL1_5:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_5]]) +; CHECK-NEXT: [[VECEXT_6:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 6 +; CHECK-NEXT: [[CALL1_6:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext [[VECEXT_6]]) +; CHECK-NEXT: [[VECEXT2:%.*]] = extractelement <16 x i32> [[PTR_VAL]], i32 7 +; CHECK-NEXT: [[CALL3:%.*]] = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i64 0, i64 0), i32 signext [[VECEXT2]]) +; CHECK-NEXT: ret void +; +entry: + %call = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([11 x i8], [11 x i8]* @.str, i64 0, i64 0)) + %vecext = extractelement <16 x i32> %ptr.val, i32 0 + %call1 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext) + %vecext.1 = extractelement <16 x i32> %ptr.val, i32 1 + %call1.1 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.1) + %vecext.2 = extractelement <16 x i32> %ptr.val, i32 2 + %call1.2 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.2) + %vecext.3 = extractelement <16 x i32> %ptr.val, i32 3 + %call1.3 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.3) + %vecext.4 = extractelement <16 x i32> %ptr.val, i32 4 + %call1.4 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.4) + %vecext.5 = extractelement <16 x i32> %ptr.val, i32 5 + %call1.5 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.5) + %vecext.6 = extractelement <16 x i32> %ptr.val, i32 6 + %call1.6 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([5 x i8], [5 x i8]* @.str.1, i64 0, i64 0), i32 signext %vecext.6) + %vecext2 = extractelement <16 x i32> %ptr.val, i32 7 + %call3 = tail call signext i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @.str.2, i64 0, i64 0), i32 signext %vecext2) + ret void +} + +declare noundef signext i32 @printf(i8* nocapture noundef readonly, ...) nounwind + +define dso_local void @test1(<4 x i32> %a, <4 x i32> %b) nounwind { +; CHECK-LABEL: @test1( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[TMP0:%.*]] = shufflevector <4 x i32> [[A:%.*]], <4 x i32> undef, <16 x i32> +; CHECK-NEXT: [[TMP1:%.*]] = shufflevector <4 x i32> [[B:%.*]], <4 x i32> undef, <16 x i32> +; CHECK-NEXT: [[TMP2:%.*]] = shufflevector <16 x i32> [[TMP0]], <16 x i32> , <16 x i32> +; CHECK-NEXT: [[VECINIT22:%.*]] = shufflevector <16 x i32> [[TMP2]], <16 x i32> [[TMP1]], <16 x i32> +; CHECK-NEXT: tail call fastcc void @printWideVec(<16 x i32> [[VECINIT22]]) +; CHECK-NEXT: ret void +; +entry: + %0 = shufflevector <4 x i32> %a, <4 x i32> undef, <16 x i32> + %1 = shufflevector <4 x i32> %b, <4 x i32> undef, <16 x i32> + %2 = shufflevector <16 x i32> %0, <16 x i32> , <16 x i32> + %vecinit22 = shufflevector <16 x i32> %2, <16 x i32> %1, <16 x i32> + tail call fastcc void @printWideVec(<16 x i32> %vecinit22) + ret void +} From llvm-branch-commits at lists.llvm.org Thu May 6 17:24:23 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:24:23 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] c89d500 - [InstCombine] add test for miscompile from select value equivalence; NFC Message-ID: <609488b7.1c69fb81.c69b4.9b77@mx.google.com> Author: Sanjay Patel Date: 2021-05-06T17:19:54-07:00 New Revision: c89d50033228953d29e835ea5cb8e7066c0d8583 URL: https://github.com/llvm/llvm-project/commit/c89d50033228953d29e835ea5cb8e7066c0d8583 DIFF: https://github.com/llvm/llvm-project/commit/c89d50033228953d29e835ea5cb8e7066c0d8583.diff LOG: [InstCombine] add test for miscompile from select value equivalence; NFC The new test is reduced from: https://llvm.org/PR49832 ...but we already show a potential miscompile in the existing test too. (cherry picked from commit c0b0da4684908b8e8143c0762fc766c1a2a5849f) Added: Modified: llvm/test/Transforms/InstCombine/select-binop-cmp.ll Removed: ################################################################################ diff --git a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll index bbf7456ae811..beea2862a8ef 100644 --- a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll +++ b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll @@ -551,6 +551,8 @@ define i32 @select_xor_icmp_bad_6(i32 %x, i32 %y, i32 %z) { ret i32 %C } +; FIXME: Value equivalence substitution is all-or-nothing, so needs a scalar compare. + define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_xor_icmp_vec_bad( ; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], @@ -564,6 +566,18 @@ define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) ret <2 x i8> %C } +; FIXME: Value equivalence substitution is all-or-nothing, so needs a scalar compare. + +define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x) { +; CHECK-LABEL: @vec_select_no_equivalence( +; CHECK-NEXT: ret <2 x i32> [[X:%.*]] +; + %x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> + %cond = icmp eq <2 x i32> %x, zeroinitializer + %s = select <2 x i1> %cond, <2 x i32> %x10, <2 x i32> %x + ret <2 x i32> %s +} + ; Folding this would only be legal if we sanitized undef to 0. define <2 x i8> @select_xor_icmp_vec_undef(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_xor_icmp_vec_undef( From llvm-branch-commits at lists.llvm.org Thu May 6 17:24:25 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:24:25 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 4a12f51 - [InstCombine] fix potential miscompile in select value equivalence Message-ID: <609488b9.1c69fb81.13216.9d56@mx.google.com> Author: Sanjay Patel Date: 2021-05-06T17:19:54-07:00 New Revision: 4a12f51ad0090c3bcfea29c8dd021486ac3aa329 URL: https://github.com/llvm/llvm-project/commit/4a12f51ad0090c3bcfea29c8dd021486ac3aa329 DIFF: https://github.com/llvm/llvm-project/commit/4a12f51ad0090c3bcfea29c8dd021486ac3aa329.diff LOG: [InstCombine] fix potential miscompile in select value equivalence As shown in the example based on: https://llvm.org/PR49832 ...and the existing test, we can't substitute a vector value because the equality compare replacement that we are attempting requires that the comparison is true for the entire value. Vector select can be partly true/false. (cherry picked from commit c590a9880d7a660a1c911fce07f3d01ea18be2df) Added: Modified: llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp llvm/test/Transforms/InstCombine/select-binop-cmp.ll Removed: ################################################################################ diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp index f26c194d31b9..5f174aae09ec 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineSelect.cpp @@ -1095,7 +1095,10 @@ static Instruction *canonicalizeAbsNabs(SelectInst &Sel, ICmpInst &Cmp, /// TODO: Wrapping flags could be preserved in some cases with better analysis. Instruction *InstCombinerImpl::foldSelectValueEquivalence(SelectInst &Sel, ICmpInst &Cmp) { - if (!Cmp.isEquality()) + // Value equivalence substitution requires an all-or-nothing replacement. + // It does not make sense for a vector compare where each lane is chosen + // independently. + if (!Cmp.isEquality() || Cmp.getType()->isVectorTy()) return nullptr; // Canonicalize the pattern to ICMP_EQ by swapping the select operands. diff --git a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll index beea2862a8ef..7c1cc21b4280 100644 --- a/llvm/test/Transforms/InstCombine/select-binop-cmp.ll +++ b/llvm/test/Transforms/InstCombine/select-binop-cmp.ll @@ -551,12 +551,12 @@ define i32 @select_xor_icmp_bad_6(i32 %x, i32 %y, i32 %z) { ret i32 %C } -; FIXME: Value equivalence substitution is all-or-nothing, so needs a scalar compare. +; Value equivalence substitution is all-or-nothing, so needs a scalar compare. define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) { ; CHECK-LABEL: @select_xor_icmp_vec_bad( ; CHECK-NEXT: [[A:%.*]] = icmp eq <2 x i8> [[X:%.*]], -; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[Z:%.*]], +; CHECK-NEXT: [[B:%.*]] = xor <2 x i8> [[X]], [[Z:%.*]] ; CHECK-NEXT: [[C:%.*]] = select <2 x i1> [[A]], <2 x i8> [[B]], <2 x i8> [[Y:%.*]] ; CHECK-NEXT: ret <2 x i8> [[C]] ; @@ -566,11 +566,14 @@ define <2 x i8> @select_xor_icmp_vec_bad(<2 x i8> %x, <2 x i8> %y, <2 x i8> %z) ret <2 x i8> %C } -; FIXME: Value equivalence substitution is all-or-nothing, so needs a scalar compare. +; Value equivalence substitution is all-or-nothing, so needs a scalar compare. define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x) { ; CHECK-LABEL: @vec_select_no_equivalence( -; CHECK-NEXT: ret <2 x i32> [[X:%.*]] +; CHECK-NEXT: [[X10:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> +; CHECK-NEXT: [[COND:%.*]] = icmp eq <2 x i32> [[X]], zeroinitializer +; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[X10]], <2 x i32> [[X]] +; CHECK-NEXT: ret <2 x i32> [[S]] ; %x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> %cond = icmp eq <2 x i32> %x, zeroinitializer From llvm-branch-commits at lists.llvm.org Thu May 6 17:24:27 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:24:27 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 266c82f - [InstSimplify] add test for vector select with operand replacement; NFC Message-ID: <609488bb.1c69fb81.95f0e.96cd@mx.google.com> Author: Sanjay Patel Date: 2021-05-06T17:21:49-07:00 New Revision: 266c82f94da232d736f413c8d9e08d066c2d7202 URL: https://github.com/llvm/llvm-project/commit/266c82f94da232d736f413c8d9e08d066c2d7202 DIFF: https://github.com/llvm/llvm-project/commit/266c82f94da232d736f413c8d9e08d066c2d7202.diff LOG: [InstSimplify] add test for vector select with operand replacement; NFC We need a sibling fix to c590a9880d7a ( https://llvm.org/PR49832 ) to avoid miscompiling. (cherry picked from commit 78e5cf66fec52c8e6e665c3c9e64d38498d94a5d) Added: Modified: llvm/test/Transforms/InstSimplify/select.ll Removed: ################################################################################ diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll index 6460b42d63c1e..68e7411c8310f 100644 --- a/llvm/test/Transforms/InstSimplify/select.ll +++ b/llvm/test/Transforms/InstSimplify/select.ll @@ -969,6 +969,28 @@ define @ignore_scalable_undef( %cond) { ret %s } +define i32 @select_ctpop_zero(i32 %x) { +; CHECK-LABEL: @select_ctpop_zero( +; CHECK-NEXT: [[T1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]) +; CHECK-NEXT: ret i32 [[T1]] +; + %t0 = icmp eq i32 %x, 0 + %t1 = call i32 @llvm.ctpop.i32(i32 %x) + %sel = select i1 %t0, i32 0, i32 %t1 + ret i32 %sel +} +declare i32 @llvm.ctpop.i32(i32) + +define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x, <2 x i32> %y) { +; CHECK-LABEL: @vec_select_no_equivalence( +; CHECK-NEXT: ret <2 x i32> zeroinitializer +; + %x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> + %cond = icmp eq <2 x i32> %x, zeroinitializer + %s = select <2 x i1> %cond, <2 x i32> %x10, <2 x i32> zeroinitializer + ret <2 x i32> %s +} + ; TODO: these can be optimized more define i32 @poison(i32 %x, i32 %y) { From llvm-branch-commits at lists.llvm.org Thu May 6 17:24:29 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Thu, 06 May 2021 17:24:29 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 8e2ff38 - [InstSimplify] fix potential miscompile in select value equivalence Message-ID: <609488bd.1c69fb81.af132.afc7@mx.google.com> Author: Sanjay Patel Date: 2021-05-06T17:21:53-07:00 New Revision: 8e2ff387d30d540195ffef299785d392b0ee17dd URL: https://github.com/llvm/llvm-project/commit/8e2ff387d30d540195ffef299785d392b0ee17dd DIFF: https://github.com/llvm/llvm-project/commit/8e2ff387d30d540195ffef299785d392b0ee17dd.diff LOG: [InstSimplify] fix potential miscompile in select value equivalence This is the sibling fix to c590a9880d7a - as there, we can't subsitute a vector value the equality compare replacement that we are trying requires that the comparison is true for the entire value. Vector select can be partly true/false. (cherry picked from commit e2a0f512eacad0699be9660f668726d7deb2cd75) Added: Modified: llvm/lib/Analysis/InstructionSimplify.cpp llvm/test/Transforms/InstSimplify/select.ll Removed: ################################################################################ diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp index c40e5c36cdc7c..a12816885c402 100644 --- a/llvm/lib/Analysis/InstructionSimplify.cpp +++ b/llvm/lib/Analysis/InstructionSimplify.cpp @@ -4127,10 +4127,12 @@ static Value *simplifySelectWithICmpCond(Value *CondVal, Value *TrueVal, TrueVal, FalseVal)) return V; - // If we have an equality comparison, then we know the value in one of the - // arms of the select. See if substituting this value into the arm and + // If we have a scalar equality comparison, then we know the value in one of + // the arms of the select. See if substituting this value into the arm and // simplifying the result yields the same value as the other arm. - if (Pred == ICmpInst::ICMP_EQ) { + // Note that the equivalence/replacement opportunity does not hold for vectors + // because each element of a vector select is chosen independently. + if (Pred == ICmpInst::ICMP_EQ && !CondVal->getType()->isVectorTy()) { if (SimplifyWithOpReplaced(FalseVal, CmpLHS, CmpRHS, Q, /* AllowRefinement */ false, MaxRecurse) == TrueVal || diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll index 68e7411c8310f..4291fc0a839e6 100644 --- a/llvm/test/Transforms/InstSimplify/select.ll +++ b/llvm/test/Transforms/InstSimplify/select.ll @@ -983,7 +983,10 @@ declare i32 @llvm.ctpop.i32(i32) define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @vec_select_no_equivalence( -; CHECK-NEXT: ret <2 x i32> zeroinitializer +; CHECK-NEXT: [[X10:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> +; CHECK-NEXT: [[COND:%.*]] = icmp eq <2 x i32> [[X]], zeroinitializer +; CHECK-NEXT: [[S:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[X10]], <2 x i32> zeroinitializer +; CHECK-NEXT: ret <2 x i32> [[S]] ; %x10 = shufflevector <2 x i32> %x, <2 x i32> undef, <2 x i32> %cond = icmp eq <2 x i32> %x, zeroinitializer From llvm-branch-commits at lists.llvm.org Mon May 10 13:57:06 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 10 May 2021 13:57:06 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 2db5d42 - Remove extra test case added in 266c82f94da232d736f413c8d9e08d066c2d7202 Message-ID: <60999e22.1c69fb81.95f0e.2d24@mx.google.com> Author: Tom Stellard Date: 2021-05-10T13:20:52-07:00 New Revision: 2db5d42193abefcb41b10bd70b7ab536cb03f1cc URL: https://github.com/llvm/llvm-project/commit/2db5d42193abefcb41b10bd70b7ab536cb03f1cc DIFF: https://github.com/llvm/llvm-project/commit/2db5d42193abefcb41b10bd70b7ab536cb03f1cc.diff LOG: Remove extra test case added in 266c82f94da232d736f413c8d9e08d066c2d7202 This test case was added by accident and is failing on the release/12.x branch. Added: Modified: llvm/test/Transforms/InstSimplify/select.ll Removed: ################################################################################ diff --git a/llvm/test/Transforms/InstSimplify/select.ll b/llvm/test/Transforms/InstSimplify/select.ll index 4291fc0a839e6..93f09d89bf40e 100644 --- a/llvm/test/Transforms/InstSimplify/select.ll +++ b/llvm/test/Transforms/InstSimplify/select.ll @@ -969,18 +969,6 @@ define @ignore_scalable_undef( %cond) { ret %s } -define i32 @select_ctpop_zero(i32 %x) { -; CHECK-LABEL: @select_ctpop_zero( -; CHECK-NEXT: [[T1:%.*]] = call i32 @llvm.ctpop.i32(i32 [[X:%.*]]) -; CHECK-NEXT: ret i32 [[T1]] -; - %t0 = icmp eq i32 %x, 0 - %t1 = call i32 @llvm.ctpop.i32(i32 %x) - %sel = select i1 %t0, i32 0, i32 %t1 - ret i32 %sel -} -declare i32 @llvm.ctpop.i32(i32) - define <2 x i32> @vec_select_no_equivalence(<2 x i32> %x, <2 x i32> %y) { ; CHECK-LABEL: @vec_select_no_equivalence( ; CHECK-NEXT: [[X10:%.*]] = shufflevector <2 x i32> [[X:%.*]], <2 x i32> undef, <2 x i32> From llvm-branch-commits at lists.llvm.org Mon May 10 14:24:35 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 10 May 2021 14:24:35 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] f3e07c8 - [NFC] Correctly assert the indents for printEnumValHelpStr. Message-ID: <6099a493.1c69fb81.e15ea.21d6@mx.google.com> Author: Joachim Meyer Date: 2021-05-10T14:24:18-07:00 New Revision: f3e07c841e2f96a73b253d3b1a95e2ac8df5a376 URL: https://github.com/llvm/llvm-project/commit/f3e07c841e2f96a73b253d3b1a95e2ac8df5a376 DIFF: https://github.com/llvm/llvm-project/commit/f3e07c841e2f96a73b253d3b1a95e2ac8df5a376.diff LOG: [NFC] Correctly assert the indents for printEnumValHelpStr. Only verify that there's no negative indent. Noted by @chapuni in https://reviews.llvm.org/D93494. Reviewed By: chapuni Differential Revision: https://reviews.llvm.org/D102021 (cherry picked from commit d9f2960c932c9803e662098e33d899efa3c67f44) Added: Modified: llvm/lib/Support/CommandLine.cpp Removed: ################################################################################ diff --git a/llvm/lib/Support/CommandLine.cpp b/llvm/lib/Support/CommandLine.cpp index e2f014d1815b7..123a23a5242c2 100644 --- a/llvm/lib/Support/CommandLine.cpp +++ b/llvm/lib/Support/CommandLine.cpp @@ -1729,7 +1729,7 @@ void Option::printHelpStr(StringRef HelpStr, size_t Indent, void Option::printEnumValHelpStr(StringRef HelpStr, size_t BaseIndent, size_t FirstLineIndentedBy) { const StringRef ValHelpPrefix = " "; - assert(BaseIndent >= FirstLineIndentedBy + ValHelpPrefix.size()); + assert(BaseIndent >= FirstLineIndentedBy); std::pair Split = HelpStr.split('\n'); outs().indent(BaseIndent - FirstLineIndentedBy) << ArgHelpPrefix << ValHelpPrefix << Split.first << "\n"; From llvm-branch-commits at lists.llvm.org Mon May 10 15:41:27 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 10 May 2021 15:41:27 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 24535af - [AArch64][GlobalISel] Fix incorrect codegen for <16 x s8> G_ASHR. Message-ID: <6099b697.1c69fb81.c4b94.5340@mx.google.com> Author: Amara Emerson Date: 2021-05-10T15:41:06-07:00 New Revision: 24535af52ae139f2bb361855fbbaf47cc9e5d580 URL: https://github.com/llvm/llvm-project/commit/24535af52ae139f2bb361855fbbaf47cc9e5d580 DIFF: https://github.com/llvm/llvm-project/commit/24535af52ae139f2bb361855fbbaf47cc9e5d580.diff LOG: [AArch64][GlobalISel] Fix incorrect codegen for <16 x s8> G_ASHR. Fixes PR49904 (cherry picked from commit 40e75cafc0fef365b5580a9c09595ac475db0c19) Added: Modified: llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir Removed: ################################################################################ diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp index 5259f4f5a4d05..fc5ef02e84578 100644 --- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp +++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp @@ -1791,7 +1791,7 @@ bool AArch64InstructionSelector::selectVectorAshrLshr( NegOpc = AArch64::NEGv8i16; } else if (Ty == LLT::vector(16, 8)) { Opc = IsASHR ? AArch64::SSHLv16i8 : AArch64::USHLv16i8; - NegOpc = AArch64::NEGv8i16; + NegOpc = AArch64::NEGv16i8; } else if (Ty == LLT::vector(8, 8)) { Opc = IsASHR ? AArch64::SSHLv8i8 : AArch64::USHLv8i8; NegOpc = AArch64::NEGv8i8; diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir index 6a5c33ed9c140..1056a449ab21d 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-vector-shift.mir @@ -562,8 +562,8 @@ body: | ; CHECK: liveins: $q0, $q1 ; CHECK: [[COPY:%[0-9]+]]:fpr128 = COPY $q0 ; CHECK: [[COPY1:%[0-9]+]]:fpr128 = COPY $q1 - ; CHECK: [[NEGv8i16_:%[0-9]+]]:fpr128 = NEGv8i16 [[COPY1]] - ; CHECK: [[USHLv16i8_:%[0-9]+]]:fpr128 = USHLv16i8 [[COPY]], [[NEGv8i16_]] + ; CHECK: [[NEGv16i8_:%[0-9]+]]:fpr128 = NEGv16i8 [[COPY1]] + ; CHECK: [[USHLv16i8_:%[0-9]+]]:fpr128 = USHLv16i8 [[COPY]], [[NEGv16i8_]] ; CHECK: $q0 = COPY [[USHLv16i8_]] ; CHECK: RET_ReallyLR implicit $q0 %0:fpr(<16 x s8>) = COPY $q0 From llvm-branch-commits at lists.llvm.org Mon May 10 17:37:41 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 10 May 2021 17:37:41 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 067c06d - [SystemZ] Don't use libcall for 128 bit shifts. Message-ID: <6099d1d5.1c69fb81.6e6d4.2666@mx.google.com> Author: Jonas Paulsson Date: 2021-05-10T17:37:13-07:00 New Revision: 067c06dc8395a2d79792c0ac4e48c2a79836b46f URL: https://github.com/llvm/llvm-project/commit/067c06dc8395a2d79792c0ac4e48c2a79836b46f DIFF: https://github.com/llvm/llvm-project/commit/067c06dc8395a2d79792c0ac4e48c2a79836b46f.diff LOG: [SystemZ] Don't use libcall for 128 bit shifts. Expand 128 bit shifts instead of using a libcall. This patch removes the 128 bit shift libcalls and thereby causes ExpandShiftWithUnknownAmountBit() to be called. Review: Ulrich Weigand Differential Revision: https://reviews.llvm.org/D101993 (cherry picked from commit 1c4cb510b4daccc0f4763958567affc2b442f317) Added: Modified: llvm/lib/Target/SystemZ/SystemZISelLowering.cpp llvm/test/CodeGen/SystemZ/shift-12.ll Removed: ################################################################################ diff --git a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp index 603446755aaff..9ace36f344a51 100644 --- a/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp +++ b/llvm/lib/Target/SystemZ/SystemZISelLowering.cpp @@ -285,10 +285,13 @@ SystemZTargetLowering::SystemZTargetLowering(const TargetMachine &TM, // Give LowerOperation the chance to replace 64-bit ORs with subregs. setOperationAction(ISD::OR, MVT::i64, Custom); - // FIXME: Can we support these natively? + // Expand 128 bit shifts without using a libcall. setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand); setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand); setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand); + setLibcallName(RTLIB::SRL_I128, nullptr); + setLibcallName(RTLIB::SHL_I128, nullptr); + setLibcallName(RTLIB::SRA_I128, nullptr); // We have native instructions for i8, i16 and i32 extensions, but not i1. setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1, Expand); diff --git a/llvm/test/CodeGen/SystemZ/shift-12.ll b/llvm/test/CodeGen/SystemZ/shift-12.ll index 7559602aa2565..421928f286985 100644 --- a/llvm/test/CodeGen/SystemZ/shift-12.ll +++ b/llvm/test/CodeGen/SystemZ/shift-12.ll @@ -2,7 +2,7 @@ ; Test removal of AND operations that don't affect last 6 bits of shift amount ; operand. ; -; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s +; RUN: llc < %s -mtriple=s390x-linux-gnu -mcpu=z14 | FileCheck %s ; Test that AND is not removed when some lower 6 bits are not set. define i32 @f1(i32 %a, i32 %sh) { @@ -119,31 +119,28 @@ define i32 @f10(i32 %a, i32 %sh) { ret i32 %reuse } -; Test that AND is not removed for i128 (which calls __ashlti3) define i128 @f11(i128 %a, i32 %sh) { ; CHECK-LABEL: f11: ; CHECK: # %bb.0: -; CHECK-NEXT: stmg %r13, %r15, 104(%r15) -; CHECK-NEXT: .cfi_offset %r13, -56 +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) ; CHECK-NEXT: .cfi_offset %r14, -48 ; CHECK-NEXT: .cfi_offset %r15, -40 -; CHECK-NEXT: aghi %r15, -192 -; CHECK-NEXT: .cfi_def_cfa_offset 352 ; CHECK-NEXT: lg %r0, 8(%r3) -; CHECK-NEXT: # kill: def $r4l killed $r4l def $r4d -; CHECK-NEXT: lgr %r13, %r2 ; CHECK-NEXT: lg %r1, 0(%r3) -; CHECK-NEXT: stg %r0, 168(%r15) -; CHECK-NEXT: risbg %r4, %r4, 57, 191, 0 -; CHECK-NEXT: la %r2, 176(%r15) -; CHECK-NEXT: la %r3, 160(%r15) -; CHECK-NEXT: stg %r1, 160(%r15) -; CHECK-NEXT: brasl %r14, __ashlti3 at PLT -; CHECK-NEXT: lg %r0, 184(%r15) -; CHECK-NEXT: lg %r1, 176(%r15) -; CHECK-NEXT: stg %r0, 8(%r13) -; CHECK-NEXT: stg %r1, 0(%r13) -; CHECK-NEXT: lmg %r13, %r15, 296(%r15) +; CHECK-NEXT: risblg %r3, %r4, 25, 159, 0 +; CHECK-NEXT: lcr %r14, %r3 +; CHECK-NEXT: sllg %r5, %r1, 0(%r4) +; CHECK-NEXT: srlg %r14, %r0, 0(%r14) +; CHECK-NEXT: ogr %r5, %r14 +; CHECK-NEXT: sllg %r3, %r0, -64(%r3) +; CHECK-NEXT: tmll %r4, 127 +; CHECK-NEXT: locgrle %r3, %r5 +; CHECK-NEXT: sllg %r0, %r0, 0(%r4) +; CHECK-NEXT: locgre %r3, %r1 +; CHECK-NEXT: locghinle %r0, 0 +; CHECK-NEXT: stg %r0, 8(%r2) +; CHECK-NEXT: stg %r3, 0(%r2) +; CHECK-NEXT: lmg %r14, %r15, 112(%r15) ; CHECK-NEXT: br %r14 %and = and i32 %sh, 127 %ext = zext i32 %and to i128 @@ -151,3 +148,62 @@ define i128 @f11(i128 %a, i32 %sh) { ret i128 %shift } +define i128 @f12(i128 %a, i32 %sh) { +; CHECK-LABEL: f12: +; CHECK: # %bb.0: +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: lg %r0, 0(%r3) +; CHECK-NEXT: lg %r1, 8(%r3) +; CHECK-NEXT: risblg %r3, %r4, 25, 159, 0 +; CHECK-NEXT: lcr %r14, %r3 +; CHECK-NEXT: srlg %r5, %r1, 0(%r4) +; CHECK-NEXT: sllg %r14, %r0, 0(%r14) +; CHECK-NEXT: ogr %r5, %r14 +; CHECK-NEXT: srlg %r3, %r0, -64(%r3) +; CHECK-NEXT: tmll %r4, 127 +; CHECK-NEXT: locgrle %r3, %r5 +; CHECK-NEXT: srlg %r0, %r0, 0(%r4) +; CHECK-NEXT: locgre %r3, %r1 +; CHECK-NEXT: locghinle %r0, 0 +; CHECK-NEXT: stg %r0, 0(%r2) +; CHECK-NEXT: stg %r3, 8(%r2) +; CHECK-NEXT: lmg %r14, %r15, 112(%r15) +; CHECK-NEXT: br %r14 + %and = and i32 %sh, 127 + %ext = zext i32 %and to i128 + %shift = lshr i128 %a, %ext + ret i128 %shift +} + +define i128 @f13(i128 %a, i32 %sh) { +; CHECK-LABEL: f13: +; CHECK: # %bb.0: +; CHECK-NEXT: stmg %r14, %r15, 112(%r15) +; CHECK-NEXT: .cfi_offset %r14, -48 +; CHECK-NEXT: .cfi_offset %r15, -40 +; CHECK-NEXT: lg %r0, 0(%r3) +; CHECK-NEXT: lg %r1, 8(%r3) +; CHECK-NEXT: risblg %r3, %r4, 25, 159, 0 +; CHECK-NEXT: lcr %r14, %r3 +; CHECK-NEXT: srlg %r5, %r1, 0(%r4) +; CHECK-NEXT: sllg %r14, %r0, 0(%r14) +; CHECK-NEXT: ogr %r5, %r14 +; CHECK-NEXT: srag %r14, %r0, 0(%r4) +; CHECK-NEXT: srag %r3, %r0, -64(%r3) +; CHECK-NEXT: srag %r0, %r0, 63 +; CHECK-NEXT: tmll %r4, 127 +; CHECK-NEXT: locgrle %r3, %r5 +; CHECK-NEXT: locgre %r3, %r1 +; CHECK-NEXT: locgrle %r0, %r14 +; CHECK-NEXT: stg %r0, 0(%r2) +; CHECK-NEXT: stg %r3, 8(%r2) +; CHECK-NEXT: lmg %r14, %r15, 112(%r15) +; CHECK-NEXT: br %r14 + %and = and i32 %sh, 127 + %ext = zext i32 %and to i128 + %shift = ashr i128 %a, %ext + ret i128 %shift +} + From llvm-branch-commits at lists.llvm.org Tue May 11 11:07:23 2021 From: llvm-branch-commits at lists.llvm.org (Alan Phipps via llvm-branch-commits) Date: Tue, 11 May 2021 11:07:23 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] b89942c - [Coverage] Fix branch coverage merging in FunctionCoverageSummary::get() for instantiation Message-ID: <609ac7db.1c69fb81.79a9d.2895@mx.google.com> Author: Alan Phipps Date: 2021-05-11T13:04:59-05:00 New Revision: b89942c336a4506dabd5e1b2a6f1b5cbaddebe55 URL: https://github.com/llvm/llvm-project/commit/b89942c336a4506dabd5e1b2a6f1b5cbaddebe55 DIFF: https://github.com/llvm/llvm-project/commit/b89942c336a4506dabd5e1b2a6f1b5cbaddebe55.diff LOG: [Coverage] Fix branch coverage merging in FunctionCoverageSummary::get() for instantiation Fix branch coverage merging in FunctionCoverageSummary::get() for instantiation groups. This change corrects the implementation for the branch coverage summary to do the same thing for branches that is done for lines and regions. That is, across function instantiations in an instantiation group, the maximum branch coverage found in any of those instantiations is returned, with the total number of branches being the same across instantiations. Differential Revision: https://reviews.llvm.org/D102193 (cherry picked from commit eccb925147d5f262a3e74cc050d0665dd4e6d8db) Added: Modified: llvm/test/tools/llvm-cov/branch-templates.cpp llvm/tools/llvm-cov/CoverageSummaryInfo.cpp llvm/tools/llvm-cov/CoverageSummaryInfo.h Removed: ################################################################################ diff --git a/llvm/test/tools/llvm-cov/branch-templates.cpp b/llvm/test/tools/llvm-cov/branch-templates.cpp index 750dc7bd58f27..4797428f8835a 100644 --- a/llvm/test/tools/llvm-cov/branch-templates.cpp +++ b/llvm/test/tools/llvm-cov/branch-templates.cpp @@ -1,9 +1,9 @@ // RUN: llvm-profdata merge %S/Inputs/branch-templates.proftext -o %t.profdata // RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT +// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORTFILE #include - template void unused(T x) { return; @@ -45,3 +45,17 @@ int main() { // REPORT-NEXT: _Z4funcIfEiT_ 5 2 60.00% 7 3 57.14% 2 1 50.00% // REPORT-NEXT: --- // REPORT-NEXT: TOTAL 22 7 68.18% 31 11 64.52% 12 6 50.00% + +// Make sure the covered branch tally for the function instantiation group is +// merged to reflect maximum branch coverage of a single instantiation, just +// like what is done for lines and regions. Also, the total branch tally +// summary for an instantiation group should agree with the total number of +// branches in the definition (In this case, 2 and 6 for func<>() and main(), +// respectively). This is returned by: FunctionCoverageSummary::get(const +// InstantiationGroup &Group, ...) + +// REPORTFILE: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover +// REPORTFILE-NEXT: --- +// REPORTFILE-NEXT: branch-templates.cpp 12 3 75.00% 2 0 100.00% 17 4 76.47% 8 4 50.00% +// REPORTFILE-NEXT: --- +// REPORTFILE-NEXT: TOTAL 12 3 75.00% 2 0 100.00% 17 4 76.47% 8 4 50.00% diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp index 4a0a86168908f..10e059adeb7d8 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -100,11 +100,7 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group, for (const auto &FCS : Summaries.drop_front()) { Summary.RegionCoverage.merge(FCS.RegionCoverage); Summary.LineCoverage.merge(FCS.LineCoverage); - - // Sum branch coverage across instantiation groups for the summary rather - // than "merge" the maximum count. This is a clearer view into whether all - // created branches are covered. - Summary.BranchCoverage += FCS.BranchCoverage; + Summary.BranchCoverage.merge(FCS.BranchCoverage); } return Summary; } diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h index 4bc1c24a079f2..62e7cad1012b1 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h @@ -123,6 +123,11 @@ class BranchCoverageInfo { return *this; } + void merge(const BranchCoverageInfo &RHS) { + Covered = std::max(Covered, RHS.Covered); + NumBranches = std::max(NumBranches, RHS.NumBranches); + } + size_t getCovered() const { return Covered; } size_t getNumBranches() const { return NumBranches; } From llvm-branch-commits at lists.llvm.org Tue May 11 17:30:00 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 17:30:00 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] aa97726 - [SCCP] Avoid modifying AdditionalUsers while iterating over it Message-ID: <609b2188.1c69fb81.1431b.8668@mx.google.com> Author: Dimitry Andric Date: 2021-05-11T17:27:32-07:00 New Revision: aa97726f6040c68dfdd8076e8efe3ef119f6b037 URL: https://github.com/llvm/llvm-project/commit/aa97726f6040c68dfdd8076e8efe3ef119f6b037 DIFF: https://github.com/llvm/llvm-project/commit/aa97726f6040c68dfdd8076e8efe3ef119f6b037.diff LOG: [SCCP] Avoid modifying AdditionalUsers while iterating over it When run under valgrind, or with a malloc that poisons freed memory, this can lead to segfaults or other problems. To avoid modifying the AdditionalUsers DenseMap while still iterating, save the instructions to be notified in a separate SmallPtrSet, and use this to later call OperandChangedState on each instruction. Fixes PR49582. Reviewed By: fhahn Differential Revision: https://reviews.llvm.org/D98602 (cherry picked from commit 6abb92f2103a58d097620b4410054c5bb18c48ec) Added: llvm/test/Transforms/SCCP/pr49582-iterator-invalidation.ll Modified: llvm/lib/Transforms/Scalar/SCCP.cpp Removed: ################################################################################ diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp index de6be52adf21..8feed9e9ebfe 100644 --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -542,9 +542,14 @@ class SCCPSolver : public InstVisitor { auto Iter = AdditionalUsers.find(I); if (Iter != AdditionalUsers.end()) { + // Copy additional users before notifying them of changes, because new + // users may be added, potentially invalidating the iterator. + SmallVector ToNotify; for (User *U : Iter->second) if (auto *UI = dyn_cast(U)) - OperandChangedState(UI); + ToNotify.push_back(UI); + for (Instruction *UI : ToNotify) + OperandChangedState(UI); } } void handleCallOverdefined(CallBase &CB); diff --git a/llvm/test/Transforms/SCCP/pr49582-iterator-invalidation.ll b/llvm/test/Transforms/SCCP/pr49582-iterator-invalidation.ll new file mode 100644 index 000000000000..6d5b2e1841b4 --- /dev/null +++ b/llvm/test/Transforms/SCCP/pr49582-iterator-invalidation.ll @@ -0,0 +1,854 @@ +; RUN: opt < %s -ipsccp -disable-output +; PR49582: This test checks for an iterator invalidation issue, which only gets +; exposed on a large-enough test case. We intentionally do not check the output. + + at c = external dso_local global i32*, align 8 + at d = external dso_local global i32, align 4 + +define void @f(i32 %i) { +entry: + br label %for.cond + +for.cond: ; preds = %if.end628, %entry + %e.0 = phi i32 [ 1, %entry ], [ %e.15, %if.end628 ] + %cmp = icmp slt i32 %e.0, %i + call void @llvm.assume(i1 %cmp) + %0 = load i32*, i32** @c, align 8 + %tobool = icmp ne i32* %0, null + br i1 %tobool, label %if.then, label %if.end628 + +if.then: ; preds = %for.cond + %1 = load i32, i32* %0, align 4 + %tobool1 = icmp ne i32 %1, 0 + br i1 %tobool1, label %if.then2, label %if.else78 + +if.then2: ; preds = %if.then + %add = add nsw i32 %e.0, 1 + %cmp3 = icmp sge i32 %add, %i + br i1 %cmp3, label %if.then4, label %if.end + +if.then4: ; preds = %if.then2 + %idxprom = sext i32 %add to i64 + br label %if.end + +if.end: ; preds = %if.then4, %if.then2 + br i1 %cmp3, label %if.then9, label %if.end13 + +if.then9: ; preds = %if.end + %idxprom11 = sext i32 %add to i64 + br label %if.end13 + +if.end13: ; preds = %if.then9, %if.end + br i1 %cmp3, label %if.then16, label %if.end20 + +if.then16: ; preds = %if.end13 + %idxprom18 = sext i32 %add to i64 + br label %if.end20 + +if.end20: ; preds = %if.then16, %if.end13 + %add21 = add nsw i32 %e.0, 3 + %cmp22 = icmp sge i32 %add21, %i + br i1 %cmp22, label %if.then23, label %if.end25 + +if.then23: ; preds = %if.end20 + br label %if.end25 + +if.end25: ; preds = %if.then23, %if.end20 + %e.1 = phi i32 [ %add21, %if.then23 ], [ %e.0, %if.end20 ] + %cmp26 = icmp sge i32 %e.1, %i + br i1 %cmp26, label %if.then27, label %if.end28 + +if.then27: ; preds = %if.end25 + %inc = add nsw i32 %e.1, 1 + br label %if.end28 + +if.end28: ; preds = %if.then27, %if.end25 + %e.2 = phi i32 [ %inc, %if.then27 ], [ %e.1, %if.end25 ] + %add29 = add nsw i32 %e.2, 2 + %cmp30 = icmp sge i32 %add29, %i + br i1 %cmp30, label %if.then31, label %if.end33 + +if.then31: ; preds = %if.end28 + br label %if.end33 + +if.end33: ; preds = %if.then31, %if.end28 + %e.3 = phi i32 [ %add29, %if.then31 ], [ %e.2, %if.end28 ] + %cmp34 = icmp sge i32 %e.3, %i + br i1 %cmp34, label %if.then35, label %if.end38 + +if.then35: ; preds = %if.end33 + %idxprom36 = sext i32 %e.3 to i64 + br label %if.end38 + +if.end38: ; preds = %if.then35, %if.end33 + br i1 %cmp34, label %if.then40, label %if.end43 + +if.then40: ; preds = %if.end38 + %idxprom41 = sext i32 %e.3 to i64 + br label %if.end43 + +if.end43: ; preds = %if.then40, %if.end38 + br i1 %cmp34, label %if.then45, label %if.end47 + +if.then45: ; preds = %if.end43 + %inc46 = add nsw i32 %e.3, 1 + br label %if.end47 + +if.end47: ; preds = %if.then45, %if.end43 + %e.4 = phi i32 [ %inc46, %if.then45 ], [ %e.3, %if.end43 ] + %cmp48 = icmp sge i32 %e.4, %i + br i1 %cmp48, label %if.then49, label %if.end51 + +if.then49: ; preds = %if.end47 + %inc50 = add nsw i32 %e.4, 1 + br label %if.end51 + +if.end51: ; preds = %if.then49, %if.end47 + %e.5 = phi i32 [ %inc50, %if.then49 ], [ %e.4, %if.end47 ] + %2 = load i32*, i32** @c, align 8 + %tobool52 = icmp ne i32* %2, null + br i1 %tobool52, label %if.then53, label %if.else + +if.then53: ; preds = %if.end51 + %cmp54 = icmp sge i32 %e.5, %i + br i1 %cmp54, label %if.then55, label %if.end628 + +if.then55: ; preds = %if.then53 + unreachable + +if.else: ; preds = %if.end51 + %3 = load i32, i32* @d, align 4 + %tobool57 = icmp ne i32 %3, 0 + br i1 %tobool57, label %if.then58, label %if.else68 + +if.then58: ; preds = %if.else + %cmp59 = icmp sge i32 %e.5, %i + br i1 %cmp59, label %if.then60, label %if.end62 + +if.then60: ; preds = %if.then58 + %inc61 = add nsw i32 %e.5, 1 + br label %if.end62 + +if.end62: ; preds = %if.then60, %if.then58 + %e.6 = phi i32 [ %inc61, %if.then60 ], [ %e.5, %if.then58 ] + %add63 = add nsw i32 %e.6, 1 + %cmp64 = icmp sge i32 %add63, %i + br i1 %cmp64, label %if.then65, label %if.end628 + +if.then65: ; preds = %if.end62 + br label %if.end628 + +if.else68: ; preds = %if.else + %add69 = add nsw i32 %e.5, 2 + %cmp70 = icmp sge i32 %add69, %i + br i1 %cmp70, label %if.then71, label %if.end628 + +if.then71: ; preds = %if.else68 + %idxprom73 = sext i32 %add69 to i64 + br label %if.end628 + +if.else78: ; preds = %if.then + %call = call i32 @g() + %tobool79 = icmp ne i32 %call, 0 + br i1 %tobool79, label %if.then80, label %if.else123 + +if.then80: ; preds = %if.else78 + %add81 = add nsw i32 %e.0, 3 + %cmp82 = icmp sge i32 %add81, %i + br i1 %cmp82, label %if.then83, label %if.end87 + +if.then83: ; preds = %if.then80 + %idxprom85 = sext i32 %add81 to i64 + br label %if.end87 + +if.end87: ; preds = %if.then83, %if.then80 + br i1 %cmp82, label %if.then90, label %if.end94 + +if.then90: ; preds = %if.end87 + %idxprom92 = sext i32 %add81 to i64 + br label %if.end94 + +if.end94: ; preds = %if.then90, %if.end87 + br i1 %cmp82, label %if.then97, label %if.end99 + +if.then97: ; preds = %if.end94 + br label %if.end99 + +if.end99: ; preds = %if.then97, %if.end94 + %e.7 = phi i32 [ %add81, %if.then97 ], [ %e.0, %if.end94 ] + %cmp100 = icmp sge i32 %e.7, %i + br i1 %cmp100, label %if.then101, label %if.end103 + +if.then101: ; preds = %if.end99 + %inc102 = add nsw i32 %e.7, 1 + br label %if.end103 + +if.end103: ; preds = %if.then101, %if.end99 + %e.8 = phi i32 [ %inc102, %if.then101 ], [ %e.7, %if.end99 ] + %add104 = add nsw i32 %e.8, 1 + %cmp105 = icmp sge i32 %add104, %i + br i1 %cmp105, label %if.then106, label %if.end108 + +if.then106: ; preds = %if.end103 + br label %if.end108 + +if.end108: ; preds = %if.then106, %if.end103 + %e.9 = phi i32 [ %add104, %if.then106 ], [ %e.8, %if.end103 ] + %cmp109 = icmp sge i32 %e.9, %i + br i1 %cmp109, label %if.then110, label %if.end113 + +if.then110: ; preds = %if.end108 + %idxprom111 = sext i32 %e.9 to i64 + br label %if.end113 + +if.end113: ; preds = %if.then110, %if.end108 + br i1 %cmp109, label %if.then115, label %if.end118 + +if.then115: ; preds = %if.end113 + %idxprom116 = sext i32 %e.9 to i64 + unreachable + +if.end118: ; preds = %if.end113 + br i1 %cmp109, label %if.then120, label %if.end628 + +if.then120: ; preds = %if.end118 + br label %if.end628 + +if.else123: ; preds = %if.else78 + %call124 = call i32 @g() + %tobool125 = icmp ne i32 %call124, 0 + br i1 %tobool125, label %if.then126, label %if.end628 + +if.then126: ; preds = %if.else123 + %call127 = call i32 @g() + %tobool128 = icmp ne i32 %call127, 0 + br i1 %tobool128, label %if.then129, label %if.else164 + +if.then129: ; preds = %if.then126 + %add130 = add nsw i32 %e.0, 1 + %cmp131 = icmp sge i32 %add130, %i + br i1 %cmp131, label %if.then132, label %if.end134 + +if.then132: ; preds = %if.then129 + br label %if.end134 + +if.end134: ; preds = %if.then132, %if.then129 + %e.10 = phi i32 [ %add130, %if.then132 ], [ %e.0, %if.then129 ] + %cmp135 = icmp sge i32 %e.10, %i + br i1 %cmp135, label %if.then136, label %if.end139 + +if.then136: ; preds = %if.end134 + %idxprom137 = sext i32 %e.10 to i64 + br label %if.end139 + +if.end139: ; preds = %if.then136, %if.end134 + br i1 %cmp135, label %if.then141, label %if.end144 + +if.then141: ; preds = %if.end139 + %idxprom142 = sext i32 %e.10 to i64 + br label %if.end144 + +if.end144: ; preds = %if.then141, %if.end139 + br i1 %cmp135, label %if.then146, label %if.end149 + +if.then146: ; preds = %if.end144 + %idxprom147 = sext i32 %e.10 to i64 + br label %if.end149 + +if.end149: ; preds = %if.then146, %if.end144 + br i1 %cmp135, label %if.then151, label %if.else154 + +if.then151: ; preds = %if.end149 + %idxprom152 = sext i32 %e.10 to i64 + br label %if.end160 + +if.else154: ; preds = %if.end149 + %idxprom157 = sext i32 %e.10 to i64 + br label %if.end160 + +if.end160: ; preds = %if.else154, %if.then151 + br i1 %cmp135, label %if.then162, label %if.end628 + +if.then162: ; preds = %if.end160 + unreachable + +if.else164: ; preds = %if.then126 + %4 = load i32*, i32** @c, align 8 + %tobool165 = icmp ne i32* %4, null + br i1 %tobool165, label %if.then166, label %if.else195 + +if.then166: ; preds = %if.else164 + %add167 = add nsw i32 %e.0, 1 + %cmp168 = icmp sge i32 %add167, %i + br i1 %cmp168, label %if.then169, label %if.end173 + +if.then169: ; preds = %if.then166 + %idxprom171 = sext i32 %add167 to i64 + br label %if.end173 + +if.end173: ; preds = %if.then169, %if.then166 + br i1 %cmp168, label %if.then176, label %if.end180 + +if.then176: ; preds = %if.end173 + %idxprom178 = sext i32 %add167 to i64 + unreachable + +if.end180: ; preds = %if.end173 + br i1 %cmp168, label %if.then183, label %if.end187 + +if.then183: ; preds = %if.end180 + %idxprom185 = sext i32 %add167 to i64 + unreachable + +if.end187: ; preds = %if.end180 + br i1 %cmp168, label %if.then190, label %if.end628 + +if.then190: ; preds = %if.end187 + br label %if.end628 + +if.else195: ; preds = %if.else164 + %5 = load i32, i32* @d, align 4 + %tobool196 = icmp ne i32 %5, 0 + br i1 %tobool196, label %if.then197, label %if.else205 + +if.then197: ; preds = %if.else195 + %add198 = add nsw i32 %e.0, 1 + %cmp199 = icmp sge i32 %add198, %i + br i1 %cmp199, label %if.then200, label %if.end628 + +if.then200: ; preds = %if.then197 + %idxprom202 = sext i32 %add198 to i64 + br label %if.end628 + +if.else205: ; preds = %if.else195 + %call206 = call i32 @h() + %tobool207 = icmp ne i32 %call206, 0 + br i1 %tobool207, label %if.then208, label %if.else217 + +if.then208: ; preds = %if.else205 + %add209 = add nsw i32 %e.0, 1 + %cmp210 = icmp sge i32 %add209, %i + br i1 %cmp210, label %if.then211, label %if.end215 + +if.then211: ; preds = %if.then208 + %idxprom213 = sext i32 %add209 to i64 + unreachable + +if.end215: ; preds = %if.then208 + %6 = zext i32 %add209 to i64 + br label %if.end628 + +if.else217: ; preds = %if.else205 + %7 = load i32*, i32** @c, align 8 + %tobool218 = icmp ne i32* %7, null + br i1 %tobool218, label %if.then219, label %if.else227 + +if.then219: ; preds = %if.else217 + %add220 = add nsw i32 %e.0, 1 + %cmp221 = icmp sge i32 %add220, %i + br i1 %cmp221, label %if.then222, label %if.end628 + +if.then222: ; preds = %if.then219 + %idxprom224 = sext i32 %add220 to i64 + br label %if.end628 + +if.else227: ; preds = %if.else217 + %call228 = call i32 @g() + %tobool229 = icmp ne i32 %call228, 0 + br i1 %tobool229, label %if.then230, label %if.else245 + +if.then230: ; preds = %if.else227 + %add231 = add nsw i32 %e.0, 1 + %cmp232 = icmp sge i32 %add231, %i + br i1 %cmp232, label %if.then233, label %if.end237 + +if.then233: ; preds = %if.then230 + %idxprom235 = sext i32 %add231 to i64 + br label %if.end237 + +if.end237: ; preds = %if.then233, %if.then230 + br i1 %cmp232, label %if.then240, label %if.end628 + +if.then240: ; preds = %if.end237 + %idxprom242 = sext i32 %add231 to i64 + br label %if.end628 + +if.else245: ; preds = %if.else227 + %8 = load i32*, i32** @c, align 8 + %tobool246 = icmp ne i32* %8, null + br i1 %tobool246, label %if.then247, label %if.else258 + +if.then247: ; preds = %if.else245 + %add248 = add nsw i32 %e.0, 1 + %cmp249 = icmp sge i32 %add248, %i + br i1 %cmp249, label %if.then250, label %if.end254 + +if.then250: ; preds = %if.then247 + %idxprom252 = sext i32 %add248 to i64 + unreachable + +if.end254: ; preds = %if.then247 + %9 = zext i32 %add248 to i64 + br label %if.end628 + +if.else258: ; preds = %if.else245 + %10 = load i32, i32* @d, align 4 + %tobool259 = icmp ne i32 %10, 0 + br i1 %tobool259, label %if.then260, label %if.else268 + +if.then260: ; preds = %if.else258 + %add261 = add nsw i32 %e.0, 1 + %cmp262 = icmp sge i32 %add261, %i + br i1 %cmp262, label %if.then263, label %if.end628 + +if.then263: ; preds = %if.then260 + %idxprom265 = sext i32 %add261 to i64 + br label %if.end628 + +if.else268: ; preds = %if.else258 + %call269 = call i32 @h() + %tobool270 = icmp ne i32 %call269, 0 + br i1 %tobool270, label %if.then271, label %if.else279 + +if.then271: ; preds = %if.else268 + %add272 = add nsw i32 %e.0, 1 + %cmp273 = icmp sge i32 %add272, %i + br i1 %cmp273, label %if.then274, label %if.end628 + +if.then274: ; preds = %if.then271 + %idxprom276 = sext i32 %add272 to i64 + br label %if.end628 + +if.else279: ; preds = %if.else268 + %11 = load i32*, i32** @c, align 8 + %tobool280 = icmp ne i32* %11, null + br i1 %tobool280, label %if.then281, label %if.else287 + +if.then281: ; preds = %if.else279 + %add282 = add nsw i32 %e.0, 2 + %cmp283 = icmp sge i32 %add282, %i + br i1 %cmp283, label %if.then284, label %if.end628 + +if.then284: ; preds = %if.then281 + br label %if.end628 + +if.else287: ; preds = %if.else279 + %call288 = call i32 @g() + %tobool289 = icmp ne i32 %call288, 0 + br i1 %tobool289, label %if.then290, label %if.else307 + +if.then290: ; preds = %if.else287 + %12 = load i32*, i32** @c, align 8 + %tobool291 = icmp ne i32* %12, null + br i1 %tobool291, label %if.then292, label %if.else298 + +if.then292: ; preds = %if.then290 + %add293 = add nsw i32 %e.0, 3 + %cmp294 = icmp sge i32 %add293, %i + br i1 %cmp294, label %if.then295, label %if.end628 + +if.then295: ; preds = %if.then292 + br label %if.end628 + +if.else298: ; preds = %if.then290 + %add299 = add nsw i32 %e.0, 4 + %cmp300 = icmp sge i32 %add299, %i + br i1 %cmp300, label %if.then301, label %if.end628 + +if.then301: ; preds = %if.else298 + %idxprom303 = sext i32 %add299 to i64 + br label %if.end628 + +if.else307: ; preds = %if.else287 + %13 = load i32*, i32** @c, align 8 + %tobool308 = icmp ne i32* %13, null + br i1 %tobool308, label %if.then309, label %if.else324 + +if.then309: ; preds = %if.else307 + %add310 = add nsw i32 %e.0, 1 + %cmp311 = icmp sge i32 %add310, %i + br i1 %cmp311, label %if.then312, label %if.else316 + +if.then312: ; preds = %if.then309 + %idxprom314 = sext i32 %add310 to i64 + br label %if.end628 + +if.else316: ; preds = %if.then309 + br i1 undef, label %if.then318, label %if.end628 + +if.then318: ; preds = %if.else316 + %idxprom320 = sext i32 %add310 to i64 + br label %if.end628 + +if.else324: ; preds = %if.else307 + %call325 = call i32 @g() + %tobool326 = icmp ne i32 %call325, 0 + br i1 %tobool326, label %if.then327, label %if.else475 + +if.then327: ; preds = %if.else324 + %add328 = add nsw i32 %e.0, 2 + %cmp329 = icmp sge i32 %add328, %i + br i1 %cmp329, label %if.then330, label %if.end332 + +if.then330: ; preds = %if.then327 + br label %if.end332 + +if.end332: ; preds = %if.then330, %if.then327 + %e.11 = phi i32 [ %add328, %if.then330 ], [ %e.0, %if.then327 ] + %cmp333 = icmp sge i32 %e.11, %i + br i1 %cmp333, label %if.then334, label %if.end336 + +if.then334: ; preds = %if.end332 + %inc335 = add nsw i32 %e.11, 1 + br label %if.end336 + +if.end336: ; preds = %if.then334, %if.end332 + %e.12 = phi i32 [ %inc335, %if.then334 ], [ %e.11, %if.end332 ] + %cmp337 = icmp sge i32 %e.12, %i + br i1 %cmp337, label %if.then338, label %if.end340 + +if.then338: ; preds = %if.end336 + %inc339 = add nsw i32 %e.12, 1 + br label %if.end340 + +if.end340: ; preds = %if.then338, %if.end336 + %e.13 = phi i32 [ %inc339, %if.then338 ], [ %e.12, %if.end336 ] + %cmp341 = icmp sge i32 %e.13, %i + br i1 %cmp341, label %if.then342, label %if.end344 + +if.then342: ; preds = %if.end340 + %inc343 = add nsw i32 %e.13, 1 + br label %if.end344 + +if.end344: ; preds = %if.then342, %if.end340 + %e.14 = phi i32 [ %inc343, %if.then342 ], [ %e.13, %if.end340 ] + %call345 = call i32 @g() + %tobool346 = icmp ne i32 %call345, 0 + br i1 %tobool346, label %if.then347, label %if.else398 + +if.then347: ; preds = %if.end344 + %cmp348 = icmp sge i32 %e.14, %i + br i1 %cmp348, label %if.then349, label %if.end352 + +if.then349: ; preds = %if.then347 + %idxprom350 = sext i32 %e.14 to i64 + br label %if.end352 + +if.end352: ; preds = %if.then349, %if.then347 + br i1 %cmp348, label %if.then354, label %if.else357 + +if.then354: ; preds = %if.end352 + %idxprom355 = sext i32 %e.14 to i64 + br label %if.end361 + +if.else357: ; preds = %if.end352 + %idxprom359 = sext i32 %e.14 to i64 + br label %if.end361 + +if.end361: ; preds = %if.else357, %if.then354 + br i1 %cmp348, label %if.then363, label %if.end366 + +if.then363: ; preds = %if.end361 + %idxprom364 = sext i32 %e.14 to i64 + br label %if.end366 + +if.end366: ; preds = %if.then363, %if.end361 + br i1 %cmp348, label %if.then368, label %if.end371 + +if.then368: ; preds = %if.end366 + %idxprom369 = sext i32 %e.14 to i64 + br label %if.end371 + +if.end371: ; preds = %if.then368, %if.end366 + br i1 %cmp348, label %if.then373, label %if.end376 + +if.then373: ; preds = %if.end371 + %idxprom374 = sext i32 %e.14 to i64 + br label %if.end376 + +if.end376: ; preds = %if.then373, %if.end371 + br i1 %cmp348, label %if.then378, label %if.end381 + +if.then378: ; preds = %if.end376 + %idxprom379 = sext i32 %e.14 to i64 + br label %if.end381 + +if.end381: ; preds = %if.then378, %if.end376 + br i1 %cmp348, label %if.then383, label %if.else386 + +if.then383: ; preds = %if.end381 + %idxprom384 = sext i32 %e.14 to i64 + br label %if.end390 + +if.else386: ; preds = %if.end381 + %idxprom388 = sext i32 %e.14 to i64 + br label %if.end390 + +if.end390: ; preds = %if.else386, %if.then383 + %add391 = add nsw i32 %e.14, 1 + %cmp392 = icmp sge i32 %add391, %i + br i1 %cmp392, label %if.then393, label %if.end628 + +if.then393: ; preds = %if.end390 + %idxprom395 = sext i32 %add391 to i64 + br label %if.end628 + +if.else398: ; preds = %if.end344 + %call399 = call i32 @h() + %tobool400 = icmp ne i32 %call399, 0 + br i1 %tobool400, label %if.then401, label %if.else409 + +if.then401: ; preds = %if.else398 + %add402 = add nsw i32 %e.14, 1 + %cmp403 = icmp sge i32 %add402, %i + br i1 %cmp403, label %if.then404, label %if.end628 + +if.then404: ; preds = %if.then401 + %idxprom406 = sext i32 %add402 to i64 + br label %if.end628 + +if.else409: ; preds = %if.else398 + %call410 = call i32 @h() + %tobool411 = icmp ne i32 %call410, 0 + br i1 %tobool411, label %if.then412, label %if.else420 + +if.then412: ; preds = %if.else409 + %add413 = add nsw i32 %e.14, 1 + %cmp414 = icmp sge i32 %add413, %i + br i1 %cmp414, label %if.then415, label %if.end628 + +if.then415: ; preds = %if.then412 + %idxprom417 = sext i32 %add413 to i64 + br label %if.end628 + +if.else420: ; preds = %if.else409 + %call421 = call i32 @h() + %tobool422 = icmp ne i32 %call421, 0 + br i1 %tobool422, label %if.then423, label %if.else431 + +if.then423: ; preds = %if.else420 + %add424 = add nsw i32 %e.14, 3 + %cmp425 = icmp sge i32 %add424, %i + br i1 %cmp425, label %if.then426, label %if.end628 + +if.then426: ; preds = %if.then423 + %idxprom428 = sext i32 %add424 to i64 + br label %if.end628 + +if.else431: ; preds = %if.else420 + %call432 = call i32 @h() + %tobool433 = icmp ne i32 %call432, 0 + br i1 %tobool433, label %if.then434, label %if.else440 + +if.then434: ; preds = %if.else431 + %add435 = add nsw i32 %e.14, 1 + %cmp436 = icmp sge i32 %add435, %i + br i1 %cmp436, label %if.then437, label %if.end628 + +if.then437: ; preds = %if.then434 + br label %if.end628 + +if.else440: ; preds = %if.else431 + %call441 = call i32 @h() + %tobool442 = icmp ne i32 %call441, 0 + br i1 %tobool442, label %if.then443, label %if.else451 + +if.then443: ; preds = %if.else440 + %tobool444 = icmp ne i32 %e.14, 0 + br i1 %tobool444, label %if.then445, label %if.end628 + +if.then445: ; preds = %if.then443 + %cmp446 = icmp sge i32 %e.14, %i + br i1 %cmp446, label %if.then447, label %if.end628 + +if.then447: ; preds = %if.then445 + br label %if.end628 + +if.else451: ; preds = %if.else440 + %call452 = call i32 @h() + %tobool453 = icmp ne i32 %call452, 0 + br i1 %tobool453, label %if.then454, label %if.else460 + +if.then454: ; preds = %if.else451 + %add455 = add nsw i32 %e.14, 1 + %cmp456 = icmp sge i32 %add455, %i + br i1 %cmp456, label %if.then457, label %if.end628 + +if.then457: ; preds = %if.then454 + br label %if.end628 + +if.else460: ; preds = %if.else451 + %add461 = add nsw i32 %e.14, 2 + %cmp462 = icmp sge i32 %add461, %i + br i1 %cmp462, label %if.then463, label %if.end628 + +if.then463: ; preds = %if.else460 + %idxprom465 = sext i32 %add461 to i64 + br label %if.end628 + +if.else475: ; preds = %if.else324 + %call476 = call i32 @g() + %tobool477 = icmp ne i32 %call476, 0 + br i1 %tobool477, label %if.then478, label %if.else509 + +if.then478: ; preds = %if.else475 + %call479 = call i32 @h() + %tobool480 = icmp ne i32 %call479, 0 + br i1 %tobool480, label %if.then481, label %if.else487 + +if.then481: ; preds = %if.then478 + %add482 = add nsw i32 %e.0, 1 + %cmp483 = icmp sge i32 %add482, %i + br i1 %cmp483, label %if.then484, label %if.end628 + +if.then484: ; preds = %if.then481 + br label %if.end628 + +if.else487: ; preds = %if.then478 + %call488 = call i32 @h() + %tobool489 = icmp ne i32 %call488, 0 + br i1 %tobool489, label %if.then490, label %if.else496 + +if.then490: ; preds = %if.else487 + %add491 = add nsw i32 %e.0, 1 + %cmp492 = icmp sge i32 %add491, %i + br i1 %cmp492, label %if.then493, label %if.end628 + +if.then493: ; preds = %if.then490 + br label %if.end628 + +if.else496: ; preds = %if.else487 + %add497 = add nsw i32 %e.0, 1 + %cmp498 = icmp sge i32 %add497, %i + br i1 %cmp498, label %if.then499, label %if.else501 + +if.then499: ; preds = %if.else496 + br label %if.end628 + +if.else501: ; preds = %if.else496 + br i1 undef, label %if.then503, label %if.end628 + +if.then503: ; preds = %if.else501 + br label %if.end628 + +if.else509: ; preds = %if.else475 + %call510 = call i32 @g() + %tobool511 = icmp ne i32 %call510, 0 + br i1 %tobool511, label %if.then512, label %if.else565 + +if.then512: ; preds = %if.else509 + %add513 = add nsw i32 %e.0, 1 + %cmp514 = icmp sge i32 %add513, %i + br i1 %cmp514, label %if.then515, label %if.end519 + +if.then515: ; preds = %if.then512 + %idxprom517 = sext i32 %add513 to i64 + br label %if.end519 + +if.end519: ; preds = %if.then515, %if.then512 + br i1 %cmp514, label %if.then522, label %if.end526 + +if.then522: ; preds = %if.end519 + %idxprom524 = sext i32 %add513 to i64 + br label %if.end526 + +if.end526: ; preds = %if.then522, %if.end519 + br i1 %cmp514, label %if.then529, label %if.end533 + +if.then529: ; preds = %if.end526 + %idxprom531 = sext i32 %add513 to i64 + br label %if.end533 + +if.end533: ; preds = %if.then529, %if.end526 + %add534 = add nsw i32 %e.0, 2 + %cmp535 = icmp sge i32 %add534, %i + br i1 %cmp535, label %if.then536, label %if.end540 + +if.then536: ; preds = %if.end533 + %idxprom538 = sext i32 %add534 to i64 + br label %if.end540 + +if.end540: ; preds = %if.then536, %if.end533 + br i1 %cmp535, label %if.then543, label %if.end547 + +if.then543: ; preds = %if.end540 + %idxprom545 = sext i32 %add534 to i64 + unreachable + +if.end547: ; preds = %if.end540 + br i1 %cmp514, label %if.then550, label %if.else554 + +if.then550: ; preds = %if.end547 + %idxprom552 = sext i32 %add513 to i64 + br label %if.end559 + +if.else554: ; preds = %if.end547 + %idxprom557 = sext i32 %add513 to i64 + br label %if.end559 + +if.end559: ; preds = %if.else554, %if.then550 + br i1 %cmp514, label %if.then562, label %if.end628 + +if.then562: ; preds = %if.end559 + br label %if.end628 + +if.else565: ; preds = %if.else509 + %call566 = call i32 @g() + %tobool567 = icmp ne i32 %call566, 0 + br i1 %tobool567, label %if.then568, label %if.else590 + +if.then568: ; preds = %if.else565 + %add569 = add nsw i32 %e.0, 2 + %cmp570 = icmp sge i32 %add569, %i + br i1 %cmp570, label %if.then571, label %if.else575 + +if.then571: ; preds = %if.then568 + %idxprom573 = sext i32 %add569 to i64 + br label %if.end582 + +if.else575: ; preds = %if.then568 + %idxprom579 = sext i32 %add569 to i64 + br label %if.end582 + +if.end582: ; preds = %if.else575, %if.then571 + %add583 = add nsw i32 %e.0, 1 + %cmp584 = icmp sge i32 %add583, %i + br i1 %cmp584, label %if.then585, label %if.end628 + +if.then585: ; preds = %if.end582 + %idxprom587 = sext i32 %add583 to i64 + br label %if.end628 + +if.else590: ; preds = %if.else565 + %call591 = call i32 @g() + %tobool592 = icmp ne i32 %call591, 0 + br i1 %tobool592, label %if.then593, label %if.end628 + +if.then593: ; preds = %if.else590 + %add594 = add nsw i32 %e.0, 1 + %cmp595 = icmp sge i32 %add594, %i + br i1 %cmp595, label %if.then596, label %if.else600 + +if.then596: ; preds = %if.then593 + %idxprom598 = sext i32 %add594 to i64 + br label %if.end628 + +if.else600: ; preds = %if.then593 + br i1 undef, label %if.then602, label %if.end628 + +if.then602: ; preds = %if.else600 + %idxprom604 = sext i32 %add594 to i64 + br label %if.end628 + +if.end628: ; preds = %if.then602, %if.else600, %if.then596, %if.else590, %if.then585, %if.end582, %if.then562, %if.end559, %if.then503, %if.else501, %if.then499, %if.then493, %if.then490, %if.then484, %if.then481, %if.then463, %if.else460, %if.then457, %if.then454, %if.then447, %if.then445, %if.then443, %if.then437, %if.then434, %if.then426, %if.then423, %if.then415, %if.then412, %if.then404, %if.then401, %if.then393, %if.end390, %if.then318, %if.else316, %if.then312, %if.then301, %if.else298, %if.then295, %if.then292, %if.then284, %if.then281, %if.then274, %if.then271, %if.then263, %if.then260, %if.end254, %if.then240, %if.end237, %if.then222, %if.then219, %if.end215, %if.then200, %if.then197, %if.then190, %if.end187, %if.end160, %if.else123, %if.then120, %if.end118, %if.then71, %if.else68, %if.then65, %if.end62, %if.then53, %for.cond + %e.15 = phi i32 [ %e.5, %if.then53 ], [ %add63, %if.then65 ], [ %e.6, %if.end62 ], [ %e.5, %if.then71 ], [ %e.5, %if.else68 ], [ %e.9, %if.then120 ], [ %e.9, %if.end118 ], [ %e.10, %if.end160 ], [ %e.0, %if.then190 ], [ %e.0, %if.end187 ], [ %e.0, %if.then200 ], [ %e.0, %if.then197 ], [ %e.0, %if.end215 ], [ %e.0, %if.then222 ], [ %e.0, %if.then219 ], [ %e.0, %if.then240 ], [ %e.0, %if.end237 ], [ %e.0, %if.end254 ], [ %e.0, %if.then263 ], [ %e.0, %if.then260 ], [ %e.0, %if.then274 ], [ %e.0, %if.then271 ], [ %add282, %if.then284 ], [ %e.0, %if.then281 ], [ %add293, %if.then295 ], [ %e.0, %if.then292 ], [ %e.0, %if.then301 ], [ %e.0, %if.else298 ], [ %e.0, %if.then312 ], [ %e.0, %if.then318 ], [ %e.0, %if.else316 ], [ %e.14, %if.then393 ], [ %e.14, %if.end390 ], [ %e.14, %if.then404 ], [ %e.14, %if.then401 ], [ %e.14, %if.then415 ], [ %e.14, %if.then412 ], [ %e.14, %if.then426 ], [ %e.14, %if.then423 ], [ %add435, %if.then437 ], [ %e.14, %if.then434 ], [ %e.14, %if.then447 ], [ %e.14, %if.then445 ], [ %e.14, %if.then443 ], [ %add455, %if.then457 ], [ %e.14, %if.then454 ], [ %e.14, %if.then463 ], [ %e.14, %if.else460 ], [ %add482, %if.then484 ], [ %e.0, %if.then481 ], [ %add491, %if.then493 ], [ %e.0, %if.then490 ], [ %add497, %if.then499 ], [ %add497, %if.then503 ], [ %e.0, %if.else501 ], [ %add513, %if.then562 ], [ %e.0, %if.end559 ], [ %e.0, %if.then585 ], [ %e.0, %if.end582 ], [ %e.0, %if.then596 ], [ %e.0, %if.then602 ], [ %e.0, %if.else600 ], [ %e.0, %if.else590 ], [ %e.0, %if.else123 ], [ %e.0, %for.cond ] + br label %for.cond +} + +declare i32 @g() + +declare i32 @h() + +; Function Attrs: nofree nosync nounwind willreturn +declare void @llvm.assume(i1 noundef) + From llvm-branch-commits at lists.llvm.org Tue May 11 20:35:55 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:35:55 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 33d312b - Revert "[Coverage] Fix branch coverage merging in FunctionCoverageSummary::get() for instantiation" Message-ID: <609b4d1b.1c69fb81.6da3e.b07d@mx.google.com> Author: Tom Stellard Date: 2021-05-11T20:35:17-07:00 New Revision: 33d312b2d731507327252fd597bac1b738870330 URL: https://github.com/llvm/llvm-project/commit/33d312b2d731507327252fd597bac1b738870330 DIFF: https://github.com/llvm/llvm-project/commit/33d312b2d731507327252fd597bac1b738870330.diff LOG: Revert "[Coverage] Fix branch coverage merging in FunctionCoverageSummary::get() for instantiation" This reverts commit b89942c336a4506dabd5e1b2a6f1b5cbaddebe55. There are issues with this patch and also no tracking bug for it. Added: Modified: llvm/test/tools/llvm-cov/branch-templates.cpp llvm/tools/llvm-cov/CoverageSummaryInfo.cpp llvm/tools/llvm-cov/CoverageSummaryInfo.h Removed: ################################################################################ diff --git a/llvm/test/tools/llvm-cov/branch-templates.cpp b/llvm/test/tools/llvm-cov/branch-templates.cpp index 4797428f8835..750dc7bd58f2 100644 --- a/llvm/test/tools/llvm-cov/branch-templates.cpp +++ b/llvm/test/tools/llvm-cov/branch-templates.cpp @@ -1,9 +1,9 @@ // RUN: llvm-profdata merge %S/Inputs/branch-templates.proftext -o %t.profdata // RUN: llvm-cov show --show-expansions --show-branches=count %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s // RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -show-functions -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORT -// RUN: llvm-cov report --show-branch-summary %S/Inputs/branch-templates.o32l -instr-profile %t.profdata -path-equivalence=/tmp,%S %s | FileCheck %s -check-prefix=REPORTFILE #include + template void unused(T x) { return; @@ -45,17 +45,3 @@ int main() { // REPORT-NEXT: _Z4funcIfEiT_ 5 2 60.00% 7 3 57.14% 2 1 50.00% // REPORT-NEXT: --- // REPORT-NEXT: TOTAL 22 7 68.18% 31 11 64.52% 12 6 50.00% - -// Make sure the covered branch tally for the function instantiation group is -// merged to reflect maximum branch coverage of a single instantiation, just -// like what is done for lines and regions. Also, the total branch tally -// summary for an instantiation group should agree with the total number of -// branches in the definition (In this case, 2 and 6 for func<>() and main(), -// respectively). This is returned by: FunctionCoverageSummary::get(const -// InstantiationGroup &Group, ...) - -// REPORTFILE: Filename Regions Missed Regions Cover Functions Missed Functions Executed Lines Missed Lines Cover Branches Missed Branches Cover -// REPORTFILE-NEXT: --- -// REPORTFILE-NEXT: branch-templates.cpp 12 3 75.00% 2 0 100.00% 17 4 76.47% 8 4 50.00% -// REPORTFILE-NEXT: --- -// REPORTFILE-NEXT: TOTAL 12 3 75.00% 2 0 100.00% 17 4 76.47% 8 4 50.00% diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp index 10e059adeb7d..4a0a86168908 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.cpp @@ -100,7 +100,11 @@ FunctionCoverageSummary::get(const InstantiationGroup &Group, for (const auto &FCS : Summaries.drop_front()) { Summary.RegionCoverage.merge(FCS.RegionCoverage); Summary.LineCoverage.merge(FCS.LineCoverage); - Summary.BranchCoverage.merge(FCS.BranchCoverage); + + // Sum branch coverage across instantiation groups for the summary rather + // than "merge" the maximum count. This is a clearer view into whether all + // created branches are covered. + Summary.BranchCoverage += FCS.BranchCoverage; } return Summary; } diff --git a/llvm/tools/llvm-cov/CoverageSummaryInfo.h b/llvm/tools/llvm-cov/CoverageSummaryInfo.h index 62e7cad1012b..4bc1c24a079f 100644 --- a/llvm/tools/llvm-cov/CoverageSummaryInfo.h +++ b/llvm/tools/llvm-cov/CoverageSummaryInfo.h @@ -123,11 +123,6 @@ class BranchCoverageInfo { return *this; } - void merge(const BranchCoverageInfo &RHS) { - Covered = std::max(Covered, RHS.Covered); - NumBranches = std::max(NumBranches, RHS.NumBranches); - } - size_t getCovered() const { return Covered; } size_t getNumBranches() const { return NumBranches; } From llvm-branch-commits at lists.llvm.org Tue May 11 20:43:27 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:43:27 -0700 (PDT) Subject: [llvm-branch-commits] [lld] 6912082 - [ELF] Don't set versionId on undefined weak lazy symbols Message-ID: <609b4edf.1c69fb81.3106.d871@mx.google.com> Author: Fangrui Song Date: 2021-05-11T20:43:08-07:00 New Revision: 6912082cfd129bbc2bd60f293371e20140d50b86 URL: https://github.com/llvm/llvm-project/commit/6912082cfd129bbc2bd60f293371e20140d50b86 DIFF: https://github.com/llvm/llvm-project/commit/6912082cfd129bbc2bd60f293371e20140d50b86.diff LOG: [ELF] Don't set versionId on undefined weak lazy symbols An unfetched lazy symbol (undefined weak) should be considered to have its original versionId which is VER_NDX_GLOBAL, instead of the lazy symbol's versionId. (The original versionId cannot be non-VER_NDX_GLOBAL because a undefined versioned symbol is an error.) The regression was introduced in D77280 when making version scripts work with lazy symbols fetched by LTO calls. Fix PR49915 Differential Revision: https://reviews.llvm.org/D100624 (cherry picked from commit 1c00530b30e21fd0f5b316401f6485bee08ce850) Added: Modified: lld/ELF/SyntheticSections.cpp lld/test/ELF/version-script-weak.s Removed: ################################################################################ diff --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp index 9a875bd7ec3e..70c36c63d101 100644 --- a/lld/ELF/SyntheticSections.cpp +++ b/lld/ELF/SyntheticSections.cpp @@ -3110,7 +3110,9 @@ size_t VersionTableSection::getSize() const { void VersionTableSection::writeTo(uint8_t *buf) { buf += 2; for (const SymbolTableEntry &s : getPartition().dynSymTab->getSymbols()) { - write16(buf, s.sym->versionId); + // Use the original versionId for an unfetched lazy symbol (undefined weak), + // which must be VER_NDX_GLOBAL (an undefined versioned symbol is an error). + write16(buf, s.sym->isLazy() ? VER_NDX_GLOBAL : s.sym->versionId); buf += 2; } } diff --git a/lld/test/ELF/version-script-weak.s b/lld/test/ELF/version-script-weak.s index 7c902eb98bf4..cfa2455ee2bd 100644 --- a/lld/test/ELF/version-script-weak.s +++ b/lld/test/ELF/version-script-weak.s @@ -24,6 +24,19 @@ # CHECK-NEXT: Section: Undefined # CHECK-NEXT: } +## The version of an unfetched lazy symbol is VER_NDX_GLOBAL. It is not affected by version scripts. +# RUN: echo "v1 { *; };" > %t2.script +# RUN: ld.lld -shared --version-script %t2.script %t.o --start-lib %t1.o --end-lib -o %t2.so +# RUN: llvm-readelf --dyn-syms %t2.so | FileCheck %s --check-prefix=CHECK2 + +# CHECK2: NOTYPE WEAK DEFAULT UND foo{{$}} + +# RUN: ld.lld -shared --soname=tshared --version-script %t2.script %t1.o -o %tshared.so +# RUN: ld.lld -shared --version-script %t2.script %t.o --start-lib %t1.o --end-lib %tshared.so -o %t3.so +# RUN: llvm-readelf --dyn-syms %t3.so | FileCheck %s --check-prefix=CHECK3 + +# CHECK3: NOTYPE WEAK DEFAULT UND foo at v1 + .text callq foo at PLT .weak foo From llvm-branch-commits at lists.llvm.org Tue May 11 20:53:34 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:53:34 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 0ef7836 - [IndVarSimplify] Add additional tests using isImpliedViaMerge. Message-ID: <609b513e.1c69fb81.9ce87.8e35@mx.google.com> Author: Florian Hahn Date: 2021-05-11T20:52:58-07:00 New Revision: 0ef78361565a861cac846b7c1f807dc2d278145d URL: https://github.com/llvm/llvm-project/commit/0ef78361565a861cac846b7c1f807dc2d278145d DIFF: https://github.com/llvm/llvm-project/commit/0ef78361565a861cac846b7c1f807dc2d278145d.diff LOG: [IndVarSimplify] Add additional tests using isImpliedViaMerge. (cherry picked from commit d65e5f60f110046898ad146c508a7d225d398549) Added: Modified: llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll Removed: ################################################################################ diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll index ddf8ada68e95..eec7908b6a8b 100644 --- a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll +++ b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll @@ -436,3 +436,58 @@ exit: } declare void @side_effect() + +; The exit condition %outer.cond.1 depends on a phi in %inner. Make sure we do +; not incorrectly determine %x.lcssa <= -1. +define i32 @exit_cond_depends_on_inner_loop() { +; CHECK-LABEL: @exit_cond_depends_on_inner_loop( +; CHECK-NEXT: entry: +; CHECK-NEXT: br label [[OUTER_HEADER:%.*]] +; CHECK: outer.header: +; CHECK-NEXT: [[IV_OUTER:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[IV_OUTER_NEXT:%.*]], [[OUTER_LATCH:%.*]] ] +; CHECK-NEXT: br label [[INNER:%.*]] +; CHECK: inner: +; CHECK-NEXT: [[X:%.*]] = phi i32 [ -1, [[OUTER_HEADER]] ], [ [[CALL:%.*]], [[INNER]] ] +; CHECK-NEXT: [[CALL]] = call i32 @match() +; CHECK-NEXT: [[INNER_COND:%.*]] = icmp sgt i32 [[CALL]], -1 +; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER]], label [[OUTER_EXITING_1:%.*]] +; CHECK: outer.exiting.1: +; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i32 [ [[X]], [[INNER]] ] +; CHECK-NEXT: br i1 false, label [[EXIT:%.*]], label [[OUTER_LATCH]] +; CHECK: outer.latch: +; CHECK-NEXT: [[IV_OUTER_NEXT]] = add nuw nsw i32 [[IV_OUTER]], 1 +; CHECK-NEXT: [[OUTER_COND_2:%.*]] = icmp ult i32 [[IV_OUTER]], 100 +; CHECK-NEXT: br i1 [[OUTER_COND_2]], label [[OUTER_HEADER]], label [[EXIT]] +; CHECK: exit: +; CHECK-NEXT: [[X_RES:%.*]] = phi i32 [ [[X_LCSSA]], [[OUTER_EXITING_1]] ], [ -1, [[OUTER_LATCH]] ] +; CHECK-NEXT: ret i32 [[X_RES]] +; +entry: + br label %outer.header + +outer.header: + %iv.outer = phi i32 [ 0, %entry ], [ %iv.outer.next , %outer.latch ] + br label %inner + +inner: + %x = phi i32 [ -1, %outer.header ], [ %call, %inner ] + %call = call i32 @match() + %inner.cond = icmp sgt i32 %call, -1 + br i1 %inner.cond, label %inner, label %outer.exiting.1 + +outer.exiting.1: + %x.lcssa = phi i32 [ %x, %inner ] + %outer.cond.1 = icmp sgt i32 %x.lcssa, -1 + br i1 %outer.cond.1, label %exit, label %outer.latch + +outer.latch: + %iv.outer.next = add nuw nsw i32 %iv.outer, 1 + %outer.cond.2 = icmp ult i32 %iv.outer, 100 + br i1 %outer.cond.2, label %outer.header, label %exit + +exit: + %x.res = phi i32 [ %x.lcssa, %outer.exiting.1 ], [ -1, %outer.latch ] + ret i32 %x.res +} + +declare i32 @match() diff --git a/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll b/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll index 5cc288c58e68..2ecea576c380 100644 --- a/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll +++ b/llvm/test/Transforms/IndVarSimplify/promote-iv-to-eliminate-casts.ll @@ -373,4 +373,66 @@ loop: br i1 %loopcond, label %loopexit, label %loop } +define void @promote_latch_condition_decrementing_loop_05(i32* %p, i32* %a, i1 %cond) { +; CHECK-LABEL: @promote_latch_condition_decrementing_loop_05( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[LEN:%.*]] = load i32, i32* [[P:%.*]], align 4, [[RNG0]] +; CHECK-NEXT: br i1 [[COND:%.*]], label [[IF_TRUE:%.*]], label [[IF_FALSE:%.*]] +; CHECK: if.true: +; CHECK-NEXT: br label [[MERGE:%.*]] +; CHECK: if.false: +; CHECK-NEXT: [[LEN_MINUS_1:%.*]] = add nsw i32 [[LEN]], -1 +; CHECK-NEXT: br label [[MERGE]] +; CHECK: merge: +; CHECK-NEXT: [[IV_START:%.*]] = phi i32 [ [[LEN]], [[IF_TRUE]] ], [ [[LEN_MINUS_1]], [[IF_FALSE]] ] +; CHECK-NEXT: [[ZERO_CHECK:%.*]] = icmp eq i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[ZERO_CHECK]], label [[LOOPEXIT:%.*]], label [[PREHEADER:%.*]] +; CHECK: preheader: +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[IV_START]] to i64 +; CHECK-NEXT: br label [[LOOP:%.*]] +; CHECK: loopexit.loopexit: +; CHECK-NEXT: br label [[LOOPEXIT]] +; CHECK: loopexit: +; CHECK-NEXT: ret void +; CHECK: loop: +; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP]] ], [ [[TMP0]], [[PREHEADER]] ] +; CHECK-NEXT: [[EL:%.*]] = getelementptr inbounds i32, i32* [[A:%.*]], i64 [[INDVARS_IV]] +; CHECK-NEXT: store atomic i32 0, i32* [[EL]] unordered, align 4 +; CHECK-NEXT: [[LOOPCOND:%.*]] = icmp slt i64 [[INDVARS_IV]], 1 +; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nsw i64 [[INDVARS_IV]], -1 +; CHECK-NEXT: br i1 [[LOOPCOND]], label [[LOOPEXIT_LOOPEXIT:%.*]], label [[LOOP]] +; + +entry: + %len = load i32, i32* %p, align 4, !range !0 + br i1 %cond, label %if.true, label %if.false + +if.true: + br label %merge + +if.false: + %len.minus.1 = add nsw i32 %len, -1 + br label %merge + +merge: + %iv_start = phi i32 [ %len, %if.true ], [%len.minus.1, %if.false ] + %zero_check = icmp eq i32 %len, 0 + br i1 %zero_check, label %loopexit, label %preheader + +preheader: + br label %loop + +loopexit: + ret void + +loop: + %iv = phi i32 [ %iv.next, %loop ], [ %iv_start, %preheader ] + %iv.wide = zext i32 %iv to i64 + %el = getelementptr inbounds i32, i32* %a, i64 %iv.wide + store atomic i32 0, i32* %el unordered, align 4 + %iv.next = add nsw i32 %iv, -1 + %loopcond = icmp slt i32 %iv, 1 + br i1 %loopcond, label %loopexit, label %loop +} + !0 = !{i32 0, i32 2147483647} From llvm-branch-commits at lists.llvm.org Tue May 11 20:53:36 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:53:36 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 4e46ff4 - [SCEV] By more careful when traversing phis in isImpliedViaMerge. Message-ID: <609b5140.1c69fb81.84ff4.c4a4@mx.google.com> Author: Florian Hahn Date: 2021-05-11T20:52:59-07:00 New Revision: 4e46ff469405bc73ec25fcf78126fb5fbd7a18a1 URL: https://github.com/llvm/llvm-project/commit/4e46ff469405bc73ec25fcf78126fb5fbd7a18a1 DIFF: https://github.com/llvm/llvm-project/commit/4e46ff469405bc73ec25fcf78126fb5fbd7a18a1.diff LOG: [SCEV] By more careful when traversing phis in isImpliedViaMerge. I think currently isImpliedViaMerge can incorrectly return true for phis in a loop/cycle, if the found condition involves the previous value of Consider the case in exit_cond_depends_on_inner_loop. At some point, we call (modulo simplifications) isImpliedViaMerge(<=, %x.lcssa, -1, %call, -1). The existing code tries to prove IncV <= -1 for all incoming values InvV using the found condition (%call <= -1). At the moment this succeeds, but only because it does not compare the same runtime value. The found condition checks the value of the last iteration, but the incoming value is from the *previous* iteration. Hence we incorrectly determine that the *previous* value was <= -1, which may not be true. I think we need to be more careful when looking at the incoming values here. In particular, we need to rule out that a found condition refers to any value that may refer to one of the previous iterations. I'm not sure there's a reliable way to do so (that also works of irreducible control flow). So for now this patch adds an additional requirement that the incoming value must properly dominate the phi block. This should ensure the values do not change in a cycle. I am not entirely sure if will catch all cases and I appreciate a through second look in that regard. Alternatively we could also unconditionally bail out in this case, instead of checking the incoming values Reviewed By: nikic Differential Revision: https://reviews.llvm.org/D101829 (cherry picked from commit 6c99e631201aaea0a75708749cbaf2ba08a493f9) Added: Modified: llvm/lib/Analysis/ScalarEvolution.cpp llvm/test/Transforms/IRCE/decrementing-loop.ll llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll Removed: ################################################################################ diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp index fe9d8297d679..1a9ae68573e9 100644 --- a/llvm/lib/Analysis/ScalarEvolution.cpp +++ b/llvm/lib/Analysis/ScalarEvolution.cpp @@ -10622,6 +10622,10 @@ bool ScalarEvolution::isImpliedViaMerge(ICmpInst::Predicate Pred, if (!dominates(RHS, IncBB)) return false; const SCEV *L = getSCEV(LPhi->getIncomingValueForBlock(IncBB)); + // Make sure L does not refer to a value from a potentially previous + // iteration of a loop. + if (!properlyDominates(L, IncBB)) + return false; if (!ProvedEasily(L, RHS)) return false; } diff --git a/llvm/test/Transforms/IRCE/decrementing-loop.ll b/llvm/test/Transforms/IRCE/decrementing-loop.ll index a824522cf206..d809fb4f7d97 100644 --- a/llvm/test/Transforms/IRCE/decrementing-loop.ll +++ b/llvm/test/Transforms/IRCE/decrementing-loop.ll @@ -212,16 +212,17 @@ exit: ret void } +; TODO: we need to be more careful when trying to look through phi nodes in +; cycles, because the condition to prove may reference the previous value of +; the phi. So we currently fail to optimize this case. ; Check that we can figure out that IV is non-negative via implication through ; two Phi nodes, one being AddRec. define void @test_05(i32* %a, i32* %a_len_ptr, i1 %cond) { ; CHECK-LABEL: test_05 -; CHECK: mainloop: -; CHECK-NEXT: br label %loop -; CHECK: loop: -; CHECK: br i1 true, label %in.bounds, label %out.of.bounds -; CHECK: loop.preloop: +; CHECK: entry: +; CHECK: br label %merge +; CHECK-NOT: mainloop entry: %len.a = load i32, i32* %a_len_ptr, !range !0 diff --git a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll index eec7908b6a8b..e574c2f84ea3 100644 --- a/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll +++ b/llvm/test/Transforms/IndVarSimplify/eliminate-exit.ll @@ -453,7 +453,8 @@ define i32 @exit_cond_depends_on_inner_loop() { ; CHECK-NEXT: br i1 [[INNER_COND]], label [[INNER]], label [[OUTER_EXITING_1:%.*]] ; CHECK: outer.exiting.1: ; CHECK-NEXT: [[X_LCSSA:%.*]] = phi i32 [ [[X]], [[INNER]] ] -; CHECK-NEXT: br i1 false, label [[EXIT:%.*]], label [[OUTER_LATCH]] +; CHECK-NEXT: [[OUTER_COND_1:%.*]] = icmp sgt i32 [[X_LCSSA]], -1 +; CHECK-NEXT: br i1 [[OUTER_COND_1]], label [[EXIT:%.*]], label [[OUTER_LATCH]] ; CHECK: outer.latch: ; CHECK-NEXT: [[IV_OUTER_NEXT]] = add nuw nsw i32 [[IV_OUTER]], 1 ; CHECK-NEXT: [[OUTER_COND_2:%.*]] = icmp ult i32 [[IV_OUTER]], 100 From llvm-branch-commits at lists.llvm.org Tue May 11 20:54:18 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:54:18 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 4eb7b15 - [Inliner] Fix noalias metadata handling for instructions simplified during cloning (PR50270) Message-ID: <609b516a.1c69fb81.9e72d.3184@mx.google.com> Author: Nikita Popov Date: 2021-05-11T20:53:59-07:00 New Revision: 4eb7b15cb447b339e82bd320adf4a09ca64ab839 URL: https://github.com/llvm/llvm-project/commit/4eb7b15cb447b339e82bd320adf4a09ca64ab839 DIFF: https://github.com/llvm/llvm-project/commit/4eb7b15cb447b339e82bd320adf4a09ca64ab839.diff LOG: [Inliner] Fix noalias metadata handling for instructions simplified during cloning (PR50270) Instead of using VMap, which may include instructions from the caller as a result of simplification, iterate over the (FirstNewBlock, Caller->end()) range, which will only include new instructions. Fixes https://bugs.llvm.org/show_bug.cgi?id=50270. Differential Revision: https://reviews.llvm.org/D102110 (cherry picked from commit aa9b02ac75350a6c7c949dd24d5c6a931be26ff9) Added: llvm/test/Transforms/Inline/pr50270.ll Modified: llvm/lib/Transforms/Utils/InlineFunction.cpp Removed: ################################################################################ diff --git a/llvm/lib/Transforms/Utils/InlineFunction.cpp b/llvm/lib/Transforms/Utils/InlineFunction.cpp index 3026342cc4a6..fb271a2118ba 100644 --- a/llvm/lib/Transforms/Utils/InlineFunction.cpp +++ b/llvm/lib/Transforms/Utils/InlineFunction.cpp @@ -780,7 +780,8 @@ static void HandleInlinedEHPad(InvokeInst *II, BasicBlock *FirstNewBlock, /// When inlining a call site that has !llvm.mem.parallel_loop_access, /// !llvm.access.group, !alias.scope or !noalias metadata, that metadata should /// be propagated to all memory-accessing cloned instructions. -static void PropagateCallSiteMetadata(CallBase &CB, ValueToValueMapTy &VMap) { +static void PropagateCallSiteMetadata(CallBase &CB, Function::iterator FStart, + Function::iterator FEnd) { MDNode *MemParallelLoopAccess = CB.getMetadata(LLVMContext::MD_mem_parallel_loop_access); MDNode *AccessGroup = CB.getMetadata(LLVMContext::MD_access_group); @@ -789,41 +790,33 @@ static void PropagateCallSiteMetadata(CallBase &CB, ValueToValueMapTy &VMap) { if (!MemParallelLoopAccess && !AccessGroup && !AliasScope && !NoAlias) return; - for (ValueToValueMapTy::iterator VMI = VMap.begin(), VMIE = VMap.end(); - VMI != VMIE; ++VMI) { - // Check that key is an instruction, to skip the Argument mapping, which - // points to an instruction in the original function, not the inlined one. - if (!VMI->second || !isa(VMI->first)) - continue; - - Instruction *NI = dyn_cast(VMI->second); - if (!NI) - continue; - - // This metadata is only relevant for instructions that access memory. - if (!NI->mayReadOrWriteMemory()) - continue; + for (BasicBlock &BB : make_range(FStart, FEnd)) { + for (Instruction &I : BB) { + // This metadata is only relevant for instructions that access memory. + if (!I.mayReadOrWriteMemory()) + continue; - if (MemParallelLoopAccess) { - // TODO: This probably should not overwrite MemParalleLoopAccess. - MemParallelLoopAccess = MDNode::concatenate( - NI->getMetadata(LLVMContext::MD_mem_parallel_loop_access), - MemParallelLoopAccess); - NI->setMetadata(LLVMContext::MD_mem_parallel_loop_access, + if (MemParallelLoopAccess) { + // TODO: This probably should not overwrite MemParalleLoopAccess. + MemParallelLoopAccess = MDNode::concatenate( + I.getMetadata(LLVMContext::MD_mem_parallel_loop_access), + MemParallelLoopAccess); + I.setMetadata(LLVMContext::MD_mem_parallel_loop_access, MemParallelLoopAccess); - } + } - if (AccessGroup) - NI->setMetadata(LLVMContext::MD_access_group, uniteAccessGroups( - NI->getMetadata(LLVMContext::MD_access_group), AccessGroup)); + if (AccessGroup) + I.setMetadata(LLVMContext::MD_access_group, uniteAccessGroups( + I.getMetadata(LLVMContext::MD_access_group), AccessGroup)); - if (AliasScope) - NI->setMetadata(LLVMContext::MD_alias_scope, MDNode::concatenate( - NI->getMetadata(LLVMContext::MD_alias_scope), AliasScope)); + if (AliasScope) + I.setMetadata(LLVMContext::MD_alias_scope, MDNode::concatenate( + I.getMetadata(LLVMContext::MD_alias_scope), AliasScope)); - if (NoAlias) - NI->setMetadata(LLVMContext::MD_noalias, MDNode::concatenate( - NI->getMetadata(LLVMContext::MD_noalias), NoAlias)); + if (NoAlias) + I.setMetadata(LLVMContext::MD_noalias, MDNode::concatenate( + I.getMetadata(LLVMContext::MD_noalias), NoAlias)); + } } } @@ -844,9 +837,9 @@ class ScopedAliasMetadataDeepCloner { /// subsequent remap() calls. void clone(); - /// Remap instructions in the given VMap from the original to the cloned + /// Remap instructions in the given range from the original to the cloned /// metadata. - void remap(ValueToValueMapTy &VMap); + void remap(Function::iterator FStart, Function::iterator FEnd); }; ScopedAliasMetadataDeepCloner::ScopedAliasMetadataDeepCloner( @@ -907,34 +900,27 @@ void ScopedAliasMetadataDeepCloner::clone() { } } -void ScopedAliasMetadataDeepCloner::remap(ValueToValueMapTy &VMap) { +void ScopedAliasMetadataDeepCloner::remap(Function::iterator FStart, + Function::iterator FEnd) { if (MDMap.empty()) return; // Nothing to do. - for (auto Entry : VMap) { - // Check that key is an instruction, to skip the Argument mapping, which - // points to an instruction in the original function, not the inlined one. - if (!Entry->second || !isa(Entry->first)) - continue; - - Instruction *I = dyn_cast(Entry->second); - if (!I) - continue; - - // Only update scopes when we find them in the map. If they are not, it is - // because we already handled that instruction before. This is faster than - // tracking which instructions we already updated. - if (MDNode *M = I->getMetadata(LLVMContext::MD_alias_scope)) - if (MDNode *MNew = MDMap.lookup(M)) - I->setMetadata(LLVMContext::MD_alias_scope, MNew); - - if (MDNode *M = I->getMetadata(LLVMContext::MD_noalias)) - if (MDNode *MNew = MDMap.lookup(M)) - I->setMetadata(LLVMContext::MD_noalias, MNew); - - if (auto *Decl = dyn_cast(I)) - if (MDNode *MNew = MDMap.lookup(Decl->getScopeList())) - Decl->setScopeList(MNew); + for (BasicBlock &BB : make_range(FStart, FEnd)) { + for (Instruction &I : BB) { + // TODO: The null checks for the MDMap.lookup() results should no longer + // be necessary. + if (MDNode *M = I.getMetadata(LLVMContext::MD_alias_scope)) + if (MDNode *MNew = MDMap.lookup(M)) + I.setMetadata(LLVMContext::MD_alias_scope, MNew); + + if (MDNode *M = I.getMetadata(LLVMContext::MD_noalias)) + if (MDNode *MNew = MDMap.lookup(M)) + I.setMetadata(LLVMContext::MD_noalias, MNew); + + if (auto *Decl = dyn_cast(&I)) + if (MDNode *MNew = MDMap.lookup(Decl->getScopeList())) + Decl->setScopeList(MNew); + } } } @@ -1926,7 +1912,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, // Now clone the inlined noalias scope metadata. SAMetadataCloner.clone(); - SAMetadataCloner.remap(VMap); + SAMetadataCloner.remap(FirstNewBlock, Caller->end()); // Add noalias metadata if necessary. AddAliasScopeMetadata(CB, VMap, DL, CalleeAAR); @@ -1936,7 +1922,7 @@ llvm::InlineResult llvm::InlineFunction(CallBase &CB, InlineFunctionInfo &IFI, AddReturnAttributes(CB, VMap); // Propagate metadata on the callsite if necessary. - PropagateCallSiteMetadata(CB, VMap); + PropagateCallSiteMetadata(CB, FirstNewBlock, Caller->end()); // Register any cloned assumptions. if (IFI.GetAssumptionCache) diff --git a/llvm/test/Transforms/Inline/pr50270.ll b/llvm/test/Transforms/Inline/pr50270.ll new file mode 100644 index 000000000000..be7c3379ce87 --- /dev/null +++ b/llvm/test/Transforms/Inline/pr50270.ll @@ -0,0 +1,71 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt -S -inline < %s | FileCheck %s + +; This tests cases where instructions in the callee are simplified to +; instructions in the caller, thus making VMap contain instructions from +; the caller. We should not be assigning incorrect noalias metadata in +; that case. + +declare { i64* } @opaque_callee() + +define { i64* } @callee(i64* %x) { +; CHECK-LABEL: @callee( +; CHECK-NEXT: [[RES:%.*]] = insertvalue { i64* } undef, i64* [[X:%.*]], 0 +; CHECK-NEXT: ret { i64* } [[RES]] +; + %res = insertvalue { i64* } undef, i64* %x, 0 + ret { i64* } %res +} + +; @opaque_callee() should not receive noalias metadata here. +define void @caller() { +; CHECK-LABEL: @caller( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: [[S:%.*]] = call { i64* } @opaque_callee() +; CHECK-NEXT: [[X:%.*]] = extractvalue { i64* } [[S]], 0 +; CHECK-NEXT: ret void +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + %s = call { i64* } @opaque_callee() + %x = extractvalue { i64* } %s, 0 + call { i64* } @callee(i64* %x), !noalias !0 + ret void +} + +; @opaque_callee() should no the same noalias metadata as the load from the +; else branch, not as the load in the if branch. +define { i64* } @self_caller(i1 %c, i64* %a) { +; CHECK-LABEL: @self_caller( +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !0) +; CHECK-NEXT: br i1 [[C:%.*]], label [[IF:%.*]], label [[ELSE:%.*]] +; CHECK: if: +; CHECK-NEXT: [[S:%.*]] = call { i64* } @opaque_callee(), !noalias !0 +; CHECK-NEXT: [[X:%.*]] = extractvalue { i64* } [[S]], 0 +; CHECK-NEXT: call void @llvm.experimental.noalias.scope.decl(metadata !3) +; CHECK-NEXT: [[TMP1:%.*]] = load volatile i64, i64* [[X]], align 4, !alias.scope !3 +; CHECK-NEXT: ret { i64* } [[S]] +; CHECK: else: +; CHECK-NEXT: [[R2:%.*]] = insertvalue { i64* } undef, i64* [[A:%.*]], 0 +; CHECK-NEXT: [[TMP2:%.*]] = load volatile i64, i64* [[A]], align 4, !alias.scope !0 +; CHECK-NEXT: ret { i64* } [[R2]] +; + call void @llvm.experimental.noalias.scope.decl(metadata !0) + br i1 %c, label %if, label %else + +if: + %s = call { i64* } @opaque_callee(), !noalias !0 + %x = extractvalue { i64* } %s, 0 + %r = call { i64* } @self_caller(i1 false, i64* %x) + ret { i64* } %r + +else: + %r2 = insertvalue { i64* } undef, i64* %a, 0 + load volatile i64, i64* %a, !alias.scope !0 + ret { i64* } %r2 +} + +declare void @llvm.experimental.noalias.scope.decl(metadata) + +!0 = !{!1} +!1 = !{!1, !2, !"scope"} +!2 = !{!2, !"domain"} From llvm-branch-commits at lists.llvm.org Tue May 11 20:55:46 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Tue, 11 May 2021 20:55:46 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 877a07b - GlobalISel: Restrict narrow scalar for fptoui/fptosi results Message-ID: <609b51c2.1c69fb81.feb58.de77@mx.google.com> Author: Matt Arsenault Date: 2021-05-11T20:55:20-07:00 New Revision: 877a07bfb3b9a0bbaa3b63a222448b11d85821f0 URL: https://github.com/llvm/llvm-project/commit/877a07bfb3b9a0bbaa3b63a222448b11d85821f0 DIFF: https://github.com/llvm/llvm-project/commit/877a07bfb3b9a0bbaa3b63a222448b11d85821f0.diff LOG: GlobalISel: Restrict narrow scalar for fptoui/fptosi results This practically only works for the f16 case AMDGPU uses, not wider types. Fixes bug 49710 by failing legalization. (cherry picked from commit 83a25a101051b404bec1a5ba9cb867705f31262d) Added: Modified: llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir Removed: ################################################################################ diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h index c3b494e94ff1..4a982b00125d 100644 --- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h +++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerHelper.h @@ -316,6 +316,7 @@ class LegalizerHelper { LegalizeResult narrowScalarShift(MachineInstr &MI, unsigned TypeIdx, LLT Ty); LegalizeResult narrowScalarMul(MachineInstr &MI, LLT Ty); + LegalizeResult narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, LLT Ty); LegalizeResult narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT Ty); LegalizeResult narrowScalarInsert(MachineInstr &MI, unsigned TypeIdx, LLT Ty); diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp index 3178ee16af2b..66871ca3b926 100644 --- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp +++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp @@ -1257,22 +1257,9 @@ LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalar(MachineInstr &MI, Observer.changedInstr(MI); return Legalized; } - case TargetOpcode::G_FPTOUI: { - if (TypeIdx != 0) - return UnableToLegalize; - Observer.changingInstr(MI); - narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_ZEXT); - Observer.changedInstr(MI); - return Legalized; - } - case TargetOpcode::G_FPTOSI: { - if (TypeIdx != 0) - return UnableToLegalize; - Observer.changingInstr(MI); - narrowScalarDst(MI, NarrowTy, 0, TargetOpcode::G_SEXT); - Observer.changedInstr(MI); - return Legalized; - } + case TargetOpcode::G_FPTOUI: + case TargetOpcode::G_FPTOSI: + return narrowScalarFPTOI(MI, TypeIdx, NarrowTy); case TargetOpcode::G_FPEXT: if (TypeIdx != 0) return UnableToLegalize; @@ -4496,6 +4483,31 @@ LegalizerHelper::narrowScalarMul(MachineInstr &MI, LLT NarrowTy) { return Legalized; } +LegalizerHelper::LegalizeResult +LegalizerHelper::narrowScalarFPTOI(MachineInstr &MI, unsigned TypeIdx, + LLT NarrowTy) { + if (TypeIdx != 0) + return UnableToLegalize; + + bool IsSigned = MI.getOpcode() == TargetOpcode::G_FPTOSI; + + Register Src = MI.getOperand(1).getReg(); + LLT SrcTy = MRI.getType(Src); + + // If all finite floats fit into the narrowed integer type, we can just swap + // out the result type. This is practically only useful for conversions from + // half to at least 16-bits, so just handle the one case. + if (SrcTy.getScalarType() != LLT::scalar(16) || + NarrowTy.getScalarSizeInBits() < (IsSigned ? 17 : 16)) + return UnableToLegalize; + + Observer.changingInstr(MI); + narrowScalarDst(MI, NarrowTy, 0, + IsSigned ? TargetOpcode::G_SEXT : TargetOpcode::G_ZEXT); + Observer.changedInstr(MI); + return Legalized; +} + LegalizerHelper::LegalizeResult LegalizerHelper::narrowScalarExtract(MachineInstr &MI, unsigned TypeIdx, LLT NarrowTy) { diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir index 9bc639679bea..c82cedd08580 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir @@ -265,3 +265,31 @@ body: | %1:_(<4 x s32>) = G_FPTOSI %0 $q0 = COPY %1 ... + +--- +name: test_fptoui_s128_s32 +body: | + bb.0: + liveins: $w0 + ; CHECK-LABEL: name: test_fptoui_s128_s32 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK: [[FPTOUI:%[0-9]+]]:_(s128) = G_FPTOUI [[COPY]](s32) + ; CHECK: $q0 = COPY [[FPTOUI]](s128) + %0:_(s32) = COPY $w0 + %1:_(s128) = G_FPTOUI %0 + $q0 = COPY %1 +... + +--- +name: test_fptosi_s128_s32 +body: | + bb.0: + liveins: $w0 + ; CHECK-LABEL: name: test_fptosi_s128_s32 + ; CHECK: [[COPY:%[0-9]+]]:_(s32) = COPY $w0 + ; CHECK: [[FPTOSI:%[0-9]+]]:_(s128) = G_FPTOSI [[COPY]](s32) + ; CHECK: $q0 = COPY [[FPTOSI]](s128) + %0:_(s32) = COPY $w0 + %1:_(s128) = G_FPTOSI %0 + $q0 = COPY %1 +... From llvm-branch-commits at lists.llvm.org Wed May 12 14:23:22 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Wed, 12 May 2021 14:23:22 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 6336c6e - AArch64/GlobalISel: Remove IR section from test Message-ID: <609c474a.1c69fb81.2c232.2dae@mx.google.com> Author: Matt Arsenault Date: 2021-05-12T11:00:57-07:00 New Revision: 6336c6eec1a1c12205d102c5555101c100c5ec73 URL: https://github.com/llvm/llvm-project/commit/6336c6eec1a1c12205d102c5555101c100c5ec73 DIFF: https://github.com/llvm/llvm-project/commit/6336c6eec1a1c12205d102c5555101c100c5ec73.diff LOG: AArch64/GlobalISel: Remove IR section from test (cherry picked from commit 2f779e79d50114830c02cdb9e77bd851e13d9fc1) Added: Modified: llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir Removed: ################################################################################ diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir index c82cedd08580e..b2ee3a6cc777c 100644 --- a/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir +++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalize-fptoi.mir @@ -1,32 +1,5 @@ # NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py -# RUN: llc -O0 -run-pass=legalizer %s -o - | FileCheck %s - ---- | - target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" - target triple = "aarch64--" - - define void @test_fptosi_s32_s32() { ret void } - define void @test_fptoui_s32_s32() { ret void } - define void @test_fptosi_s32_s64() { ret void } - define void @test_fptoui_s32_s64() { ret void } - - define void @test_fptosi_s64_s32() { ret void } - define void @test_fptoui_s64_s32() { ret void } - define void @test_fptosi_s64_s64() { ret void } - define void @test_fptoui_s64_s64() { ret void } - - define void @test_fptosi_s1_s32() { ret void } - define void @test_fptoui_s1_s32() { ret void } - - define void @test_fptosi_s8_s64() { ret void } - define void @test_fptoui_s8_s64() { ret void } - - define void @test_fptosi_s16_s32() { ret void } - define void @test_fptoui_s16_s32() { ret void } - - define void @test_fptoui_v4s32() { ret void } - define void @test_fptosi_v4s32() { ret void } -... +# RUN: llc -mtriple=aarch64-- -O0 -run-pass=legalizer %s -o - | FileCheck %s --- name: test_fptosi_s32_s32 From llvm-branch-commits at lists.llvm.org Mon May 17 11:16:31 2021 From: llvm-branch-commits at lists.llvm.org (Nick Desaulniers via llvm-branch-commits) Date: Mon, 17 May 2021 11:16:31 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] de579ba - [LowerConstantIntrinsics] reuse isManifestLogic from ConstantFolding Message-ID: <60a2b2ff.1c69fb81.78bdc.43e0@mx.google.com> Author: Nick Desaulniers Date: 2021-05-17T11:05:31-07:00 New Revision: de579bae6eabd02b815e549776b8c680957a0769 URL: https://github.com/llvm/llvm-project/commit/de579bae6eabd02b815e549776b8c680957a0769 DIFF: https://github.com/llvm/llvm-project/commit/de579bae6eabd02b815e549776b8c680957a0769.diff LOG: [LowerConstantIntrinsics] reuse isManifestLogic from ConstantFolding GlobalVariables are Constants, yet should not unconditionally be considered true for __builtin_constant_p. Via the LangRef https://llvm.org/docs/LangRef.html#llvm-is-constant-intrinsic: This intrinsic generates no code. If its argument is known to be a manifest compile-time constant value, then the intrinsic will be converted to a constant true value. Otherwise, it will be converted to a constant false value. In particular, note that if the argument is a constant expression which refers to a global (the address of which _is_ a constant, but not manifest during the compile), then the intrinsic evaluates to false. Move isManifestConstant from ConstantFolding to be a method of Constant so that we can reuse the same logic in LowerConstantIntrinsics. pr/41459 Reviewed By: rsmith, george.burgess.iv Differential Revision: https://reviews.llvm.org/D102367 (cherry picked from commit 8c72749bd92d35397e93908bc5a504d4cbcef1cb) Added: Modified: llvm/include/llvm/IR/Constant.h llvm/lib/Analysis/ConstantFolding.cpp llvm/lib/IR/Constants.cpp llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll Removed: ################################################################################ diff --git a/llvm/include/llvm/IR/Constant.h b/llvm/include/llvm/IR/Constant.h index 0190aca27b724..71692c7460155 100644 --- a/llvm/include/llvm/IR/Constant.h +++ b/llvm/include/llvm/IR/Constant.h @@ -214,6 +214,10 @@ class Constant : public User { /// both must either be scalars or vectors with the same element count. If no /// changes are made, the constant C is returned. static Constant *mergeUndefsWith(Constant *C, Constant *Other); + + /// Return true if a constant is ConstantData or a ConstantAggregate or + /// ConstantExpr that contain only ConstantData. + bool isManifestConstant() const; }; } // end namespace llvm diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index f73890d548f09..cc1ce4c65821f 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1808,19 +1808,6 @@ double getValueAsDouble(ConstantFP *Op) { return APF.convertToDouble(); } -static bool isManifestConstant(const Constant *c) { - if (isa(c)) { - return true; - } else if (isa(c) || isa(c)) { - for (const Value *subc : c->operand_values()) { - if (!isManifestConstant(cast(subc))) - return false; - } - return true; - } - return false; -} - static bool getConstIntOrUndef(Value *Op, const APInt *&C) { if (auto *CI = dyn_cast(Op)) { C = &CI->getValue(); @@ -1845,7 +1832,7 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, // We know we have a "Constant" argument. But we want to only // return true for manifest constants, not those that depend on // constants with unknowable values, e.g. GlobalValue or BlockAddress. - if (isManifestConstant(Operands[0])) + if (Operands[0]->isManifestConstant()) return ConstantInt::getTrue(Ty->getContext()); return nullptr; } diff --git a/llvm/lib/IR/Constants.cpp b/llvm/lib/IR/Constants.cpp index 6fd205c654a8a..9f05917cf7cc8 100644 --- a/llvm/lib/IR/Constants.cpp +++ b/llvm/lib/IR/Constants.cpp @@ -803,6 +803,18 @@ Constant *Constant::mergeUndefsWith(Constant *C, Constant *Other) { return C; } +bool Constant::isManifestConstant() const { + if (isa(this)) + return true; + if (isa(this) || isa(this)) { + for (const Value *Op : operand_values()) + if (!cast(Op)->isManifestConstant()) + return false; + return true; + } + return false; +} + //===----------------------------------------------------------------------===// // ConstantInt //===----------------------------------------------------------------------===// diff --git a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp index bfe8db83b0271..bb30c48127a0f 100644 --- a/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp +++ b/llvm/lib/Transforms/Scalar/LowerConstantIntrinsics.cpp @@ -43,10 +43,10 @@ STATISTIC(ObjectSizeIntrinsicsHandled, "Number of 'objectsize' intrinsic calls handled"); static Value *lowerIsConstantIntrinsic(IntrinsicInst *II) { - Value *Op = II->getOperand(0); - - return isa(Op) ? ConstantInt::getTrue(II->getType()) - : ConstantInt::getFalse(II->getType()); + if (auto *C = dyn_cast(II->getOperand(0))) + if (C->isManifestConstant()) + return ConstantInt::getTrue(II->getType()); + return ConstantInt::getFalse(II->getType()); } static bool replaceConditionalBranchesOnConstant(Instruction *II, diff --git a/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll b/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll index b2c98d2049cd3..e19dce1b55433 100644 --- a/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll +++ b/llvm/test/Transforms/LowerConstantIntrinsics/constant-intrinsics.ll @@ -112,3 +112,11 @@ define i1 @test_various_types(i256 %int, float %float, <2 x i64> %vec, {i32, i32 ret i1 %res6 } + + at real_mode_blob_end = external dso_local global [0 x i8], align 1 +define i1 @global_array() { +; CHECK-LABEL: @global_array( +; CHECK-NEXT: ret i1 false + %1 = call i1 @llvm.is.constant.i64(i64 ptrtoint ([0 x i8]* @real_mode_blob_end to i64)) + ret i1 %1 +} From llvm-branch-commits at lists.llvm.org Wed May 19 20:02:38 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Wed, 19 May 2021 20:02:38 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 4973ce5 - ~(C + X) --> ~C - X (PR50308) Message-ID: <60a5d14e.1c69fb81.4536c.39b9@mx.google.com> Author: Roman Lebedev Date: 2021-05-19T20:01:56-07:00 New Revision: 4973ce53ca8abfc14233a3d8b3045673e0e8543c URL: https://github.com/llvm/llvm-project/commit/4973ce53ca8abfc14233a3d8b3045673e0e8543c DIFF: https://github.com/llvm/llvm-project/commit/4973ce53ca8abfc14233a3d8b3045673e0e8543c.diff LOG: ~(C + X) --> ~C - X (PR50308) We can not rely on (C+X)-->(X+C) already happening, because we might not have visited that `add` yet. The added testcase would get stuck in an endless combine loop. (cherry-picked from 554b1bced325) Added: Modified: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp llvm/test/Transforms/InstCombine/not-add.ll Removed: ################################################################################ diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 68c4156af2c42..85a7abe211b3c 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -3221,11 +3221,6 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { } } - // ~(X - Y) --> ~X + Y - if (match(NotVal, m_Sub(m_Value(X), m_Value(Y)))) - if (isa(X) || NotVal->hasOneUse()) - return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y); - // ~(~X >>s Y) --> (X >>s Y) if (match(NotVal, m_AShr(m_Not(m_Value(X)), m_Value(Y)))) return BinaryOperator::CreateAShr(X, Y); @@ -3256,9 +3251,15 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { return BinaryOperator::CreateAShr(ConstantExpr::getNot(C), Y); } - // ~(X + C) --> -(C + 1) - X - if (match(Op0, m_Add(m_Value(X), m_Constant(C)))) - return BinaryOperator::CreateSub(ConstantExpr::getNeg(AddOne(C)), X); + // ~(X + C) --> ~C - X + if (match(NotVal, m_c_Add(m_Value(X), m_ImmConstant(C)))) + return BinaryOperator::CreateSub(ConstantExpr::getNot(C), X); + + // ~(X - Y) --> ~X + Y + // FIXME: is it really beneficial to sink the `not` here? + if (match(NotVal, m_Sub(m_Value(X), m_Value(Y)))) + if (isa(X) || NotVal->hasOneUse()) + return BinaryOperator::CreateAdd(Builder.CreateNot(X), Y); // ~(~X + Y) --> X - Y if (match(NotVal, m_c_Add(m_Not(m_Value(X)), m_Value(Y)))) diff --git a/llvm/test/Transforms/InstCombine/not-add.ll b/llvm/test/Transforms/InstCombine/not-add.ll index 6891fdd5fcc54..d372e7603724b 100644 --- a/llvm/test/Transforms/InstCombine/not-add.ll +++ b/llvm/test/Transforms/InstCombine/not-add.ll @@ -137,3 +137,31 @@ define <4 x i32> @vector_test_undef_nsw_nuw(<4 x i32> %x, <4 x i32> %y) { %nota = xor <4 x i32> %a, ret <4 x i32> %nota } + +define i32 @pr50308(i1 %c1, i32 %v1, i32 %v2, i32 %v3) { +; CHECK-LABEL: @pr50308( +; CHECK-NEXT: entry: +; CHECK-NEXT: br i1 [[C1:%.*]], label [[COND_TRUE:%.*]], label [[COND_END:%.*]] +; CHECK: cond.true: +; CHECK-NEXT: [[ADD_NOT:%.*]] = sub i32 -2, [[V1:%.*]] +; CHECK-NEXT: [[ADD1_NEG:%.*]] = xor i32 [[ADD_NOT]], [[V2:%.*]] +; CHECK-NEXT: br label [[COND_END]] +; CHECK: cond.end: +; CHECK-NEXT: [[COND_NEG:%.*]] = phi i32 [ [[ADD1_NEG]], [[COND_TRUE]] ], [ 0, [[ENTRY:%.*]] ] +; CHECK-NEXT: [[SUB:%.*]] = add i32 [[COND_NEG]], [[V3:%.*]] +; CHECK-NEXT: ret i32 [[SUB]] +; +entry: + br i1 %c1, label %cond.true, label %cond.end + +cond.true: + %add = add nsw i32 1, %v1 + %xor = xor i32 %add, %v2 + %add1 = add nsw i32 1, %xor + br label %cond.end + +cond.end: + %cond = phi i32 [ %add1, %cond.true ], [ 0, %entry ] + %sub = sub nsw i32 %v3, %cond + ret i32 %sub +} From llvm-branch-commits at lists.llvm.org Sat May 22 06:57:47 2021 From: llvm-branch-commits at lists.llvm.org (Sam Clegg via llvm-branch-commits) Date: Sat, 22 May 2021 06:57:47 -0700 (PDT) Subject: [llvm-branch-commits] [compiler-rt] 697a0d1 - Update libraries from emscripten repo Message-ID: <60a90ddb.1c69fb81.8b4d0.62e3@mx.google.com> Author: Sam Clegg Date: 2021-05-22T06:39:33-07:00 New Revision: 697a0d1925cf37442b444d6b3eee6fe047d7e5bc URL: https://github.com/llvm/llvm-project/commit/697a0d1925cf37442b444d6b3eee6fe047d7e5bc DIFF: https://github.com/llvm/llvm-project/commit/697a0d1925cf37442b444d6b3eee6fe047d7e5bc.diff LOG: Update libraries from emscripten repo These changes are from emscripten as of 3ad991a6cc3c085ac325be. Added: Modified: compiler-rt/include/sanitizer/tsan_interface_atomic.h compiler-rt/lib/asan/asan_errors.cpp compiler-rt/lib/asan/asan_flags.cpp compiler-rt/lib/asan/asan_interceptors.cpp compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp compiler-rt/lib/asan/asan_malloc_linux.cpp compiler-rt/lib/asan/asan_mapping.h compiler-rt/lib/asan/asan_poisoning.cpp compiler-rt/lib/asan/asan_poisoning.h compiler-rt/lib/asan/asan_posix.cpp compiler-rt/lib/asan/asan_rtl.cpp compiler-rt/lib/asan/asan_shadow_setup.cpp compiler-rt/lib/asan/asan_thread.cpp compiler-rt/lib/builtins/powitf2.c compiler-rt/lib/interception/interception.h compiler-rt/lib/interception/interception_linux.h compiler-rt/lib/lsan/lsan.cpp compiler-rt/lib/lsan/lsan_allocator.cpp compiler-rt/lib/lsan/lsan_allocator.h compiler-rt/lib/lsan/lsan_common.cpp compiler-rt/lib/lsan/lsan_common.h compiler-rt/lib/lsan/lsan_common_linux.cpp compiler-rt/lib/lsan/lsan_interceptors.cpp compiler-rt/lib/lsan/lsan_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_linux.h compiler-rt/lib/sanitizer_common/sanitizer_platform.h compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc compiler-rt/lib/ubsan/ubsan_checks.inc compiler-rt/lib/ubsan/ubsan_diag.cpp compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp compiler-rt/lib/ubsan/ubsan_flags.cpp compiler-rt/lib/ubsan/ubsan_handlers.cpp compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp compiler-rt/lib/ubsan/ubsan_init.cpp compiler-rt/lib/ubsan/ubsan_init_standalone.cpp compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp compiler-rt/lib/ubsan/ubsan_monitor.cpp compiler-rt/lib/ubsan/ubsan_platform.h compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp compiler-rt/lib/ubsan/ubsan_type_hash.cpp compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp compiler-rt/lib/ubsan/ubsan_value.cpp compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp libcxx/include/__config libcxx/include/__sso_allocator libcxx/include/codecvt libcxx/include/ios libcxx/include/memory libcxx/include/regex libcxx/include/typeinfo libcxx/src/include/config_elast.h libcxx/src/ios.cpp libcxx/src/iostream.cpp libcxx/src/new.cpp libcxx/src/regex.cpp libcxxabi/include/cxxabi.h libcxxabi/src/abort_message.cpp libcxxabi/src/cxa_default_handlers.cpp libcxxabi/src/cxa_exception.cpp libcxxabi/src/cxa_exception.h libcxxabi/src/cxa_handlers.cpp libcxxabi/src/cxa_personality.cpp libcxxabi/src/private_typeinfo.cpp libcxxabi/src/stdlib_new_delete.cpp Removed: ################################################################################ diff --git a/compiler-rt/include/sanitizer/tsan_interface_atomic.h b/compiler-rt/include/sanitizer/tsan_interface_atomic.h index 8052bc1d56b38..5e41e2256c300 100644 --- a/compiler-rt/include/sanitizer/tsan_interface_atomic.h +++ b/compiler-rt/include/sanitizer/tsan_interface_atomic.h @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128; #endif // Part of ABI, do not change. -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic typedef enum { __tsan_memory_order_relaxed, __tsan_memory_order_consume, diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp index 541c6e0353b57..e1c953b141643 100644 --- a/compiler-rt/lib/asan/asan_errors.cpp +++ b/compiler-rt/lib/asan/asan_errors.cpp @@ -480,6 +480,17 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr); if (far_from_bounds) scariness.Scare(10, "far-from-bounds"); } +#if SANITIZER_EMSCRIPTEN + // If address is in the first page (64 KB), then it is likely that the + // access is a result of a null pointer dereference. + else if (addr < 65536) { + bug_descr = "null-pointer-dereference"; + scariness.Scare(25, bug_descr); + } else if (AddrIsInShadow(addr)) { + bug_descr = "shadow-access"; + scariness.Scare(25, bug_descr); + } +#endif } } diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index c5c70eaed737f..a09535f8269e0 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -22,6 +22,12 @@ #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + + namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). @@ -58,7 +64,11 @@ void InitializeFlags() { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using LSan. + // You can't run external symbolizer executables anyway. cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); +#endif cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; cf.exitcode = 1; @@ -119,6 +129,26 @@ void InitializeFlags() { lsan_parser.ParseString(lsan_default_options); #endif +#if SANITIZER_EMSCRIPTEN + char *options; + // Override from Emscripten Module. +#define MAKE_OPTION_LOAD(parser, name) \ + options = (char*) EM_ASM_INT({ \ + return withBuiltinMalloc(function () { \ + return allocateUTF8(Module[name] || 0); \ + }); \ + }); \ + parser.ParseString(options); \ + emscripten_builtin_free(options); + + MAKE_OPTION_LOAD(asan_parser, 'ASAN_OPTIONS'); +#if CAN_SANITIZE_LEAKS + MAKE_OPTION_LOAD(lsan_parser, 'LSAN_OPTIONS'); +#endif +#if CAN_SANITIZE_UB + MAKE_OPTION_LOAD(ubsan_parser, 'UBSAN_OPTIONS'); +#endif +#else // Override from command line. asan_parser.ParseStringFromEnv("ASAN_OPTIONS"); #if CAN_SANITIZE_LEAKS @@ -127,12 +157,18 @@ void InitializeFlags() { #if CAN_SANITIZE_UB ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); #endif +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN + if (common_flags()->help) { // TODO(samsonov): print all of the flags (ASan, LSan, common). asan_parser.PrintFlagDescriptions(); diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index b19cf25c7cd00..9002c7fe4dbd9 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -23,10 +23,10 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia and RTEMS. -// Only the functions in asan_interceptors_memintrinsics.cpp are +// There is no general interception at all on Fuchsia, RTEMS and Emscripten. +// Only the functions in asan_interceptors_memintrinsics.cc are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" @@ -719,4 +719,4 @@ void InitializeAsanInterceptors() { } // namespace __asan -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp index ccdd5159042cf..7280523b86b70 100644 --- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp +++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp @@ -30,7 +30,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -#if SANITIZER_FUCHSIA || SANITIZER_RTEMS +#if SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN // Fuchsia and RTEMS don't use sanitizer_common_interceptors.inc, but // the only things there it wants are these three. Just define them @@ -40,4 +40,4 @@ extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]]; extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; -#endif // SANITIZER_FUCHSIA || SANITIZER_RTEMS +#endif // SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp index faa8968a5d009..20719cd51f959 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -15,7 +15,8 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ - SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS + SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS || \ + SANITIZER_EMSCRIPTEN #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_errno.h" diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index 41fb49ee46d46..67c5448729a3d 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -268,8 +268,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. #if SANITIZER_MYRIAD2 #include "asan_mapping_myriad.h" -#elif defined(__sparc__) && SANITIZER_WORDSIZE == 64 -#include "asan_mapping_sparc64.h" +#elif SANITIZER_EMSCRIPTEN +#include "asan_mapping_emscripten.h" #else #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp index f3fbe684e2cbc..a3152eab85409 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -65,7 +65,9 @@ struct ShadowSegmentEndpoint { void FlushUnneededASanShadowMemory(uptr p, uptr size) { // Since asan's mapping is compacting, the shadow chunk may be // not page-aligned, so we only flush the page-aligned portion. +#if !SANITIZER_EMSCRIPTEN ReleaseMemoryPagesToOS(MemToShadow(p), MemToShadow(p + size)); +#endif } void AsanPoisonOrUnpoisonIntraObjectRedzone(uptr ptr, uptr size, bool poison) { @@ -187,6 +189,15 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0; if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0; } else { +#if SANITIZER_EMSCRIPTEN + // XXX Emscripten hack XXX + // Null pointer handling, since Emscripten does not crash on null pointer, + // ASan must catch null pointer dereference by itself. + // Unfortunately, this function returns 0 to mean the region is not + // poisoned, so we must return 1 instead if we receive a region + // starting at 0. + if (!beg) return 1; +#endif if (!AddrIsInMem(beg)) return beg; if (!AddrIsInMem(end)) return end; } diff --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h index 62dd9bd0edd32..0c8c283986a62 100644 --- a/compiler-rt/lib/asan/asan_poisoning.h +++ b/compiler-rt/lib/asan/asan_poisoning.h @@ -54,6 +54,10 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, // RTEMS doesn't have have pages, let alone a fast way to zero // them, so default to memset. SANITIZER_RTEMS == 1 || + // Emscripten doesn't have a nice way to zero whole pages. + // The bulk memory proposal will allow memset to be optimized, but + // even then, we still must use memset. + SANITIZER_EMSCRIPTEN == 1 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp index 920d216624a3f..85ebd181ebf2f 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -83,7 +83,7 @@ void PlatformTSDDtor(void *tsd) { atomic_signal_fence(memory_order_seq_cst); AsanThread::TSDDtor(tsd); } -#else +#elif !SANITIZER_EMSCRIPTEN static pthread_key_t tsd_key; static bool tsd_key_inited = false; void AsanTSDInit(void (*destructor)(void *tsd)) { diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index 594d7752eea62..5665654e942fb 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -50,6 +50,7 @@ static void AsanDie() { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); } +#if !SANITIZER_EMSCRIPTEN if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); @@ -59,6 +60,7 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } +#endif } static void AsanCheckFailed(const char *file, int line, const char *cond, @@ -314,7 +316,7 @@ static void asan_atexit() { } static void InitializeHighMemEnd() { -#if !SANITIZER_MYRIAD2 +#if !SANITIZER_MYRIAD2 && !SANITIZER_EMSCRIPTEN #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxUserVirtualAddress(); // Increase kHighMemEnd to make sure it's properly @@ -463,7 +465,9 @@ static void AsanInitInternal() { InitializeShadowMemory(); AsanTSDInit(PlatformTSDDtor); +#if !SANITIZER_EMSCRIPTEN InstallDeadlySignalHandlers(AsanOnDeadlySignal); +#endif AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); diff --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp index 17324932a86f9..e17da6a3696a9 100644 --- a/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -13,9 +13,9 @@ #include "sanitizer_common/sanitizer_platform.h" -// asan_fuchsia.cpp and asan_rtems.cpp have their own +// asan_fuchsia.cc, asan_rtems.cc and asan_emscripten.cc have their own // InitializeShadowMemory implementation. -#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN #include "asan_internal.h" #include "asan_mapping.h" diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 6734d9a1668c7..b573b7f2817b1 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -101,7 +101,9 @@ void AsanThread::Destroy() { VReport(1, "T%d exited\n", tid); malloc_storage().CommitBack(); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); +#endif asanThreadRegistry().FinishThread(tid); FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because @@ -249,7 +251,9 @@ thread_return_t AsanThread::ThreadStart( if (signal_thread_is_registered) atomic_store(signal_thread_is_registered, 1, memory_order_release); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif if (!start_routine_) { // start_routine_ == 0 if we're on the main thread or on one of the diff --git a/compiler-rt/lib/builtins/powitf2.c b/compiler-rt/lib/builtins/powitf2.c index fcbdb4c2ee2a6..443da04b29b19 100644 --- a/compiler-rt/lib/builtins/powitf2.c +++ b/compiler-rt/lib/builtins/powitf2.c @@ -12,7 +12,7 @@ #include "int_lib.h" -#if _ARCH_PPC +#if defined _ARCH_PPC || defined __wasm__ // Returns: a ^ b diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h index d27a8ccf92a8e..aa2986b1c92fa 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -18,7 +18,8 @@ #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ !SANITIZER_NETBSD && !SANITIZER_OPENBSD && !SANITIZER_WINDOWS && \ - !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS + !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS && \ + !SANITIZER_EMSCRIPTEN # error "Interception doesn't work on this operating system." #endif @@ -130,7 +131,7 @@ const interpose_substitution substitution_##func_name[] \ extern "C" ret_type func(__VA_ARGS__); # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); -#elif SANITIZER_RTEMS +#elif SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN # define WRAP(x) x # define WRAPPER_NAME(x) #x # define INTERCEPTOR_ATTRIBUTE @@ -162,6 +163,13 @@ const interpose_substitution substitution_##func_name[] \ # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define REAL(x) __unsanitized_##x # define DECLARE_REAL(ret_type, func, ...) +#elif SANITIZER_EMSCRIPTEN +// Sanitizer runtimes on Emscripten just define functions directly to override +// the libc functions. If the real version is really needed, they can be defined +// with the emscripten_builtin_ prefix. +# define REAL(x) emscripten_builtin_##x +# define DECLARE_REAL(ret_type, func, ...) \ + extern "C" ret_type REAL(func)(__VA_ARGS__); #elif SANITIZER_RTEMS # define REAL(x) __real_ ## x # define DECLARE_REAL(ret_type, func, ...) \ @@ -202,7 +210,8 @@ const interpose_substitution substitution_##func_name[] \ // macros does its job. In exceptional cases you may need to call REAL(foo) // without defining INTERCEPTOR(..., foo, ...). For example, if you override // foo with an interceptor for other function. -#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && \ + !SANITIZER_EMSCRIPTEN # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -272,16 +281,16 @@ const interpose_substitution substitution_##func_name[] \ // INTERCEPT_FUNCTION macro, only its name. namespace __interception { #if defined(_WIN64) -typedef unsigned long long uptr; +typedef unsigned long long uptr; // NOLINT #else -typedef unsigned long uptr; +typedef unsigned long uptr; // NOLINT #endif // _WIN64 } // namespace __interception #define INCLUDED_FROM_INTERCEPTION_LIB #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h index e578da0cf64ee..5a98b57d01d7b 100644 --- a/compiler-rt/lib/interception/interception_linux.h +++ b/compiler-rt/lib/interception/interception_linux.h @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_linux.h should be included from interception library only" @@ -35,8 +35,9 @@ bool InterceptFunction(const char *name, const char *ver, uptr *ptr_to_real, (::__interception::uptr) & (func), \ (::__interception::uptr) & WRAP(func)) -// Android, Solaris and OpenBSD do not have dlvsym -#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD +// Android, Solaris, OpenBSD and emscripten do not have dlvsym +#if !SANITIZER_ANDROID && !SANITIZER_SOLARIS && !SANITIZER_OPENBSD && \ + !SANITIZER_EMSCRIPTEN #define INTERCEPT_FUNCTION_VER_LINUX_OR_FREEBSD(func, symver) \ ::__interception::InterceptFunction( \ #func, symver, \ diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp index 4ce03046ffb7f..8e3f0294eea04 100644 --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -20,6 +20,11 @@ #include "lsan_common.h" #include "lsan_thread.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + bool lsan_inited; bool lsan_init_is_running; @@ -58,7 +63,11 @@ static void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using LSan. + // You can't run external symbolizers anyway. cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); +#endif cf.malloc_context_size = 30; cf.intercept_tls_get_addr = true; cf.detect_leaks = true; @@ -76,7 +85,22 @@ static void InitializeFlags() { // Override from user-specified string. const char *lsan_default_options = MaybeCallLsanDefaultOptions(); parser.ParseString(lsan_default_options); - parser.ParseStringFromEnv("LSAN_OPTIONS"); +#if SANITIZER_EMSCRIPTEN + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['LSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#else + parser.ParseString(GetEnv("LSAN_OPTIONS")); +#endif // SANITIZER_EMSCRIPTEN + +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN SetVerbosity(common_flags()->verbosity); @@ -113,7 +137,10 @@ extern "C" void __lsan_init() { InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); +#if !SANITIZER_EMSCRIPTEN + // Emscripten does not have signals InstallDeadlySignalHandlers(LsanOnDeadlySignal); +#endif u32 tid = ThreadCreate(0, 0, true); CHECK_EQ(tid, 0); ThreadStart(tid, GetTid()); diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index d86c3921395cb..845526a8771a1 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -26,7 +26,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -#if defined(__i386__) || defined(__arm__) +#if defined(__i386__) || defined(__arm__) || defined(__wasm32__) static const uptr kMaxAllowedMallocSize = 1UL << 30; #elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h index e139709976728..3df5f77bd3bcf 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.h +++ b/compiler-rt/lib/lsan/lsan_allocator.h @@ -50,15 +50,22 @@ struct ChunkMetadata { }; #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ - defined(__arm__) + defined(__arm__) || defined(__wasm32__) +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +template +using ByteMapASVT = + TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>; + template struct AP32 { static const uptr kSpaceBeg = 0; static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; static const uptr kMetadataSize = sizeof(ChunkMetadata); typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = 20; + static const uptr kRegionSizeLog = __lsan::kRegionSizeLog; using AddressSpaceView = AddressSpaceViewTy; + using ByteMap = __lsan::ByteMapASVT; typedef NoOpMapUnmapCallback MapUnmapCallback; static const uptr kFlags = 0; }; diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index 9ff9f4c5d1c97..fdd53733241b5 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -1,4 +1,4 @@ -//=-- lsan_common.cpp -----------------------------------------------------===// +//=-- lsan_common.cc ------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -25,6 +25,10 @@ #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if SANITIZER_EMSCRIPTEN +#include "lsan/lsan_allocator.h" +#endif + #if CAN_SANITIZE_LEAKS namespace __lsan { @@ -84,7 +88,7 @@ static const char kStdSuppressions[] = void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) + suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); if (&__lsan_default_suppressions) @@ -162,7 +166,16 @@ void ScanRangeForPointers(uptr begin, uptr end, uptr pp = begin; if (pp % alignment) pp = pp + alignment - pp % alignment; - for (; pp + sizeof(void *) <= end; pp += alignment) { + + // Emscripten in non-threaded mode stores thread_local variables in the + // same place as normal globals. This means allocator_cache must be skipped + // when scanning globals instead of when scanning thread-locals. +#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__) + uptr cache_begin, cache_end; + GetAllocatorCacheRange(&cache_begin, &cache_end); +#endif + + for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT void *p = *reinterpret_cast(pp); if (!CanBeAHeapPointer(reinterpret_cast(p))) continue; uptr chunk = PointsIntoChunk(p); @@ -181,6 +194,14 @@ void ScanRangeForPointers(uptr begin, uptr end, continue; } +#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__) + if (cache_begin <= pp && pp < cache_end) { + LOG_POINTERS("%p: skipping because it overlaps the cache %p-%p.\n", + pp, cache_begin, cache_end); + continue; + } +#endif + m.set_tag(tag); LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p, chunk, chunk + m.requested_size(), m.requested_size()); @@ -211,9 +232,10 @@ void ForEachExtraStackRangeCb(uptr begin, uptr end, void* arg) { ScanRangeForPointers(begin, end, frontier, "FAKE STACK", kReachable); } +#if !SANITIZER_EMSCRIPTEN // Scans thread data (stacks and TLS) for heap pointers. -static void ProcessThreads(SuspendedThreadsList const &suspended_threads, - Frontier *frontier) { +void ProcessThreads(SuspendedThreadsList const &suspended_threads, + Frontier *frontier) { InternalMmapVector registers(suspended_threads.RegisterCount()); uptr registers_begin = reinterpret_cast(registers.data()); uptr registers_end = @@ -307,6 +329,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, } } } +#endif // !SANITIZER_EMSCRIPTEN void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, uptr region_begin, uptr region_end, bool is_readable) { @@ -322,14 +345,22 @@ void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, kReachable); } +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_heap_size(); +#endif + static void ProcessRootRegion(Frontier *frontier, const RootRegion &root_region) { +#if SANITIZER_EMSCRIPTEN + ScanRootRegion(frontier, root_region, 0, emscripten_get_heap_size(), true); +#else MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { ScanRootRegion(frontier, root_region, segment.start, segment.end, segment.IsReadable()); } +#endif // SANITIZER_EMSCRIPTEN } // Scans root regions for heap pointers. @@ -433,6 +464,7 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { // On all other platforms, this simply checks to ensure that the caller pc is // valid before reporting chunks as leaked. void ProcessPC(Frontier *frontier) { +#if !SANITIZER_EMSCRIPTEN StackDepotReverseMap stack_depot_reverse_map; InvalidPCParam arg; arg.frontier = frontier; @@ -440,6 +472,7 @@ void ProcessPC(Frontier *frontier) { arg.skip_linker_allocations = flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr; ForEachChunk(MarkInvalidPCCb, &arg); +#endif } // Sets the appropriate tag on each chunk. @@ -555,7 +588,9 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, CheckForLeaksParam *param = reinterpret_cast(arg); CHECK(param); CHECK(!param->success); +#if !SANITIZER_EMSCRIPTEN ReportUnsuspendedThreads(suspended_threads); +#endif ClassifyAllChunks(suspended_threads); ForEachChunk(CollectLeaksCb, ¶m->leak_report); // Clean up for subsequent leak checks. This assumes we did not overwrite any @@ -647,8 +682,15 @@ static Suppression *GetSuppressionForAddr(uptr addr) { static Suppression *GetSuppressionForStack(u32 stack_trace_id) { StackTrace stack = StackDepotGet(stack_trace_id); for (uptr i = 0; i < stack.size; i++) { +#if SANITIZER_EMSCRIPTEN + // On Emscripten, the stack trace is the actual call site, not + // the code that would be executed after the return. + // Therefore, StackTrace::GetPreviousInstructionPc is not needed. + Suppression *s = GetSuppressionForAddr(stack.trace[i]); +#else Suppression *s = GetSuppressionForAddr( StackTrace::GetPreviousInstructionPc(stack.trace[i])); +#endif if (s) return s; } return nullptr; diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index d24abe31b71b5..6901e18829aeb 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -40,7 +40,7 @@ #elif defined(__arm__) && \ SANITIZER_LINUX && !SANITIZER_ANDROID #define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_NETBSD +#elif SANITIZER_EMSCRIPTEN #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 @@ -213,6 +213,10 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, uptr *cache_end, DTLS **dtls); void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); +// Scans thread data (stacks and TLS) for heap pointers. +void ProcessThreads(SuspendedThreadsList const &suspended_threads, + Frontier *frontier); + // If called from the main thread, updates the main thread's TID in the thread // registry. We need this to handle processes that fork() without a subsequent // exec(), which invalidates the recorded TID. To update it, we must call diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp index ea1a4a2f569d0..a9693e02edd1c 100644 --- a/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -15,7 +15,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" -#if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD) +#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX #include #include "sanitizer_common/sanitizer_common.h" diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index f642bb807bc88..b27f324bc558f 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -384,6 +384,16 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK #endif +#if SANITIZER_EMSCRIPTEN +extern "C" { + int emscripten_builtin_pthread_create(void *thread, void *attr, + void *(*callback)(void *), void *arg); + int emscripten_builtin_pthread_join(void *th, void **ret); + void *emscripten_builtin_malloc(size_t size); + void emscripten_builtin_free(void *); +} +#endif + #if SANITIZER_INTERCEPT_STRERROR INTERCEPTOR(char *, strerror, int errnum) { __lsan::ScopedInterceptorDisabler disabler; @@ -418,7 +428,11 @@ extern "C" void *__lsan_thread_start_func(void *arg) { internal_sched_yield(); SetCurrentThread(tid); ThreadStart(tid, GetTid()); +#if SANITIZER_EMSCRIPTEN + emscripten_builtin_free(p); +#else atomic_store(&p->tid, 0, memory_order_release); +#endif return callback(param); } @@ -434,10 +448,17 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, AdjustStackSize(attr); int detached = 0; pthread_attr_getdetachstate(attr, &detached); +#if SANITIZER_EMSCRIPTEN + ThreadParam *p = (ThreadParam *) emscripten_builtin_malloc(sizeof(ThreadParam)); + p->callback = callback; + p->param = param; + atomic_store(&p->tid, 0, memory_order_relaxed); +#else ThreadParam p; p.callback = callback; p.param = param; atomic_store(&p.tid, 0, memory_order_relaxed); +#endif int res; { // Ignore all allocations made by pthread_create: thread stack/TLS may be @@ -445,15 +466,23 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. ScopedInterceptorDisabler disabler; +#if SANITIZER_EMSCRIPTEN + res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, p); +#else res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); +#endif } if (res == 0) { int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, IsStateDetached(detached)); CHECK_NE(tid, 0); +#if SANITIZER_EMSCRIPTEN + atomic_store(&p->tid, tid, memory_order_release); +#else atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) internal_sched_yield(); +#endif } if (attr == &myattr) pthread_attr_destroy(&myattr); @@ -469,11 +498,21 @@ INTERCEPTOR(int, pthread_join, void *th, void **ret) { return res; } +#if !SANITIZER_EMSCRIPTEN INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); } +#endif + +#if SANITIZER_EMSCRIPTEN +namespace __lsan { +void InitializeInterceptors() {} + +} // namespace __lsan + +#else #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #include "sanitizer_common/sanitizer_signal_interceptors.inc" @@ -518,3 +557,4 @@ void InitializeInterceptors() { } } // namespace __lsan +#endif // SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/lsan/lsan_linux.cpp b/compiler-rt/lib/lsan/lsan_linux.cpp index 14a42b75d2af3..691ce42313687 100644 --- a/compiler-rt/lib/lsan/lsan_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_linux.cpp @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_NETBSD +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN #include "lsan_allocator.h" @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {} } // namespace __lsan -#endif // SANITIZER_LINUX || SANITIZER_NETBSD +#endif // SANITIZER_LINUX diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h index f388d0d364633..7f797c2c4c15c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -19,11 +19,14 @@ #ifndef SANITIZER_ERRNO_CODES_H #define SANITIZER_ERRNO_CODES_H +// XXX EMSCRIPTEN: use wasi errno codes, which is what our musl port now uses +#include + namespace __sanitizer { -#define errno_ENOMEM 12 -#define errno_EBUSY 16 -#define errno_EINVAL 22 +#define errno_ENOMEM __WASI_ERRNO_NOMEM +#define errno_EBUSY __WASI_ERRNO_BUSY +#define errno_EINVAL __WASI_ERRNO_INVAL // Those might not present or their value diff er on diff erent platforms. extern const int errno_EOWNERDEAD; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index d0ffc79b06107..4e4609c27cb66 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -182,7 +182,8 @@ typedef u64 OFF64_T; #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else -# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) +# if SANITIZER_OPENBSD || defined(__s390__) && !defined(__s390x__) || \ + SANITIZER_EMSCRIPTEN // Special case: 31-bit s390 has unsigned long as size_t. typedef unsigned long operator_new_size_type; # else diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 84453f1bd3008..dc5bbb6bc6cc6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -101,9 +101,17 @@ extern struct ps_strings *__ps_strings; #define environ _environ #endif +#if SANITIZER_EMSCRIPTEN +#include +#include +#include +#include +#include +#endif + extern char **environ; -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN // struct kernel_timeval { long tv_sec; @@ -164,7 +172,7 @@ namespace __sanitizer { // --------------- sanitizer_libc.h #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -#if !SANITIZER_S390 && !SANITIZER_OPENBSD +#if !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS @@ -177,20 +185,26 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, offset / 4096); #endif } -#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD +#endif // !SANITIZER_S390 && !SANITIZER_OPENBSD && !SANITIZER_NETBSD -#if !SANITIZER_OPENBSD +#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN uptr internal_munmap(void *addr, uptr length) { return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } +#endif +#if !SANITIZER_OPENBSD int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } #endif uptr internal_close(fd_t fd) { +#if SANITIZER_EMSCRIPTEN + return __wasi_fd_close(fd); +#else return internal_syscall(SYSCALL(close), fd); +#endif } uptr internal_open(const char *filename, int flags) { @@ -211,27 +225,50 @@ uptr internal_open(const char *filename, int flags, u32 mode) { } uptr internal_read(fd_t fd, void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_iovec_t iov = { (uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_read(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); return res; +#endif } uptr internal_write(fd_t fd, const void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_ciovec_t iov = { (const uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_write(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); return res; +#endif } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; +#if SANITIZER_EMSCRIPTEN + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, + 0, size, 0)); +#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); +#endif return res; } -#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX || SANITIZER_EMSCRIPTEN static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; @@ -419,7 +456,11 @@ uptr internal_rename(const char *oldpath, const char *newpath) { } uptr internal_sched_yield() { +#if SANITIZER_EMSCRIPTEN + return 0; +#else return internal_syscall(SYSCALL(sched_yield)); +#endif } void internal__exit(int exitcode) { @@ -431,6 +472,8 @@ void internal__exit(int exitcode) { Die(); // Unreachable. } + +#if !SANITIZER_EMSCRIPTEN unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; ts.tv_sec = seconds; @@ -445,6 +488,7 @@ uptr internal_execve(const char *filename, char *const argv[], return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } +#endif // !SANITIZER_EMSCRIPTEN #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD // ----------------- sanitizer_common.h @@ -472,11 +516,14 @@ tid_t GetTid() { return internal_syscall(SYSCALL(getthrid)); #elif SANITIZER_SOLARIS return thr_self(); +#elif SANITIZER_EMSCRIPTEN + return (tid_t) pthread_self(); #else return internal_syscall(SYSCALL(gettid)); #endif } +#if !SANITIZER_EMSCRIPTEN int TgKill(pid_t pid, tid_t tid, int sig) { #if SANITIZER_LINUX return internal_syscall(SYSCALL(tgkill), pid, tid, sig); @@ -491,8 +538,9 @@ int TgKill(pid_t pid, tid_t tid, int sig) { #endif } #endif +#endif -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN u64 NanoTime() { #if SANITIZER_FREEBSD || SANITIZER_OPENBSD timeval tv; @@ -509,12 +557,20 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { } #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if SANITIZER_EMSCRIPTEN +int __clock_gettime(__sanitizer_clockid_t clk_id, void *tp); + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + return __clock_gettime(clk_id, tp); +} +#endif + // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on some others) and does not use libc. This function // should be called first inside __asan_init. const char *GetEnv(const char *name) { #if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_OPENBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -584,7 +640,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } #endif -#if !SANITIZER_OPENBSD +#if !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN static void GetArgsAndEnv(char ***argv, char ***envp) { #if SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -631,7 +687,7 @@ char **GetEnviron() { return envp; } -#endif // !SANITIZER_OPENBSD +#endif // !SANITIZER_OPENBSD && !SANITIZER_EMSCRIPTEN #if !SANITIZER_SOLARIS enum MutexState { @@ -654,6 +710,8 @@ void BlockingMutex::Lock() { _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); #elif SANITIZER_NETBSD sched_yield(); /* No userspace futex-like synchronization */ +#elif SANITIZER_EMSCRIPTEN + emscripten_futex_wait(m, MtxSleeping, INFINITY); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, 0, 0, 0); @@ -670,6 +728,8 @@ void BlockingMutex::Unlock() { _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); #elif SANITIZER_NETBSD /* No userspace futex-like synchronization */ +#elif SANITIZER_EMSCRIPTEN + emscripten_futex_wake(m, 1); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); #endif @@ -716,11 +776,13 @@ struct linux_dirent { #endif #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_EMSCRIPTEN // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); } +#endif uptr internal_waitpid(int pid, int *status, int options) { return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, @@ -746,7 +808,12 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { +#if SANITIZER_EMSCRIPTEN + __wasi_filesize_t result; + return __wasi_syscall_ret(__wasi_fd_seek(fd, offset, whence, &result)) ? -1 : result; +#else return internal_syscall(SYSCALL(lseek), fd, offset, whence); +#endif } #if SANITIZER_LINUX @@ -755,12 +822,17 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { } #endif +#if !SANITIZER_EMSCRIPTEN uptr internal_sigaltstack(const void *ss, void *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } +#endif int internal_fork() { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_EMSCRIPTEN + Report("fork not supported on emscripten\n"); + return -1; +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(clone), SIGCHLD, 0); #else return internal_syscall(SYSCALL(fork)); @@ -844,6 +916,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { #if SANITIZER_FREEBSD || SANITIZER_OPENBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); +#elif SANITIZER_EMSCRIPTEN + return NULL; #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; @@ -894,7 +968,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { #endif #endif // !SANITIZER_SOLARIS -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN // ThreadLister implementation. ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { char task_directory_path[80]; @@ -1073,20 +1147,24 @@ uptr GetPageSize() { int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); CHECK_EQ(rv, 0); return (uptr)pz; -#elif SANITIZER_USE_GETAUXVAL - return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif } #endif // !SANITIZER_ANDROID +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len); +#endif + #if !SANITIZER_OPENBSD uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { #if SANITIZER_SOLARIS const char *default_module_name = getexecname(); CHECK_NE(default_module_name, NULL); return internal_snprintf(buf, buf_len, "%s", default_module_name); +#elif SANITIZER_EMSCRIPTEN + return emscripten_get_module_name(buf, buf_len); #else #if SANITIZER_FREEBSD || SANITIZER_NETBSD #if SANITIZER_FREEBSD @@ -1975,11 +2053,9 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif *bp = ucontext->uc_mcontext.gregs[11]; *sp = ucontext->uc_mcontext.gregs[15]; -#elif defined(__riscv) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.__gregs[REG_PC]; - *bp = ucontext->uc_mcontext.__gregs[REG_S0]; - *sp = ucontext->uc_mcontext.__gregs[REG_SP]; +#elif SANITIZER_EMSCRIPTEN + Report("GetPcSpBp not implemented on emscripten"); + Abort(); #else # error "Unsupported arch" #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index c28347ad963a7..d73b539c3cdb8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_OPENBSD || SANITIZER_SOLARIS + SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_freebsd.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index c68bfa2587558..6d098e3a78269 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -15,7 +15,7 @@ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__OpenBSD__) && !defined(__APPLE__) && !defined(_WIN32) && \ !defined(__Fuchsia__) && !defined(__rtems__) && \ - !(defined(__sun__) && defined(__svr4__)) + !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__) # error "This operating system is not supported" #endif @@ -110,9 +110,16 @@ # define SANITIZER_RTEMS 0 #endif +#if defined(__EMSCRIPTEN__) +# define SANITIZER_EMSCRIPTEN 1 +#else +# define SANITIZER_EMSCRIPTEN 0 +#endif + #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS) + SANITIZER_NETBSD || SANITIZER_OPENBSD || SANITIZER_SOLARIS || \ + SANITIZER_EMSCRIPTEN) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 4cc69af1241da..658259830f3d1 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -138,12 +138,24 @@ # define SI_POSIX_NOT_MAC 0 #endif +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN +# define SI_POSIX_NOT_EMSCRIPTEN 1 +#else +# define SI_POSIX_NOT_EMSCRIPTEN 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_FREEBSD # define SI_LINUX_NOT_FREEBSD 1 # else # define SI_LINUX_NOT_FREEBSD 0 #endif +#if SANITIZER_EMSCRIPTEN +# define SI_EMSCRIPTEN 1 +#else +# define SI_EMSCRIPTEN 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA @@ -271,7 +283,7 @@ #define SANITIZER_INTERCEPT_RECVMMSG SI_LINUX #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX -#define SANITIZER_INTERCEPT_IOCTL SI_POSIX +#define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX @@ -314,7 +326,7 @@ SI_SOLARIS) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_STRERROR SI_POSIX +#define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index aa845df4dde48..c44449aee09a6 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -13,7 +13,7 @@ #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as // exported from libc) returns, and not the user-facing "dirent", which @@ -57,7 +57,7 @@ #include #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN #include #include #include @@ -200,7 +200,7 @@ namespace __sanitizer { unsigned struct_statfs64_sz = sizeof(struct statfs64); #endif // SANITIZER_MAC && !SANITIZER_IOS -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN unsigned struct_fstab_sz = sizeof(struct fstab); unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); @@ -389,7 +389,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); // ioctl arguments unsigned struct_ifreq_sz = sizeof(struct ifreq); unsigned struct_termios_sz = sizeof(struct termios); + +#if !SANITIZER_EMSCRIPTEN unsigned struct_winsize_sz = sizeof(struct winsize); +#endif #if SANITIZER_LINUX unsigned struct_arpreq_sz = sizeof(struct arpreq); @@ -471,15 +474,18 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); #endif // (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID -#if !SANITIZER_ANDROID && !SANITIZER_MAC +#if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); #endif +#if !SANITIZER_EMSCRIPTEN const unsigned long __sanitizer_bufsiz = BUFSIZ; +#endif const unsigned IOCTL_NOT_PRESENT = 0; +#if !SANITIZER_EMSCRIPTEN unsigned IOCTL_FIOASYNC = FIOASYNC; unsigned IOCTL_FIOCLEX = FIOCLEX; unsigned IOCTL_FIOGETOWN = FIOGETOWN; @@ -528,6 +534,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; #endif +#endif #if SANITIZER_LINUX unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); @@ -1018,6 +1025,7 @@ CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); #endif COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +#if !SANITIZER_EMSCRIPTEN CHECK_SIZE_AND_OFFSET(dirent, d_ino); #if SANITIZER_MAC CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); @@ -1027,6 +1035,7 @@ CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); CHECK_SIZE_AND_OFFSET(dirent, d_off); #endif CHECK_SIZE_AND_OFFSET(dirent, d_reclen); +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); @@ -1046,6 +1055,7 @@ CHECK_SIZE_AND_OFFSET(pollfd, revents); CHECK_TYPE_SIZE(nfds_t); +#if !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(sigset_t); COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); @@ -1060,6 +1070,7 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); #if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); #endif +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX CHECK_TYPE_SIZE(__sysctl_args); @@ -1113,7 +1124,9 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); #endif +#if !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ether_addr); +#endif #if (SANITIZER_LINUX || SANITIZER_FREEBSD) && !SANITIZER_ANDROID CHECK_TYPE_SIZE(ipc_perm); @@ -1151,7 +1164,7 @@ CHECK_TYPE_SIZE(clock_t); CHECK_TYPE_SIZE(clockid_t); #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); @@ -1181,7 +1194,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(timeb); CHECK_SIZE_AND_OFFSET(timeb, time); CHECK_SIZE_AND_OFFSET(timeb, millitm); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 5337b26b29b8b..b0896f86720b3 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -14,7 +14,7 @@ #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" @@ -503,7 +503,7 @@ typedef long long __sanitizer_clock_t; typedef long __sanitizer_clock_t; #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN typedef int __sanitizer_clockid_t; #endif @@ -556,6 +556,8 @@ struct __sanitizer_sigset_t { // The size is determined by looking at sizeof of real sigset_t on linux. uptr val[128 / sizeof(uptr)]; }; +#elif SANITIZER_EMSCRIPTEN +typedef unsigned long __sanitizer_sigset_t; #endif struct __sanitizer_siginfo { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index d890a3a317737..fea3483506f26 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -220,6 +220,16 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1, return (end1 < start2) || (end2 < start1); } +#if SANITIZER_EMSCRIPTEN +bool MemoryRangeIsAvailable(uptr /*range_start*/, uptr /*range_end*/) { + // TODO: actually implement this. + return true; +} + +void DumpProcessMap() { + Report("Cannot dump memory map on emscripten"); +} +#else // FIXME: this is thread-unsafe, but should not cause problems most of the time. // When the shadow is mapped only a single thread usually exists (plus maybe // several worker threads on Mac, which aren't expected to map big chunks of @@ -252,6 +262,7 @@ void DumpProcessMap() { Report("End of process memory map.\n"); UnmapOrDie(filename, kBufSize); } +#endif const char *GetPwd() { return GetEnv("PWD"); @@ -272,6 +283,10 @@ void ReportFile::Write(const char *buffer, uptr length) { } bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { +#if SANITIZER_EMSCRIPTEN + // Code is not mapped in memory in Emscripten, so this operation is meaningless + // and thus always fails. +#else MemoryMappingLayout proc_maps(/*cache_enabled*/false); InternalScopedString buff(kMaxPathLength); MemoryMappedSegment segment(buff.data(), kMaxPathLength); @@ -283,6 +298,7 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { return true; } } +#endif return false; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index 304b3a01a08b6..3c0c91e7cac31 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -215,7 +215,9 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // Set the alternate signal stack for the main thread. // This will cause SetAlternateSignalStack to be called twice, but the stack // will be actually set only once. +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif MaybeInstallSigaction(SIGSEGV, handler); MaybeInstallSigaction(SIGBUS, handler); MaybeInstallSigaction(SIGABRT, handler); @@ -275,6 +277,11 @@ bool SignalContext::IsStackOverflow() const { #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { +#if SANITIZER_EMSCRIPTEN + // Avoid pulling in __sys_pipe for the trick below, which doesn't work on + // WebAssembly anyways because there are no memory protections. + return true; +#else uptr page_size = GetPageSizeCached(); // Checking too large memory ranges is slow. CHECK_LT(size, page_size * 10); @@ -294,6 +301,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { internal_close(sock_pair[0]); internal_close(sock_pair[1]); return result; +#endif // SANITIZER_EMSCRIPTEN } void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -301,7 +309,9 @@ void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // to read the file mappings from /proc/self/maps. Luckily, neither the // process will be able to load additional libraries, so it's fine to use the // cached mappings. +#ifndef SANITIZER_EMSCRIPTEN MemoryMappingLayout::CacheMemoryMappings(); +#endif } static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp index ef14fb704eed3..7029da649eb86 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -26,9 +26,11 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) { #endif } +#if !defined(__EMSCRIPTEN__) uptr StackTrace::GetCurrentPc() { return GET_CALLER_PC(); } +#endif void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { size = cnt + !!extra_top_pc; @@ -39,8 +41,8 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { top_frame_bp = 0; } -// Sparc implemention is in its own file. -#if !defined(__sparc__) +// Sparc and Emscripten implementions are in their own files. +#if !defined(__sparc__) && !defined(__EMSCRIPTEN__) // In GCC on ARM bp points to saved lr, not fp, so we should check the next // cell in stack to be a saved frame pointer. GetCanonicFrame returns the diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index f1f29e9f32ee8..ab71cb6a86a0b 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -33,7 +33,7 @@ static const u32 kStackTraceMax = 256; // Fast unwind is the only option on Mac for now; we will need to // revisit this macro when slow unwind works on Mac, see // https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS +#if SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN # define SANITIZER_CAN_SLOW_UNWIND 0 #else # define SANITIZER_CAN_SLOW_UNWIND 1 @@ -65,6 +65,9 @@ struct StackTrace { return request_fast_unwind; } +#if SANITIZER_EMSCRIPTEN + static bool snapshot_stack; +#endif static uptr GetCurrentPc(); static inline uptr GetPreviousInstructionPc(uptr pc); static uptr GetNextInstructionPc(uptr pc); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp index 4ef305cf17991..2559349319b34 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -28,9 +28,15 @@ void StackTrace::Print() const { int dedup_frames = common_flags()->dedup_token_length; uptr frame_num = 0; for (uptr i = 0; i < size && trace[i]; i++) { +#if !SANITIZER_EMSCRIPTEN // PCs in stack traces are actually the return addresses, that is, // addresses of the next instructions after the call. uptr pc = GetPreviousInstructionPc(trace[i]); +#else + // On Emscripten, the stack traces are obtained from JavaScript, and the + // addresses are not return addresses. + uptr pc = trace[i]; +#endif SymbolizedStack *frames = Symbolizer::GetOrInit()->SymbolizePC(pc); CHECK(frames); for (SymbolizedStack *cur = frames; cur; cur = cur->next) { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index c123ecb11206c..3918348b47bec 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_POSIX +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_file.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp index c26724ceb7a7d..4783459fba52a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -39,7 +39,21 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, } #endif -#if !SANITIZER_FUCHSIA +#if SANITIZER_EMSCRIPTEN +#include + +static INLINE bool ReportSupportsColors() { + return !!EM_ASM_INT({ + var setting = Module['printWithColors']; + if (setting != null) { + return setting; + } else { + return ENVIRONMENT_IS_NODE && process.stderr.isTTY; + } + }); +} + +#elif !SANITIZER_FUCHSIA bool ReportFile::SupportsColors() { SpinMutexLock l(mu); @@ -56,7 +70,7 @@ static INLINE bool ReportSupportsColors() { // Fuchsia's logs always go through post-processing that handles colorization. static INLINE bool ReportSupportsColors() { return true; } -#endif // !SANITIZER_FUCHSIA +#endif // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA bool ColorizeReports() { // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc index a43ce3efab127..f64b403d62aa8 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -13,7 +13,7 @@ // NetBSD uses libc calls directly #if !SANITIZER_NETBSD -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_OPENBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 33a8dfcde0269..7e7216c5b4ab7 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -18,11 +18,6 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") -UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") -UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", - "pointer-overflow") -UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset", - "pointer-overflow") UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cpp b/compiler-rt/lib/ubsan/ubsan_diag.cpp index 1b2828d236d6e..529cc6985763b 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_diag.cpp ----------------------------------------------------===// +//===-- ubsan_diag.cc -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -404,7 +404,7 @@ static const char *kSuppressionTypes[] = { void __ubsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) + suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); } diff --git a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp index 300179adae28c..c22fd17499725 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag_standalone.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_diag_standalone.cpp -----------------------------------------===// +//===-- ubsan_diag_standalone.cc ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_flags.cpp b/compiler-rt/lib/ubsan/ubsan_flags.cpp index 721c2273f133a..210b831507d2e 100644 --- a/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_flags.cpp ---------------------------------------------------===// +//===-- ubsan_flags.cc ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -19,6 +19,11 @@ #include +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + namespace __ubsan { const char *MaybeCallUbsanDefaultOptions() { @@ -54,7 +59,12 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); + cf.print_summary = false; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using some sanitizers. + // You can't run external symbolizers anyway. cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH"); +#endif OverrideCommonFlags(cf); } @@ -67,8 +77,20 @@ void InitializeFlags() { // Override from user-specified string. parser.ParseString(MaybeCallUbsanDefaultOptions()); + // Override from environment variable. - parser.ParseStringFromEnv("UBSAN_OPTIONS"); +#if SANITIZER_EMSCRIPTEN + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['UBSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#else + parser.ParseString(GetEnv("UBSAN_OPTIONS")); +#endif // SANITIZER_EMSCRIPTEN + InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index 3f9da75a12a8d..938ac89750f36 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_handlers.cpp ------------------------------------------------===// +//===-- ubsan_handlers.cc -------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -691,33 +691,14 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ValueHandle Result, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET; - - if (Base == 0 && Result == 0) - ET = ErrorType::NullptrWithOffset; - else if (Base == 0 && Result != 0) - ET = ErrorType::NullptrWithNonZeroOffset; - else if (Base != 0 && Result == 0) - ET = ErrorType::NullptrAfterNonZeroOffset; - else - ET = ErrorType::PointerOverflow; + ErrorType ET = ErrorType::PointerOverflow; if (ignoreReport(Loc, Opts, ET)) return; ScopedReport R(Opts, Loc, ET); - if (ET == ErrorType::NullptrWithOffset) { - Diag(Loc, DL_Error, ET, "applying zero offset to null pointer"); - } else if (ET == ErrorType::NullptrWithNonZeroOffset) { - Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer") - << Result; - } else if (ET == ErrorType::NullptrAfterNonZeroOffset) { - Diag( - Loc, DL_Error, ET, - "applying non-zero offset to non-null pointer %0 produced null pointer") - << (void *)Base; - } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { + if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { if (Base > Result) Diag(Loc, DL_Error, ET, "addition of unsigned offset to %0 overflowed to %1") diff --git a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp index 2a6d558de0342..9c324cc19a11f 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_handlers_cxx.cpp --------------------------------------------===// +//===-- ubsan_handlers_cxx.cc ---------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_init.cpp b/compiler-rt/lib/ubsan/ubsan_init.cpp index 1a3b7d3726743..f0bbe1ef10768 100644 --- a/compiler-rt/lib/ubsan/ubsan_init.cpp +++ b/compiler-rt/lib/ubsan/ubsan_init.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init.cpp ----------------------------------------------------===// +//===-- ubsan_init.cc -----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp index 91c3f57b424b9..323c2c1f9a474 100644 --- a/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_init_standalone.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init_standalone.cpp -----------------------------------------===// +//===-- ubsan_init_standalone.cc ------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp b/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp index fabbf919a4022..bf344a2a9fcdb 100644 --- a/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp +++ b/compiler-rt/lib/ubsan/ubsan_init_standalone_preinit.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_init_standalone_preinit.cpp --------------------------------===// +//===-- ubsan_init_standalone_preinit.cc ---------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_monitor.cpp b/compiler-rt/lib/ubsan/ubsan_monitor.cpp index d064e95f76f72..cb97a8ff1b887 100644 --- a/compiler-rt/lib/ubsan/ubsan_monitor.cpp +++ b/compiler-rt/lib/ubsan/ubsan_monitor.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_monitor.cpp ---------------------------------------*- C++ -*-===// +//===-- ubsan_monitor.cc ----------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h index 71d7fb18c9b3a..684af5a5c179b 100644 --- a/compiler-rt/lib/ubsan/ubsan_platform.h +++ b/compiler-rt/lib/ubsan/ubsan_platform.h @@ -16,7 +16,8 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(__NetBSD__) || defined(__OpenBSD__) || \ (defined(__sun__) && defined(__svr4__)) || \ - defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) + defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) || \ + defined(__EMSCRIPTEN__) # define CAN_SANITIZE_UB 1 #else # define CAN_SANITIZE_UB 0 diff --git a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp index 2c91db8ca3974..5f8a8c0662d4f 100644 --- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp @@ -1,4 +1,5 @@ -//=-- ubsan_signals_standalone.cpp ----------------------------------------===// +//=-- ubsan_signals_standalone.cc +//------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -26,7 +27,7 @@ // debuggerd handler, but before the ART handler. // * Interceptors don't work at all when ubsan runtime is loaded late, ex. when // it is part of an APK that does not use wrap.sh method. -#if SANITIZER_FUCHSIA || SANITIZER_ANDROID +#if SANITIZER_FUCHSIA || SANITIZER_ANDROID || SANITIZER_EMSCRIPTEN namespace __ubsan { void InitializeDeadlySignals() {} @@ -45,9 +46,8 @@ namespace __ubsan { static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - ubsan_GetStackTrace(stack, kStackTraceMax, - StackTrace::GetNextInstructionPc(sig.pc), sig.bp, - sig.context, common_flags()->fast_unwind_on_fatal); + ubsan_GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); } static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) { diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash.cpp index 8f4b9aee50bbd..431495672b55a 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash.cpp -----------------------------------------------===// +//===-- ubsan_type_hash.cc ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -11,7 +11,7 @@ // permitted to use language features which require a C++ ABI library. // // Most of the implementation lives in an ABI-specific source file -// (ubsan_type_hash_{itanium,win}.cpp). +// (ubsan_type_hash_{itanium,win}.cc). // //===----------------------------------------------------------------------===// diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp index 97846d4dd434b..c4b048f20a8c9 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash_itanium.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash_itanium.cpp ---------------------------------------===// +//===-- ubsan_type_hash_itanium.cc ----------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp index 45dcb758ec445..c7b2e45af4e66 100644 --- a/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp +++ b/compiler-rt/lib/ubsan/ubsan_type_hash_win.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_type_hash_win.cpp -------------------------------------------===// +//===-- ubsan_type_hash_win.cc --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_value.cpp b/compiler-rt/lib/ubsan/ubsan_value.cpp index 60f0b5c993482..ba336a6673ca7 100644 --- a/compiler-rt/lib/ubsan/ubsan_value.cpp +++ b/compiler-rt/lib/ubsan/ubsan_value.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_value.cpp ---------------------------------------------------===// +//===-- ubsan_value.cc ----------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp index 5ac7fc3e08e4c..fd39e210af0a8 100644 --- a/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp +++ b/compiler-rt/lib/ubsan/ubsan_win_dll_thunk.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_dll_thunk.cpp -------------------------------------------===// +//===-- ubsan_win_dll_thunk.cc --------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp b/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp index 00722b4033a53..87ada6131cde0 100644 --- a/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp +++ b/compiler-rt/lib/ubsan/ubsan_win_dynamic_runtime_thunk.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_dynamic_runtime_thunk.cpp -------------------------------===// +//===-- ubsan_win_dynamic_runtime_thunk.cc --------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp b/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp index 01db0c0ce78ab..8cf6344ce1d80 100644 --- a/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp +++ b/compiler-rt/lib/ubsan/ubsan_win_weak_interception.cpp @@ -1,4 +1,4 @@ -//===-- ubsan_win_weak_interception.cpp -----------------------------------===// +//===-- ubsan_win_weak_interception.cc ------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/libcxx/include/__config b/libcxx/include/__config index ccce227f4d6bd..5cedbe4a44fb2 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -99,7 +99,8 @@ // Previously libc++ used "unsigned int" exclusively. # define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION // Unstable attempt to provide a more optimized std::function -# define _LIBCPP_ABI_OPTIMIZED_FUNCTION +// XXX EMSCRIPTEN https://github.com/emscripten-core/emscripten/issues/11022 +//# define _LIBCPP_ABI_OPTIMIZED_FUNCTION // All the regex constants must be distinct and nonzero. # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO #elif _LIBCPP_ABI_VERSION == 1 @@ -307,7 +308,7 @@ // random data even when using sandboxing mechanisms such as chroots, // Capsicum, etc. # define _LIBCPP_USING_ARC4_RANDOM -#elif defined(__Fuchsia__) || defined(__wasi__) +#elif defined(__Fuchsia__) || defined(__wasi__) || defined(__EMSCRIPTEN__) # define _LIBCPP_USING_GETENTROPY #elif defined(__native_client__) // NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access, @@ -908,7 +909,7 @@ typedef unsigned int char32_t; #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // Most unix variants have catopen. These are the specific ones that don't. -# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) +# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) // XXX Emscripten catopen always returns -1 # define _LIBCPP_HAS_CATOPEN 1 # endif #endif @@ -1122,6 +1123,7 @@ _LIBCPP_FUNC_VIS extern "C" void __sanitizer_annotate_contiguous_container( defined(__APPLE__) || \ defined(__CloudABI__) || \ defined(__sun__) || \ + defined(__EMSCRIPTEN__) || \ (defined(__MINGW32__) && __has_include()) # define _LIBCPP_HAS_THREAD_API_PTHREAD # elif defined(__Fuchsia__) diff --git a/libcxx/include/__sso_allocator b/libcxx/include/__sso_allocator index 393012873848c..c381068a3614b 100644 --- a/libcxx/include/__sso_allocator +++ b/libcxx/include/__sso_allocator @@ -40,9 +40,9 @@ public: typedef _Tp* pointer; typedef _Tp value_type; - _LIBCPP_INLINE_VISIBILITY __sso_allocator() throw() : __allocated_(false) {} - _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator&) throw() : __allocated_(false) {} - template _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator<_Up, _Np>&) throw() + _LIBCPP_INLINE_VISIBILITY __sso_allocator() _NOEXCEPT : __allocated_(false) {} + _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator&) _NOEXCEPT : __allocated_(false) {} + template _LIBCPP_INLINE_VISIBILITY __sso_allocator(const __sso_allocator<_Up, _Np>&) _NOEXCEPT : __allocated_(false) {} private: __sso_allocator& operator=(const __sso_allocator&); @@ -63,7 +63,7 @@ public: else _VSTD::__libcpp_deallocate(__p, __n * sizeof(_Tp), _LIBCPP_ALIGNOF(_Tp)); } - _LIBCPP_INLINE_VISIBILITY size_type max_size() const throw() {return size_type(~0) / sizeof(_Tp);} + _LIBCPP_INLINE_VISIBILITY size_type max_size() const _NOEXCEPT {return size_type(~0) / sizeof(_Tp);} _LIBCPP_INLINE_VISIBILITY bool operator==(__sso_allocator& __a) const {return &buf_ == &__a.buf_;} diff --git a/libcxx/include/codecvt b/libcxx/include/codecvt index 5ea411ea781b7..05fa765c31804 100644 --- a/libcxx/include/codecvt +++ b/libcxx/include/codecvt @@ -102,11 +102,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -137,11 +137,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -172,11 +172,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template @@ -260,11 +260,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -295,11 +295,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -330,11 +330,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -365,11 +365,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -400,11 +400,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template @@ -488,11 +488,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template <> @@ -523,11 +523,11 @@ protected: virtual result do_unshift(state_type& __st, extern_type* __to, extern_type* __to_end, extern_type*& __to_nxt) const; - virtual int do_encoding() const throw(); - virtual bool do_always_noconv() const throw(); + virtual int do_encoding() const _NOEXCEPT; + virtual bool do_always_noconv() const _NOEXCEPT; virtual int do_length(state_type&, const extern_type* __frm, const extern_type* __end, size_t __mx) const; - virtual int do_max_length() const throw(); + virtual int do_max_length() const _NOEXCEPT; }; template _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr<_Up>& __p) throw() + _LIBCPP_INLINE_VISIBILITY explicit auto_ptr(_Tp* __p = 0) _NOEXCEPT : __ptr_(__p) {} + _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr& __p) _NOEXCEPT : __ptr_(__p.release()) {} + template _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr<_Up>& __p) _NOEXCEPT : __ptr_(__p.release()) {} - _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr& __p) throw() + _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr& __p) _NOEXCEPT {reset(__p.release()); return *this;} - template _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr<_Up>& __p) throw() + template _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr<_Up>& __p) _NOEXCEPT {reset(__p.release()); return *this;} - _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr_ref<_Tp> __p) throw() + _LIBCPP_INLINE_VISIBILITY auto_ptr& operator=(auto_ptr_ref<_Tp> __p) _NOEXCEPT {reset(__p.__ptr_); return *this;} - _LIBCPP_INLINE_VISIBILITY ~auto_ptr() throw() {delete __ptr_;} + _LIBCPP_INLINE_VISIBILITY ~auto_ptr() _NOEXCEPT {delete __ptr_;} - _LIBCPP_INLINE_VISIBILITY _Tp& operator*() const throw() + _LIBCPP_INLINE_VISIBILITY _Tp& operator*() const _NOEXCEPT {return *__ptr_;} - _LIBCPP_INLINE_VISIBILITY _Tp* operator->() const throw() {return __ptr_;} - _LIBCPP_INLINE_VISIBILITY _Tp* get() const throw() {return __ptr_;} - _LIBCPP_INLINE_VISIBILITY _Tp* release() throw() + _LIBCPP_INLINE_VISIBILITY _Tp* operator->() const _NOEXCEPT {return __ptr_;} + _LIBCPP_INLINE_VISIBILITY _Tp* get() const _NOEXCEPT {return __ptr_;} + _LIBCPP_INLINE_VISIBILITY _Tp* release() _NOEXCEPT { _Tp* __t = __ptr_; __ptr_ = 0; return __t; } - _LIBCPP_INLINE_VISIBILITY void reset(_Tp* __p = 0) throw() + _LIBCPP_INLINE_VISIBILITY void reset(_Tp* __p = 0) _NOEXCEPT { if (__ptr_ != __p) delete __ptr_; __ptr_ = __p; } - _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr_ref<_Tp> __p) throw() : __ptr_(__p.__ptr_) {} - template _LIBCPP_INLINE_VISIBILITY operator auto_ptr_ref<_Up>() throw() + _LIBCPP_INLINE_VISIBILITY auto_ptr(auto_ptr_ref<_Tp> __p) _NOEXCEPT : __ptr_(__p.__ptr_) {} + template _LIBCPP_INLINE_VISIBILITY operator auto_ptr_ref<_Up>() _NOEXCEPT {auto_ptr_ref<_Up> __t; __t.__ptr_ = release(); return __t;} - template _LIBCPP_INLINE_VISIBILITY operator auto_ptr<_Up>() throw() + template _LIBCPP_INLINE_VISIBILITY operator auto_ptr<_Up>() _NOEXCEPT {return auto_ptr<_Up>(release());} }; diff --git a/libcxx/include/regex b/libcxx/include/regex index 5ac9e325e136f..0fa1ca75c7b5b 100644 --- a/libcxx/include/regex +++ b/libcxx/include/regex @@ -977,7 +977,7 @@ class _LIBCPP_EXCEPTION_ABI regex_error regex_constants::error_type __code_; public: explicit regex_error(regex_constants::error_type __ecode); - virtual ~regex_error() throw(); + virtual ~regex_error() _NOEXCEPT; _LIBCPP_INLINE_VISIBILITY regex_constants::error_type code() const {return __code_;} }; diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo index 27601769a83be..645a1c8890f1f 100644 --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -301,6 +301,9 @@ public: return __impl::__hash(__type_name); } + // XXX Emscripten: adding `always_inline` fixes + // https://github.com/emscripten-core/emscripten/issues/13330 + __attribute__((always_inline)) _LIBCPP_INLINE_VISIBILITY bool operator==(const type_info& __arg) const _NOEXCEPT { diff --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h index 501cbc4ffebaa..56e1a95b54edb 100644 --- a/libcxx/src/include/config_elast.h +++ b/libcxx/src/include/config_elast.h @@ -29,6 +29,8 @@ #define _LIBCPP_ELAST 4095 #elif defined(__APPLE__) // No _LIBCPP_ELAST needed on Apple +#elif defined(__EMSCRIPTEN__) // XXX EMSCRIPTEN added ELAST value +#define _LIBCPP_ELAST 256 #elif defined(__sun__) #define _LIBCPP_ELAST ESTALE #elif defined(_LIBCPP_MSVCRT_LIKE) diff --git a/libcxx/src/ios.cpp b/libcxx/src/ios.cpp index 2dc84be828739..92717138885a5 100644 --- a/libcxx/src/ios.cpp +++ b/libcxx/src/ios.cpp @@ -84,7 +84,7 @@ ios_base::failure::failure(const char* msg, const error_code& ec) { } -ios_base::failure::~failure() throw() +ios_base::failure::~failure() _NOEXCEPT { } diff --git a/libcxx/src/iostream.cpp b/libcxx/src/iostream.cpp index ad1920abc6572..874c856030211 100644 --- a/libcxx/src/iostream.cpp +++ b/libcxx/src/iostream.cpp @@ -77,7 +77,7 @@ __asm__("?wclog@" _LIBCPP_ABI_NAMESPACE_STR "@std@@3V?$basic_ostream at _WU?$char_t #endif ; -_LIBCPP_HIDDEN ios_base::Init __start_std_streams; +_LIBCPP_HIDDEN ios_base::Init __attribute__((init_priority(101))) __start_std_streams; // XXX EMSCRIPTEN: ensure a high priority for this constructor, see #3824 // On Windows the TLS storage for locales needs to be initialized before we create // the standard streams, otherwise it may not be alive during program termination diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index 901e78565857b..bd0b42f7cb7c0 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -74,8 +74,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; diff --git a/libcxx/src/regex.cpp b/libcxx/src/regex.cpp index d31e494874321..fb779c540b38c 100644 --- a/libcxx/src/regex.cpp +++ b/libcxx/src/regex.cpp @@ -66,7 +66,7 @@ regex_error::regex_error(regex_constants::error_type ecode) __code_(ecode) {} -regex_error::~regex_error() throw() {} +regex_error::~regex_error() _NOEXCEPT {} namespace { diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h index d21d3e1e2331d..3ffb1a167f388 100644 --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -39,20 +39,24 @@ extern "C" { // 2.4.2 Allocating the Exception Object extern _LIBCXXABI_FUNC_VIS void * -__cxa_allocate_exception(size_t thrown_size) throw(); +__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_free_exception(void *thrown_exception) throw(); +__cxa_free_exception(void *thrown_exception) _NOEXCEPT; // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void *thrown_exception, std::type_info *tinfo, +#ifdef __USING_WASM_EXCEPTIONS__ + void *(*dest)(void *)); +#else void (*dest)(void *)); +#endif // 2.5.3 Exception Handlers extern _LIBCXXABI_FUNC_VIS void * -__cxa_get_exception_ptr(void *exceptionObject) throw(); +__cxa_get_exception_ptr(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void * -__cxa_begin_catch(void *exceptionObject) throw(); +__cxa_begin_catch(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); #if defined(_LIBCXXABI_ARM_EHABI) extern _LIBCXXABI_FUNC_VIS bool @@ -147,17 +151,17 @@ extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name, // Apple additions to support C++ 0x exception_ptr class // These are primitives to wrap a smart pointer around an exception object -extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw(); +extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_rethrow_primary_exception(void *primary_exception); extern _LIBCXXABI_FUNC_VIS void -__cxa_increment_exception_refcount(void *primary_exception) throw(); +__cxa_increment_exception_refcount(void *primary_exception) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_decrement_exception_refcount(void *primary_exception) throw(); +__cxa_decrement_exception_refcount(void *primary_exception) _NOEXCEPT; // Apple extension to support std::uncaught_exception() -extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw(); -extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw(); +extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _NOEXCEPT; +extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _NOEXCEPT; #if defined(__linux__) || defined(__Fuchsia__) // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI. diff --git a/libcxxabi/src/abort_message.cpp b/libcxxabi/src/abort_message.cpp index d556af1c9037d..4bb7fe37bfb6e 100644 --- a/libcxxabi/src/abort_message.cpp +++ b/libcxxabi/src/abort_message.cpp @@ -35,11 +35,20 @@ void abort_message(const char* format, ...) #ifdef __APPLE__ fprintf(stderr, "libc++abi.dylib: "); #endif +#if defined(__EMSCRIPTEN__) && defined(NDEBUG) + // Just trap in a non-debug build. These internal libcxxabi assertions are + // very rare, and it's not worth linking in vfprintf stdio support or + // even minimal logging for them, as we'll have a proper call stack, which + // will show a call into "abort_message", and can help debugging. (In a + // debug build that won't be inlined.) + __builtin_trap(); +#else va_list list; va_start(list, format); vfprintf(stderr, format, list); va_end(list); fprintf(stderr, "\n"); +#endif // EMSCRIPTEN #endif #if defined(__APPLE__) && defined(HAVE_CRASHREPORTERCLIENT_H) diff --git a/libcxxabi/src/cxa_default_handlers.cpp b/libcxxabi/src/cxa_default_handlers.cpp index d2f823d2b7786..de256c5a68689 100644 --- a/libcxxabi/src/cxa_default_handlers.cpp +++ b/libcxxabi/src/cxa_default_handlers.cpp @@ -45,6 +45,7 @@ static void demangling_terminate_handler() exception_header + 1; const __shim_type_info* thrown_type = static_cast(exception_header->exceptionType); +#ifndef __EMSCRIPTEN__ // Try to get demangled name of thrown_type int status; char buf[1024]; @@ -52,6 +53,10 @@ static void demangling_terminate_handler() const char* name = __cxa_demangle(thrown_type->name(), buf, &len, &status); if (status != 0) name = thrown_type->name(); +#else // __EMSCRIPTEN__ - we can demangle stack traces ourselves, best not to + // pull in all of libcxxabi-demangle for just this file + const char* name = thrown_type->name(); +#endif // If the uncaught exception can be caught with std::exception& const __shim_type_info* catch_type = static_cast(&typeid(std::exception)); diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp index ebb05ce54213d..2a7483cb4a986 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -180,7 +180,7 @@ extern "C" { // object. Zero-fill the object. If memory can't be allocated, call // std::terminate. Return a pointer to the memory to be used for the // user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); // Allocate extra space before the __cxa_exception header to ensure the @@ -198,7 +198,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() { // Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { // Compute the size of the padding before the header. size_t header_offset = get_cxa_exception_offset(); char *raw_buffer = @@ -254,7 +254,12 @@ will call terminate, assuming that there was no handler for the exception. */ void +#ifdef __USING_WASM_EXCEPTIONS__ +// In wasm, destructors return their argument +__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(*dest)(void *)) { +#else __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { +#endif __cxa_eh_globals *globals = __cxa_get_globals(); __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -292,7 +297,7 @@ The adjusted pointer is computed by the personality routine during phase 1 Requires: exception is native */ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { +void *__cxa_get_exception_ptr(void *unwind_exception) _NOEXCEPT { #if defined(_LIBCXXABI_ARM_EHABI) return reinterpret_cast( static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); @@ -307,7 +312,7 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() { The routine to be called before the cleanup. This will save __cxa_exception in __cxa_eh_globals, so that __cxa_end_cleanup() can recover later. */ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { +bool __cxa_begin_cleanup(void *unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); __cxa_eh_globals* globals = __cxa_get_globals(); __cxa_exception* exception_header = @@ -418,7 +423,7 @@ to terminate or unexpected during unwinding. _Unwind_Exception and return a pointer to that. */ void* -__cxa_begin_catch(void* unwind_arg) throw() +__cxa_begin_catch(void* unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); bool native_exception = __isOurExceptionClass(unwind_exception); @@ -626,7 +631,7 @@ void __cxa_rethrow() { Requires: If thrown_object is not NULL, it is a native exception. */ void -__cxa_increment_exception_refcount(void *thrown_object) throw() { +__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -643,7 +648,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ _LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { +void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -666,7 +671,7 @@ void __cxa_decrement_exception_refcount(void *thrown_object) throw() { been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ -void *__cxa_current_primary_exception() throw() { +void *__cxa_current_primary_exception() _NOEXCEPT { // get the current exception __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (NULL == globals) @@ -738,10 +743,10 @@ __cxa_rethrow_primary_exception(void* thrown_object) } bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } +__cxa_uncaught_exception() _NOEXCEPT { return __cxa_uncaught_exceptions() != 0; } unsigned int -__cxa_uncaught_exceptions() throw() +__cxa_uncaught_exceptions() _NOEXCEPT { // This does not report foreign exceptions in flight __cxa_eh_globals* globals = __cxa_get_globals_fast(); diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h index 8c6c8bca853c6..6adc4c597792d 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.h @@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // Manage the exception object itself. std::type_info *exceptionType; +#ifdef __USING_WASM_EXCEPTIONS__ + // In wasm, destructors return their argument + void *(*exceptionDestructor)(void *); +#else void (*exceptionDestructor)(void *); +#endif std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; diff --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp index f520a4db6edac..713f02b3c6597 100644 --- a/libcxxabi/src/cxa_handlers.cpp +++ b/libcxxabi/src/cxa_handlers.cpp @@ -19,6 +19,32 @@ #include "private_typeinfo.h" #include "include/atomic_support.h" +namespace __cxxabiv1 { + +#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__ +// XXX EMSCRIPTEN: Copied from cxa_exception.cpp since we don't compile that +// file in Emscripten EH mode. Note that in no-exceptions builds we include +// cxa_noexception.cpp which provides stubs of those anyhow. + +// Is it one of ours? +uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { +// On x86 and some ARM unwinders, unwind_exception->exception_class is +// a uint64_t. On other ARM unwinders, it is a char[8] +// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf +// So we just copy it into a uint64_t to be sure. + uint64_t exClass; + ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); + return exClass; +} + +bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { + return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); +} +#endif + +} + namespace std { diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index f27625776111b..3715e7c7dcf08 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -22,6 +22,8 @@ #include "private_typeinfo.h" #include "unwind.h" +#define __USING_SJLJ_OR_WASM_EXCEPTIONS__ (__USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__) + #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) #include #include @@ -61,7 +63,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, +------------------+--+-----+-----+------------------------+--------------------------+ | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | +---------------------+-----------+---------------------------------------------------+ -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip lies within the | | ... (start, length) range of one of these | @@ -75,7 +77,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#else // __USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip is a 1-based index into | | ... this table. Or it is -1 meaning no | @@ -88,7 +90,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------------------------------------------------------+ | Beginning of Action Table ttypeIndex == 0 : cleanup | | ... ttypeIndex > 0 : catch | @@ -529,7 +531,7 @@ void set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, const scan_results& results) { -#if defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ #define __builtin_eh_return_data_regno(regno) regno #endif _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), @@ -616,7 +618,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Get beginning current frame's code (as defined by the // emitted dwarf code) uintptr_t funcStart = _Unwind_GetRegionStart(context); -#ifdef __USING_SJLJ_EXCEPTIONS__ +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (ip == uintptr_t(-1)) { // no action @@ -626,9 +628,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, else if (ip == 0) call_terminate(native_exception, unwind_exception); // ip is 1-based index into call site table -#else // !__USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ const uint8_t* classInfo = NULL; // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding // dwarf emission @@ -649,8 +651,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Walk call-site table looking for range that // includes current PC. uint8_t callSiteEncoding = *lsda++; -#ifdef __USING_SJLJ_EXCEPTIONS__ - (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ + (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used #endif uint32_t callSiteTableLength = static_cast(readULEB128(&lsda)); const uint8_t* callSiteTableStart = lsda; @@ -660,7 +662,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, while (callSitePtr < callSiteTableEnd) { // There is one entry per call site. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ // The call sites are non-overlapping in [start, start+length) // The call sites are ordered in increasing value of start uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); @@ -668,15 +670,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); uintptr_t actionEntry = readULEB128(&callSitePtr); if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ // ip is 1-based index into this table uintptr_t landingPad = readULEB128(&callSitePtr); uintptr_t actionEntry = readULEB128(&callSitePtr); if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ { // Found the call site containing ip. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (landingPad == 0) { // No handler here @@ -684,9 +686,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, return; } landingPad = (uintptr_t)lpStart + landingPad; -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ if (actionEntry == 0) { // Found a cleanup @@ -725,7 +727,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // If this is a type 2 search save state and return _URC_HANDLER_FOUND // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) +#endif { // Save state and return _URC_HANDLER_FOUND results.ttypeIndex = ttypeIndex; @@ -761,7 +768,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // If this is a type 1 search save state and return _URC_HANDLER_FOUND // If this is a type 3 search and !_UA_FORCE_UNWIND, we should have found this in phase 1! // If this is a type 3 search and _UA_FORCE_UNWIND, ignore handler and continue scan +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else if (actions & _UA_SEARCH_PHASE) +#endif { // Save state and return _URC_HANDLER_FOUND results.ttypeIndex = ttypeIndex; @@ -805,7 +817,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // If this is a type 1 search, save state and return _URC_HANDLER_FOUND // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else if (actions & _UA_SEARCH_PHASE) +#endif { // Save state and return _URC_HANDLER_FOUND results.ttypeIndex = ttypeIndex; @@ -830,7 +847,12 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // If this is a type 2 search, save state and return _URC_HANDLER_FOUND // If this is a type 3 search !_UA_FORCE_UNWIND, we should have found this in phase 1! // If this is a type 3 search _UA_FORCE_UNWIND, ignore handler and continue scan +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) +#endif { // Save state and return _URC_HANDLER_FOUND results.ttypeIndex = ttypeIndex; @@ -878,7 +900,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, action += actionOffset; } // there is no break out of this loop, only return } -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ else if (ipOffset < start) { // There is no call site for this ip @@ -886,7 +908,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Possible stack corruption. call_terminate(native_exception, unwind_exception); } -#endif // !__USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ } // there might be some tricky cases which break out of this loop // It is possible that no eh table entry specify how to handle @@ -943,7 +965,9 @@ _UA_CLEANUP_PHASE */ #if !defined(_LIBCXXABI_ARM_EHABI) -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_WASM_EXCEPTIONS__ +_Unwind_Reason_Code __gxx_personality_wasm0 +#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) static _Unwind_Reason_Code __gxx_personality_imp #else _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code @@ -1025,6 +1049,16 @@ __gxx_personality_v0 { // Found a non-catching handler. Jump to it: set_registers(unwind_exception, context, results); +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm uses only one phase in _UA_CLEANUP_PHASE, so we should set + // these here. + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + exception_header->handlerSwitchValue = static_cast(results.ttypeIndex); + exception_header->actionRecord = results.actionRecord; + exception_header->languageSpecificData = results.languageSpecificData; + exception_header->catchTemp = reinterpret_cast(results.landingPad); + exception_header->adjustedPtr = results.adjustedPtr; +#endif return _URC_INSTALL_CONTEXT; } // Did not find a cleanup. Return the results of the scan diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index 5ce762a22bc4d..99c6fa021d377 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -1288,4 +1288,35 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, use_strcmp); } +// XXX EMSCRIPTEN + +#ifndef __USING_WASM_EXCEPTIONS__ + +// These functions are used by the emscripten-style exception handling +// mechanism. +// Note that they need to be included even in the `-noexcept` build of +// libc++abi to support the case where some parts of a project are built +// with exception catching enabled, but at link time exception catching +// is disabled. In this case dependencies to these functions (and the JS +// functions which call them) will still exist in the final build. +extern "C" { + +int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) { + //std::type_info *t1 = static_cast(catchType); + //std::type_info *t2 = static_cast(excpType); + //printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown); + + void *temp = *thrown; + int ret = catchType->can_catch(excpType, temp); + if (ret) *thrown = temp; // apply changes only if we are catching + return ret; +} + +int __cxa_is_pointer_type(__shim_type_info* type) { + return !!dynamic_cast<__pointer_type_info*>(type); +} + +} +#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ + } // __cxxabiv1 diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp index 698c5f7c290c0..0fcb486ec663a 100644 --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -38,8 +38,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; From llvm-branch-commits at lists.llvm.org Mon May 24 20:49:44 2021 From: llvm-branch-commits at lists.llvm.org (Sam Clegg via llvm-branch-commits) Date: Mon, 24 May 2021 20:49:44 -0700 (PDT) Subject: [llvm-branch-commits] [compiler-rt] 60e78c0 - Update library changes from upstream llvmorg-12.0.0 Message-ID: <60ac73d8.1c69fb81.7fb22.9441@mx.google.com> Author: Sam Clegg Date: 2021-05-24T20:49:18-07:00 New Revision: 60e78c0fb0a394b17d61e9be2a43ed1e34b31852 URL: https://github.com/llvm/llvm-project/commit/60e78c0fb0a394b17d61e9be2a43ed1e34b31852 DIFF: https://github.com/llvm/llvm-project/commit/60e78c0fb0a394b17d61e9be2a43ed1e34b31852.diff LOG: Update library changes from upstream llvmorg-12.0.0 These changes are from emscripten as of 3ad991a6cc3c085ac325be. Added: Modified: compiler-rt/include/sanitizer/tsan_interface_atomic.h compiler-rt/lib/asan/asan_errors.cpp compiler-rt/lib/asan/asan_flags.cpp compiler-rt/lib/asan/asan_interceptors.cpp compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp compiler-rt/lib/asan/asan_malloc_linux.cpp compiler-rt/lib/asan/asan_mapping.h compiler-rt/lib/asan/asan_poisoning.cpp compiler-rt/lib/asan/asan_poisoning.h compiler-rt/lib/asan/asan_posix.cpp compiler-rt/lib/asan/asan_rtl.cpp compiler-rt/lib/asan/asan_shadow_setup.cpp compiler-rt/lib/asan/asan_thread.cpp compiler-rt/lib/interception/interception.h compiler-rt/lib/interception/interception_linux.h compiler-rt/lib/lsan/lsan.cpp compiler-rt/lib/lsan/lsan_allocator.cpp compiler-rt/lib/lsan/lsan_allocator.h compiler-rt/lib/lsan/lsan_common.cpp compiler-rt/lib/lsan/lsan_common.h compiler-rt/lib/lsan/lsan_common_linux.cpp compiler-rt/lib/lsan/lsan_interceptors.cpp compiler-rt/lib/lsan/lsan_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp compiler-rt/lib/sanitizer_common/sanitizer_linux.h compiler-rt/lib/sanitizer_common/sanitizer_platform.h compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc compiler-rt/lib/ubsan/ubsan_checks.inc compiler-rt/lib/ubsan/ubsan_diag.cpp compiler-rt/lib/ubsan/ubsan_flags.cpp compiler-rt/lib/ubsan/ubsan_handlers.cpp compiler-rt/lib/ubsan/ubsan_platform.h compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp libcxx/include/__config libcxx/include/typeinfo libcxx/src/include/config_elast.h libcxx/src/new.cpp libcxx/src/support/runtime/exception_fallback.ipp libcxxabi/include/cxxabi.h libcxxabi/src/abort_message.cpp libcxxabi/src/cxa_exception.cpp libcxxabi/src/cxa_exception.h libcxxabi/src/cxa_handlers.cpp libcxxabi/src/cxa_personality.cpp libcxxabi/src/private_typeinfo.cpp libcxxabi/src/stdlib_new_delete.cpp Removed: ################################################################################ diff --git a/compiler-rt/include/sanitizer/tsan_interface_atomic.h b/compiler-rt/include/sanitizer/tsan_interface_atomic.h index 8052bc1d56b38..5e41e2256c300 100644 --- a/compiler-rt/include/sanitizer/tsan_interface_atomic.h +++ b/compiler-rt/include/sanitizer/tsan_interface_atomic.h @@ -30,7 +30,7 @@ __extension__ typedef __int128 __tsan_atomic128; #endif // Part of ABI, do not change. -// https://github.com/llvm/llvm-project/blob/master/libcxx/include/atomic +// https://github.com/llvm/llvm-project/blob/main/libcxx/include/atomic typedef enum { __tsan_memory_order_relaxed, __tsan_memory_order_consume, diff --git a/compiler-rt/lib/asan/asan_errors.cpp b/compiler-rt/lib/asan/asan_errors.cpp index 541c6e0353b57..e1c953b141643 100644 --- a/compiler-rt/lib/asan/asan_errors.cpp +++ b/compiler-rt/lib/asan/asan_errors.cpp @@ -480,6 +480,17 @@ ErrorGeneric::ErrorGeneric(u32 tid, uptr pc_, uptr bp_, uptr sp_, uptr addr, scariness.Scare(bug_type_score + read_after_free_bonus, bug_descr); if (far_from_bounds) scariness.Scare(10, "far-from-bounds"); } +#if SANITIZER_EMSCRIPTEN + // If address is in the first page (64 KB), then it is likely that the + // access is a result of a null pointer dereference. + else if (addr < 65536) { + bug_descr = "null-pointer-dereference"; + scariness.Scare(25, bug_descr); + } else if (AddrIsInShadow(addr)) { + bug_descr = "shadow-access"; + scariness.Scare(25, bug_descr); + } +#endif } } diff --git a/compiler-rt/lib/asan/asan_flags.cpp b/compiler-rt/lib/asan/asan_flags.cpp index cb6a89fe32ce7..197dfb23661af 100644 --- a/compiler-rt/lib/asan/asan_flags.cpp +++ b/compiler-rt/lib/asan/asan_flags.cpp @@ -22,6 +22,12 @@ #include "ubsan/ubsan_flags.h" #include "ubsan/ubsan_platform.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + + namespace __asan { Flags asan_flags_dont_use_directly; // use via flags(). @@ -54,7 +60,11 @@ void InitializeFlags() { CommonFlags cf; cf.CopyFrom(*common_flags()); cf.detect_leaks = cf.detect_leaks && CAN_SANITIZE_LEAKS; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using LSan. + // You can't run external symbolizer executables anyway. cf.external_symbolizer_path = GetEnv("ASAN_SYMBOLIZER_PATH"); +#endif cf.malloc_context_size = kDefaultMallocContextSize; cf.intercept_tls_get_addr = true; cf.exitcode = 1; @@ -115,6 +125,26 @@ void InitializeFlags() { lsan_parser.ParseString(lsan_default_options); #endif +#if SANITIZER_EMSCRIPTEN + char *options; + // Override from Emscripten Module. +#define MAKE_OPTION_LOAD(parser, name) \ + options = (char*) EM_ASM_INT({ \ + return withBuiltinMalloc(function () { \ + return allocateUTF8(Module[name] || 0); \ + }); \ + }); \ + parser.ParseString(options); \ + emscripten_builtin_free(options); + + MAKE_OPTION_LOAD(asan_parser, 'ASAN_OPTIONS'); +#if CAN_SANITIZE_LEAKS + MAKE_OPTION_LOAD(lsan_parser, 'LSAN_OPTIONS'); +#endif +#if CAN_SANITIZE_UB + MAKE_OPTION_LOAD(ubsan_parser, 'UBSAN_OPTIONS'); +#endif +#else // Override from command line. asan_parser.ParseStringFromEnv("ASAN_OPTIONS"); #if CAN_SANITIZE_LEAKS @@ -123,12 +153,18 @@ void InitializeFlags() { #if CAN_SANITIZE_UB ubsan_parser.ParseStringFromEnv("UBSAN_OPTIONS"); #endif +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); // TODO(eugenis): dump all flags at verbosity>=2? if (Verbosity()) ReportUnrecognizedFlags(); +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN + if (common_flags()->help) { // TODO(samsonov): print all of the flags (ASan, LSan, common). asan_parser.PrintFlagDescriptions(); diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp index cd07d51878b1c..6f124e9770373 100644 --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -23,10 +23,10 @@ #include "lsan/lsan_common.h" #include "sanitizer_common/sanitizer_libc.h" -// There is no general interception at all on Fuchsia and RTEMS. -// Only the functions in asan_interceptors_memintrinsics.cpp are +// There is no general interception at all on Fuchsia, RTEMS and Emscripten. +// Only the functions in asan_interceptors_memintrinsics.cc are // really defined to replace libc functions. -#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN #if SANITIZER_POSIX #include "sanitizer_common/sanitizer_posix.h" @@ -704,4 +704,4 @@ void InitializeAsanInterceptors() { } // namespace __asan -#endif // !SANITIZER_FUCHSIA +#endif // !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp index ccdd5159042cf..7280523b86b70 100644 --- a/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp +++ b/compiler-rt/lib/asan/asan_interceptors_memintrinsics.cpp @@ -30,7 +30,7 @@ void *__asan_memmove(void *to, const void *from, uptr size) { ASAN_MEMMOVE_IMPL(nullptr, to, from, size); } -#if SANITIZER_FUCHSIA || SANITIZER_RTEMS +#if SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN // Fuchsia and RTEMS don't use sanitizer_common_interceptors.inc, but // the only things there it wants are these three. Just define them @@ -40,4 +40,4 @@ extern "C" decltype(__asan_memcpy) memcpy[[gnu::alias("__asan_memcpy")]]; extern "C" decltype(__asan_memmove) memmove[[gnu::alias("__asan_memmove")]]; extern "C" decltype(__asan_memset) memset[[gnu::alias("__asan_memset")]]; -#endif // SANITIZER_FUCHSIA || SANITIZER_RTEMS +#endif // SANITIZER_FUCHSIA || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/asan/asan_malloc_linux.cpp b/compiler-rt/lib/asan/asan_malloc_linux.cpp index 9c3f0a5338ee5..7d7b3631a187c 100644 --- a/compiler-rt/lib/asan/asan_malloc_linux.cpp +++ b/compiler-rt/lib/asan/asan_malloc_linux.cpp @@ -15,7 +15,8 @@ #include "sanitizer_common/sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_FUCHSIA || SANITIZER_LINUX || \ - SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS + SANITIZER_NETBSD || SANITIZER_RTEMS || SANITIZER_SOLARIS || \ + SANITIZER_EMSCRIPTEN #include "sanitizer_common/sanitizer_allocator_checks.h" #include "sanitizer_common/sanitizer_errno.h" diff --git a/compiler-rt/lib/asan/asan_mapping.h b/compiler-rt/lib/asan/asan_mapping.h index f239c3ee2ff92..aa499376df64f 100644 --- a/compiler-rt/lib/asan/asan_mapping.h +++ b/compiler-rt/lib/asan/asan_mapping.h @@ -287,8 +287,8 @@ extern uptr kHighMemEnd, kMidMemBeg, kMidMemEnd; // Initialized in __asan_init. #if SANITIZER_MYRIAD2 #include "asan_mapping_myriad.h" -#elif defined(__sparc__) && SANITIZER_WORDSIZE == 64 -#include "asan_mapping_sparc64.h" +#elif SANITIZER_EMSCRIPTEN +#include "asan_mapping_emscripten.h" #else #define MEM_TO_SHADOW(mem) (((mem) >> SHADOW_SCALE) + (SHADOW_OFFSET)) diff --git a/compiler-rt/lib/asan/asan_poisoning.cpp b/compiler-rt/lib/asan/asan_poisoning.cpp index 44f872ef61909..15be546f62b23 100644 --- a/compiler-rt/lib/asan/asan_poisoning.cpp +++ b/compiler-rt/lib/asan/asan_poisoning.cpp @@ -181,6 +181,15 @@ uptr __asan_region_is_poisoned(uptr beg, uptr size) { if (!AddrIsInMem(beg) && !AddrIsInShadow(beg)) return 0; if (!AddrIsInMem(end) && !AddrIsInShadow(end)) return 0; } else { +#if SANITIZER_EMSCRIPTEN + // XXX Emscripten hack XXX + // Null pointer handling, since Emscripten does not crash on null pointer, + // ASan must catch null pointer dereference by itself. + // Unfortunately, this function returns 0 to mean the region is not + // poisoned, so we must return 1 instead if we receive a region + // starting at 0. + if (!beg) return 1; +#endif if (!AddrIsInMem(beg)) return beg; if (!AddrIsInMem(end)) return end; } diff --git a/compiler-rt/lib/asan/asan_poisoning.h b/compiler-rt/lib/asan/asan_poisoning.h index 62dd9bd0edd32..0c8c283986a62 100644 --- a/compiler-rt/lib/asan/asan_poisoning.h +++ b/compiler-rt/lib/asan/asan_poisoning.h @@ -54,6 +54,10 @@ ALWAYS_INLINE void FastPoisonShadow(uptr aligned_beg, uptr aligned_size, // RTEMS doesn't have have pages, let alone a fast way to zero // them, so default to memset. SANITIZER_RTEMS == 1 || + // Emscripten doesn't have a nice way to zero whole pages. + // The bulk memory proposal will allow memset to be optimized, but + // even then, we still must use memset. + SANITIZER_EMSCRIPTEN == 1 || shadow_end - shadow_beg < common_flags()->clear_shadow_mmap_threshold) { REAL(memset)((void*)shadow_beg, value, shadow_end - shadow_beg); } else { diff --git a/compiler-rt/lib/asan/asan_posix.cpp b/compiler-rt/lib/asan/asan_posix.cpp index d7f19d846544b..6e49520498158 100644 --- a/compiler-rt/lib/asan/asan_posix.cpp +++ b/compiler-rt/lib/asan/asan_posix.cpp @@ -40,6 +40,9 @@ void AsanOnDeadlySignal(int signo, void *siginfo, void *context) { } bool PlatformUnpoisonStacks() { +#if SANITIZER_EMSCRIPTEN + return false; +#else stack_t signal_stack; CHECK_EQ(0, sigaltstack(nullptr, &signal_stack)); uptr sigalt_bottom = (uptr)signal_stack.ss_sp; @@ -63,6 +66,7 @@ bool PlatformUnpoisonStacks() { &tls_size); UnpoisonStack(default_bottom, default_bottom + stack_size, "default"); return true; +#endif } // ---------------------- TSD ---------------- {{{1 @@ -111,7 +115,7 @@ void PlatformTSDDtor(void *tsd) { atomic_signal_fence(memory_order_seq_cst); AsanThread::TSDDtor(tsd); } -#else +#elif !SANITIZER_EMSCRIPTEN static pthread_key_t tsd_key; static bool tsd_key_inited = false; void AsanTSDInit(void (*destructor)(void *tsd)) { diff --git a/compiler-rt/lib/asan/asan_rtl.cpp b/compiler-rt/lib/asan/asan_rtl.cpp index 7b5a929963c6a..3acaa74e3f5ea 100644 --- a/compiler-rt/lib/asan/asan_rtl.cpp +++ b/compiler-rt/lib/asan/asan_rtl.cpp @@ -51,6 +51,7 @@ static void AsanDie() { Report("Sleeping for %d second(s)\n", flags()->sleep_before_dying); SleepForSeconds(flags()->sleep_before_dying); } +#if !SANITIZER_EMSCRIPTEN if (flags()->unmap_shadow_on_exit) { if (kMidMemBeg) { UnmapOrDie((void*)kLowShadowBeg, kMidMemBeg - kLowShadowBeg); @@ -60,6 +61,7 @@ static void AsanDie() { UnmapOrDie((void*)kLowShadowBeg, kHighShadowEnd - kLowShadowBeg); } } +#endif } static void AsanCheckFailed(const char *file, int line, const char *cond, @@ -315,7 +317,7 @@ static void asan_atexit() { } static void InitializeHighMemEnd() { -#if !SANITIZER_MYRIAD2 +#if !SANITIZER_MYRIAD2 && !SANITIZER_EMSCRIPTEN #if !ASAN_FIXED_MAPPING kHighMemEnd = GetMaxUserVirtualAddress(); // Increase kHighMemEnd to make sure it's properly @@ -464,7 +466,9 @@ static void AsanInitInternal() { InitializeShadowMemory(); AsanTSDInit(PlatformTSDDtor); +#if !SANITIZER_EMSCRIPTEN InstallDeadlySignalHandlers(AsanOnDeadlySignal); +#endif AllocatorOptions allocator_options; allocator_options.SetFrom(flags(), common_flags()); diff --git a/compiler-rt/lib/asan/asan_shadow_setup.cpp b/compiler-rt/lib/asan/asan_shadow_setup.cpp index 2ead4425add83..9b9e7ae3fe15f 100644 --- a/compiler-rt/lib/asan/asan_shadow_setup.cpp +++ b/compiler-rt/lib/asan/asan_shadow_setup.cpp @@ -13,9 +13,9 @@ #include "sanitizer_common/sanitizer_platform.h" -// asan_fuchsia.cpp and asan_rtems.cpp have their own +// asan_fuchsia.cc, asan_rtems.cc and asan_emscripten.cc have their own // InitializeShadowMemory implementation. -#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_EMSCRIPTEN #include "asan_internal.h" #include "asan_mapping.h" diff --git a/compiler-rt/lib/asan/asan_thread.cpp b/compiler-rt/lib/asan/asan_thread.cpp index 19ac6c1627ca5..a15571b0e4258 100644 --- a/compiler-rt/lib/asan/asan_thread.cpp +++ b/compiler-rt/lib/asan/asan_thread.cpp @@ -101,7 +101,9 @@ void AsanThread::Destroy() { VReport(1, "T%d exited\n", tid); malloc_storage().CommitBack(); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) UnsetAlternateSignalStack(); +#endif asanThreadRegistry().FinishThread(tid); FlushToDeadThreadStats(&stats_); // We also clear the shadow on thread destruction because @@ -257,7 +259,9 @@ thread_return_t AsanThread::ThreadStart(tid_t os_id) { Init(); asanThreadRegistry().StartThread(tid(), os_id, ThreadType::Regular, nullptr); +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif if (!start_routine_) { // start_routine_ == 0 if we're on the main thread or on one of the diff --git a/compiler-rt/lib/interception/interception.h b/compiler-rt/lib/interception/interception.h index cb0b5284ed268..c69a63963798d 100644 --- a/compiler-rt/lib/interception/interception.h +++ b/compiler-rt/lib/interception/interception.h @@ -18,7 +18,8 @@ #if !SANITIZER_LINUX && !SANITIZER_FREEBSD && !SANITIZER_MAC && \ !SANITIZER_NETBSD && !SANITIZER_WINDOWS && \ - !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS + !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && !SANITIZER_SOLARIS && \ + !SANITIZER_EMSCRIPTEN # error "Interception doesn't work on this operating system." #endif @@ -130,7 +131,7 @@ const interpose_substitution substitution_##func_name[] \ extern "C" ret_type func(__VA_ARGS__); # define DECLARE_WRAPPER_WINAPI(ret_type, func, ...) \ extern "C" __declspec(dllimport) ret_type __stdcall func(__VA_ARGS__); -#elif SANITIZER_RTEMS +#elif SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN # define WRAP(x) x # define WRAPPER_NAME(x) #x # define INTERCEPTOR_ATTRIBUTE @@ -162,6 +163,13 @@ const interpose_substitution substitution_##func_name[] \ # define INTERCEPTOR_ATTRIBUTE __attribute__((visibility("default"))) # define REAL(x) __unsanitized_##x # define DECLARE_REAL(ret_type, func, ...) +#elif SANITIZER_EMSCRIPTEN +// Sanitizer runtimes on Emscripten just define functions directly to override +// the libc functions. If the real version is really needed, they can be defined +// with the emscripten_builtin_ prefix. +# define REAL(x) emscripten_builtin_##x +# define DECLARE_REAL(ret_type, func, ...) \ + extern "C" ret_type REAL(func)(__VA_ARGS__); #elif SANITIZER_RTEMS # define REAL(x) __real_ ## x # define DECLARE_REAL(ret_type, func, ...) \ @@ -202,7 +210,8 @@ const interpose_substitution substitution_##func_name[] \ // macros does its job. In exceptional cases you may need to call REAL(foo) // without defining INTERCEPTOR(..., foo, ...). For example, if you override // foo with an interceptor for other function. -#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS +#if !SANITIZER_MAC && !SANITIZER_FUCHSIA && !SANITIZER_RTEMS && \ + !SANITIZER_EMSCRIPTEN # define DEFINE_REAL(ret_type, func, ...) \ typedef ret_type (*FUNC_TYPE(func))(__VA_ARGS__); \ namespace __interception { \ @@ -272,16 +281,16 @@ const interpose_substitution substitution_##func_name[] \ // INTERCEPT_FUNCTION macro, only its name. namespace __interception { #if defined(_WIN64) -typedef unsigned long long uptr; +typedef unsigned long long uptr; // NOLINT #else -typedef unsigned long uptr; +typedef unsigned long uptr; // NOLINT #endif // _WIN64 } // namespace __interception #define INCLUDED_FROM_INTERCEPTION_LIB #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # include "interception_linux.h" # define INTERCEPT_FUNCTION(func) INTERCEPT_FUNCTION_LINUX_OR_FREEBSD(func) diff --git a/compiler-rt/lib/interception/interception_linux.h b/compiler-rt/lib/interception/interception_linux.h index a08f8cb98c409..6d3957e570267 100644 --- a/compiler-rt/lib/interception/interception_linux.h +++ b/compiler-rt/lib/interception/interception_linux.h @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #if SANITIZER_LINUX || SANITIZER_FREEBSD || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #if !defined(INCLUDED_FROM_INTERCEPTION_LIB) # error "interception_linux.h should be included from interception library only" diff --git a/compiler-rt/lib/lsan/lsan.cpp b/compiler-rt/lib/lsan/lsan.cpp index 2c0a3bf0787c2..e1e33c068e1fe 100644 --- a/compiler-rt/lib/lsan/lsan.cpp +++ b/compiler-rt/lib/lsan/lsan.cpp @@ -19,6 +19,11 @@ #include "lsan_common.h" #include "lsan_thread.h" +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + bool lsan_inited; bool lsan_init_is_running; @@ -57,7 +62,11 @@ static void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using LSan. + // You can't run external symbolizers anyway. cf.external_symbolizer_path = GetEnv("LSAN_SYMBOLIZER_PATH"); +#endif cf.malloc_context_size = 30; cf.intercept_tls_get_addr = true; cf.detect_leaks = true; @@ -75,7 +84,22 @@ static void InitializeFlags() { // Override from user-specified string. const char *lsan_default_options = __lsan_default_options(); parser.ParseString(lsan_default_options); - parser.ParseStringFromEnv("LSAN_OPTIONS"); +#if SANITIZER_EMSCRIPTEN + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['LSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#else + parser.ParseString(GetEnv("LSAN_OPTIONS")); +#endif // SANITIZER_EMSCRIPTEN + +#if SANITIZER_EMSCRIPTEN + if (common_flags()->malloc_context_size <= 1) + StackTrace::snapshot_stack = false; +#endif // SANITIZER_EMSCRIPTEN InitializeCommonFlags(); @@ -101,7 +125,10 @@ extern "C" void __lsan_init() { InitTlsSize(); InitializeInterceptors(); InitializeThreadRegistry(); +#if !SANITIZER_EMSCRIPTEN + // Emscripten does not have signals InstallDeadlySignalHandlers(LsanOnDeadlySignal); +#endif InitializeMainThread(); if (common_flags()->detect_leaks && common_flags()->leak_check_at_exit) diff --git a/compiler-rt/lib/lsan/lsan_allocator.cpp b/compiler-rt/lib/lsan/lsan_allocator.cpp index 70422957e6f30..5dff571e4a059 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.cpp +++ b/compiler-rt/lib/lsan/lsan_allocator.cpp @@ -26,7 +26,7 @@ extern "C" void *memset(void *ptr, int value, uptr num); namespace __lsan { -#if defined(__i386__) || defined(__arm__) +#if defined(__i386__) || defined(__arm__) || defined(__wasm32__) static const uptr kMaxAllowedMallocSize = 1UL << 30; #elif defined(__mips64) || defined(__aarch64__) static const uptr kMaxAllowedMallocSize = 4UL << 30; diff --git a/compiler-rt/lib/lsan/lsan_allocator.h b/compiler-rt/lib/lsan/lsan_allocator.h index 17e13cd014ba4..050a9143bc014 100644 --- a/compiler-rt/lib/lsan/lsan_allocator.h +++ b/compiler-rt/lib/lsan/lsan_allocator.h @@ -50,15 +50,22 @@ struct ChunkMetadata { }; #if defined(__mips64) || defined(__aarch64__) || defined(__i386__) || \ - defined(__arm__) + defined(__arm__) || defined(__wasm32__) +static const uptr kRegionSizeLog = 20; +static const uptr kNumRegions = SANITIZER_MMAP_RANGE_SIZE >> kRegionSizeLog; +template +using ByteMapASVT = + TwoLevelByteMap<(kNumRegions >> 12), 1 << 12, AddressSpaceView>; + template struct AP32 { static const uptr kSpaceBeg = 0; static const u64 kSpaceSize = SANITIZER_MMAP_RANGE_SIZE; static const uptr kMetadataSize = sizeof(ChunkMetadata); typedef __sanitizer::CompactSizeClassMap SizeClassMap; - static const uptr kRegionSizeLog = 20; + static const uptr kRegionSizeLog = __lsan::kRegionSizeLog; using AddressSpaceView = AddressSpaceViewTy; + using ByteMap = __lsan::ByteMapASVT; typedef NoOpMapUnmapCallback MapUnmapCallback; static const uptr kFlags = 0; }; diff --git a/compiler-rt/lib/lsan/lsan_common.cpp b/compiler-rt/lib/lsan/lsan_common.cpp index d5b4132b24d58..50a2e1952ecd6 100644 --- a/compiler-rt/lib/lsan/lsan_common.cpp +++ b/compiler-rt/lib/lsan/lsan_common.cpp @@ -25,6 +25,10 @@ #include "sanitizer_common/sanitizer_thread_registry.h" #include "sanitizer_common/sanitizer_tls_get_addr.h" +#if SANITIZER_EMSCRIPTEN +#include "lsan/lsan_allocator.h" +#endif + #if CAN_SANITIZE_LEAKS namespace __lsan { @@ -111,7 +115,7 @@ static const char kStdSuppressions[] = void InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) + suppression_ctx = new (suppression_placeholder) // NOLINT LeakSuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); } @@ -191,7 +195,16 @@ void ScanRangeForPointers(uptr begin, uptr end, uptr pp = begin; if (pp % alignment) pp = pp + alignment - pp % alignment; - for (; pp + sizeof(void *) <= end; pp += alignment) { + + // Emscripten in non-threaded mode stores thread_local variables in the + // same place as normal globals. This means allocator_cache must be skipped + // when scanning globals instead of when scanning thread-locals. +#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__) + uptr cache_begin, cache_end; + GetAllocatorCacheRange(&cache_begin, &cache_end); +#endif + + for (; pp + sizeof(void *) <= end; pp += alignment) { // NOLINT void *p = *reinterpret_cast(pp); if (!CanBeAHeapPointer(reinterpret_cast(p))) continue; uptr chunk = PointsIntoChunk(p); @@ -210,6 +223,14 @@ void ScanRangeForPointers(uptr begin, uptr end, continue; } +#if SANITIZER_EMSCRIPTEN && !defined(__EMSCRIPTEN_PTHREADS__) + if (cache_begin <= pp && pp < cache_end) { + LOG_POINTERS("%p: skipping because it overlaps the cache %p-%p.\n", + pp, cache_begin, cache_end); + continue; + } +#endif + m.set_tag(tag); LOG_POINTERS("%p: found %p pointing into chunk %p-%p of size %zu.\n", pp, p, chunk, chunk + m.requested_size(), m.requested_size()); @@ -274,6 +295,7 @@ static void ProcessThreadRegistry(Frontier *frontier) { } } +#if !SANITIZER_EMSCRIPTEN // Scans thread data (stacks and TLS) for heap pointers. static void ProcessThreads(SuspendedThreadsList const &suspended_threads, Frontier *frontier) { @@ -389,6 +411,7 @@ static void ProcessThreads(SuspendedThreadsList const &suspended_threads, // Add pointers reachable from ThreadContexts ProcessThreadRegistry(frontier); } +#endif // !SANITIZER_EMSCRIPTEN #endif // SANITIZER_FUCHSIA @@ -406,14 +429,22 @@ void ScanRootRegion(Frontier *frontier, const RootRegion &root_region, kReachable); } +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_heap_size(); +#endif + static void ProcessRootRegion(Frontier *frontier, const RootRegion &root_region) { +#if SANITIZER_EMSCRIPTEN + ScanRootRegion(frontier, root_region, 0, emscripten_get_heap_size(), true); +#else MemoryMappingLayout proc_maps(/*cache_enabled*/ true); MemoryMappedSegment segment; while (proc_maps.Next(&segment)) { ScanRootRegion(frontier, root_region, segment.start, segment.end, segment.IsReadable()); } +#endif // SANITIZER_EMSCRIPTEN } // Scans root regions for heap pointers. @@ -535,6 +566,7 @@ static void MarkInvalidPCCb(uptr chunk, void *arg) { // On all other platforms, this simply checks to ensure that the caller pc is // valid before reporting chunks as leaked. void ProcessPC(Frontier *frontier) { +#if !SANITIZER_EMSCRIPTEN StackDepotReverseMap stack_depot_reverse_map; InvalidPCParam arg; arg.frontier = frontier; @@ -542,6 +574,7 @@ void ProcessPC(Frontier *frontier) { arg.skip_linker_allocations = flags()->use_tls && flags()->use_ld_allocations && GetLinker() != nullptr; ForEachChunk(MarkInvalidPCCb, &arg); +#endif } // Sets the appropriate tag on each chunk. @@ -667,7 +700,9 @@ static void CheckForLeaksCallback(const SuspendedThreadsList &suspended_threads, CheckForLeaksParam *param = reinterpret_cast(arg); CHECK(param); CHECK(!param->success); +#if !SANITIZER_EMSCRIPTEN ReportUnsuspendedThreads(suspended_threads); +#endif ClassifyAllChunks(suspended_threads, ¶m->frontier); ForEachChunk(CollectLeaksCb, ¶m->leak_report); // Clean up for subsequent leak checks. This assumes we did not overwrite any @@ -784,8 +819,15 @@ Suppression *LeakSuppressionContext::GetSuppressionForStack( LazyInit(); StackTrace stack = StackDepotGet(stack_trace_id); for (uptr i = 0; i < stack.size; i++) { +#if SANITIZER_EMSCRIPTEN + // On Emscripten, the stack trace is the actual call site, not + // the code that would be executed after the return. + // Therefore, StackTrace::GetPreviousInstructionPc is not needed. + Suppression *s = GetSuppressionForAddr(stack.trace[i]); +#else Suppression *s = GetSuppressionForAddr( StackTrace::GetPreviousInstructionPc(stack.trace[i])); +#endif if (s) { suppressed_stacks_sorted = false; suppressed_stacks.push_back(stack_trace_id); diff --git a/compiler-rt/lib/lsan/lsan_common.h b/compiler-rt/lib/lsan/lsan_common.h index b0ae6f020b63a..809e7e57a9f19 100644 --- a/compiler-rt/lib/lsan/lsan_common.h +++ b/compiler-rt/lib/lsan/lsan_common.h @@ -41,7 +41,7 @@ #define CAN_SANITIZE_LEAKS 1 #elif defined(__arm__) && SANITIZER_LINUX #define CAN_SANITIZE_LEAKS 1 -#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA +#elif SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #define CAN_SANITIZE_LEAKS 1 #else #define CAN_SANITIZE_LEAKS 0 @@ -230,6 +230,10 @@ bool GetThreadRangesLocked(tid_t os_id, uptr *stack_begin, uptr *stack_end, void GetAllThreadAllocatorCachesLocked(InternalMmapVector *caches); void ForEachExtraStackRange(tid_t os_id, RangeIteratorCallback callback, void *arg); +// Scans thread data (stacks and TLS) for heap pointers. +void ProcessThreads(SuspendedThreadsList const &suspended_threads, + Frontier *frontier); + // If called from the main thread, updates the main thread's TID in the thread // registry. We need this to handle processes that fork() without a subsequent // exec(), which invalidates the recorded TID. To update it, we must call diff --git a/compiler-rt/lib/lsan/lsan_common_linux.cpp b/compiler-rt/lib/lsan/lsan_common_linux.cpp index 3af586e220f6c..896f0479cb0a8 100644 --- a/compiler-rt/lib/lsan/lsan_common_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_common_linux.cpp @@ -15,7 +15,7 @@ #include "sanitizer_common/sanitizer_platform.h" #include "lsan_common.h" -#if CAN_SANITIZE_LEAKS && (SANITIZER_LINUX || SANITIZER_NETBSD) +#if CAN_SANITIZE_LEAKS && SANITIZER_LINUX #include #include "sanitizer_common/sanitizer_common.h" diff --git a/compiler-rt/lib/lsan/lsan_interceptors.cpp b/compiler-rt/lib/lsan/lsan_interceptors.cpp index bf8d316770ee1..e90bcb50d0f3a 100644 --- a/compiler-rt/lib/lsan/lsan_interceptors.cpp +++ b/compiler-rt/lib/lsan/lsan_interceptors.cpp @@ -393,6 +393,17 @@ INTERCEPTOR(int, pthread_atfork, void (*prepare)(), void (*parent)(), #define LSAN_MAYBE_INTERCEPT_PTHREAD_ATFORK #endif +#if SANITIZER_EMSCRIPTEN +extern "C" { + int emscripten_builtin_pthread_create(void *thread, void *attr, + void *(*callback)(void *), void *arg); + int emscripten_builtin_pthread_join(void *th, void **ret); + int emscripten_builtin_pthread_detach(void *th); + void *emscripten_builtin_malloc(size_t size); + void emscripten_builtin_free(void *); +} +#endif + #if SANITIZER_INTERCEPT_STRERROR INTERCEPTOR(char *, strerror, int errnum) { __lsan::ScopedInterceptorDisabler disabler; @@ -428,7 +439,11 @@ extern "C" void *__lsan_thread_start_func(void *arg) { while ((tid = atomic_load(&p->tid, memory_order_acquire)) == 0) internal_sched_yield(); ThreadStart(tid, GetTid()); +#if SANITIZER_EMSCRIPTEN + emscripten_builtin_free(p); +#else atomic_store(&p->tid, 0, memory_order_release); +#endif return callback(param); } @@ -444,10 +459,17 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, AdjustStackSize(attr); int detached = 0; pthread_attr_getdetachstate(attr, &detached); +#if SANITIZER_EMSCRIPTEN + ThreadParam *p = (ThreadParam *) emscripten_builtin_malloc(sizeof(ThreadParam)); + p->callback = callback; + p->param = param; + atomic_store(&p->tid, 0, memory_order_relaxed); +#else ThreadParam p; p.callback = callback; p.param = param; atomic_store(&p.tid, 0, memory_order_relaxed); +#endif int res; { // Ignore all allocations made by pthread_create: thread stack/TLS may be @@ -455,15 +477,23 @@ INTERCEPTOR(int, pthread_create, void *th, void *attr, // the linked list it's stored in doesn't even hold valid pointers to the // objects, the latter are calculated by obscure pointer arithmetic. ScopedInterceptorDisabler disabler; +#if SANITIZER_EMSCRIPTEN + res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, p); +#else res = REAL(pthread_create)(th, attr, __lsan_thread_start_func, &p); +#endif } if (res == 0) { int tid = ThreadCreate(GetCurrentThread(), *(uptr *)th, IsStateDetached(detached)); CHECK_NE(tid, 0); +#if SANITIZER_EMSCRIPTEN + atomic_store(&p->tid, tid, memory_order_release); +#else atomic_store(&p.tid, tid, memory_order_release); while (atomic_load(&p.tid, memory_order_acquire) != 0) internal_sched_yield(); +#endif } if (attr == &myattr) pthread_attr_destroy(&myattr); @@ -488,6 +518,7 @@ INTERCEPTOR(int, pthread_detach, void *th) { return res; } +#if !SANITIZER_EMSCRIPTEN INTERCEPTOR(void, _exit, int status) { if (status == 0 && HasReportedLeaks()) status = common_flags()->exitcode; REAL(_exit)(status); @@ -495,14 +526,13 @@ INTERCEPTOR(void, _exit, int status) { #define COMMON_INTERCEPT_FUNCTION(name) INTERCEPT_FUNCTION(name) #include "sanitizer_common/sanitizer_signal_interceptors.inc" - -#endif // SANITIZER_POSIX +#endif namespace __lsan { void InitializeInterceptors() { // Fuchsia doesn't use interceptors that require any setup. -#if !SANITIZER_FUCHSIA +#if !SANITIZER_FUCHSIA && !SANITIZER_EMSCRIPTEN InitializeSignalInterceptors(); INTERCEPT_FUNCTION(malloc); @@ -544,3 +574,4 @@ void InitializeInterceptors() { } } // namespace __lsan +#endif // SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/lsan/lsan_linux.cpp b/compiler-rt/lib/lsan/lsan_linux.cpp index 47c2f21b5a6bc..63ae2c1a945b8 100644 --- a/compiler-rt/lib/lsan/lsan_linux.cpp +++ b/compiler-rt/lib/lsan/lsan_linux.cpp @@ -12,7 +12,7 @@ #include "sanitizer_common/sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA +#if SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN #include "lsan_allocator.h" @@ -29,4 +29,4 @@ void ReplaceSystemMalloc() {} } // namespace __lsan -#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA +#endif // SANITIZER_LINUX || SANITIZER_NETBSD || SANITIZER_FUCHSIA || SANITIZER_EMSCRIPTEN diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h index 192e9392d494a..650cf99128d78 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_errno_codes.h @@ -19,12 +19,15 @@ #ifndef SANITIZER_ERRNO_CODES_H #define SANITIZER_ERRNO_CODES_H +// XXX EMSCRIPTEN: use wasi errno codes, which is what our musl port now uses +#include + namespace __sanitizer { -#define errno_ENOMEM 12 -#define errno_EBUSY 16 -#define errno_EINVAL 22 -#define errno_ENAMETOOLONG 36 +#define errno_ENOMEM __WASI_ERRNO_NOMEM +#define errno_EBUSY __WASI_ERRNO_BUSY +#define errno_EINVAL __WASI_ERRNO_INVAL +#define errno_ENAMETOOLONG __WASI_ERRNO_NAMETOOLONG // Those might not present or their value diff er on diff erent platforms. extern const int errno_EOWNERDEAD; diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h index d8f0540037d24..9e6f406029e0d 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_internal_defs.h @@ -181,7 +181,7 @@ typedef u64 OFF64_T; #if (SANITIZER_WORDSIZE == 64) || SANITIZER_MAC typedef uptr operator_new_size_type; #else -# if defined(__s390__) && !defined(__s390x__) +# if defined(__s390__) && !defined(__s390x__) || SANITIZER_EMSCRIPTEN // Special case: 31-bit s390 has unsigned long as size_t. typedef unsigned long operator_new_size_type; # else diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp index 379f6d9e294b7..d1738e0c2aecf 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.cpp @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_flags.h" @@ -103,9 +103,17 @@ extern struct ps_strings *__ps_strings; #define environ _environ #endif +#if SANITIZER_EMSCRIPTEN +#include +#include +#include +#include +#include +#endif + extern char **environ; -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN // struct kernel_timeval { long tv_sec; @@ -164,7 +172,7 @@ namespace __sanitizer { // --------------- sanitizer_libc.h #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD -#if !SANITIZER_S390 +#if !SANITIZER_S390 && !SANITIZER_EMSCRIPTEN uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, u64 offset) { #if SANITIZER_FREEBSD || SANITIZER_LINUX_USES_64BIT_SYSCALLS @@ -177,8 +185,9 @@ uptr internal_mmap(void *addr, uptr length, int prot, int flags, int fd, offset / 4096); #endif } -#endif // !SANITIZER_S390 +#endif // !SANITIZER_S390 && !SANITIZER_NETBSD +#if !SANITIZER_EMSCRIPTEN uptr internal_munmap(void *addr, uptr length) { return internal_syscall(SYSCALL(munmap), (uptr)addr, length); } @@ -186,13 +195,18 @@ uptr internal_munmap(void *addr, uptr length) { int internal_mprotect(void *addr, uptr length, int prot) { return internal_syscall(SYSCALL(mprotect), (uptr)addr, length, prot); } +#endif int internal_madvise(uptr addr, uptr length, int advice) { return internal_syscall(SYSCALL(madvise), addr, length, advice); } uptr internal_close(fd_t fd) { +#if SANITIZER_EMSCRIPTEN + return __wasi_fd_close(fd); +#else return internal_syscall(SYSCALL(close), fd); +#endif } uptr internal_open(const char *filename, int flags) { @@ -213,27 +227,50 @@ uptr internal_open(const char *filename, int flags, u32 mode) { } uptr internal_read(fd_t fd, void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_iovec_t iov = { (uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_read(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(read), fd, (uptr)buf, count)); return res; +#endif } uptr internal_write(fd_t fd, const void *buf, uptr count) { +#ifdef __EMSCRIPTEN__ + __wasi_ciovec_t iov = { (const uint8_t *)buf, count }; + size_t num; + if (__wasi_syscall_ret(__wasi_fd_write(fd, &iov, 1, &num))) { + return -1; + } + return num; +#else sptr res; HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(write), fd, (uptr)buf, count)); return res; +#endif } uptr internal_ftruncate(fd_t fd, uptr size) { sptr res; +#if SANITIZER_EMSCRIPTEN + HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, + 0, size, 0)); +#else HANDLE_EINTR(res, (sptr)internal_syscall(SYSCALL(ftruncate), fd, (OFF_T)size)); +#endif return res; } -#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX +#if !SANITIZER_LINUX_USES_64BIT_SYSCALLS && SANITIZER_LINUX || SANITIZER_EMSCRIPTEN static void stat64_to_stat(struct stat64 *in, struct stat *out) { internal_memset(out, 0, sizeof(*out)); out->st_dev = in->st_dev; @@ -419,9 +456,14 @@ uptr internal_rename(const char *oldpath, const char *newpath) { } uptr internal_sched_yield() { +#if SANITIZER_EMSCRIPTEN + return 0; +#else return internal_syscall(SYSCALL(sched_yield)); +#endif } +#if !SANITIZER_EMSCRIPTEN unsigned int internal_sleep(unsigned int seconds) { struct timespec ts; ts.tv_sec = seconds; @@ -436,6 +478,7 @@ uptr internal_execve(const char *filename, char *const argv[], return internal_syscall(SYSCALL(execve), (uptr)filename, (uptr)argv, (uptr)envp); } +#endif // !SANITIZER_EMSCRIPTEN #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD #if !SANITIZER_NETBSD @@ -472,11 +515,14 @@ tid_t GetTid() { return Tid; #elif SANITIZER_SOLARIS return thr_self(); +#elif SANITIZER_EMSCRIPTEN + return (tid_t) pthread_self(); #else return internal_syscall(SYSCALL(gettid)); #endif } +#if !SANITIZER_EMSCRIPTEN int TgKill(pid_t pid, tid_t tid, int sig) { #if SANITIZER_LINUX return internal_syscall(SYSCALL(tgkill), pid, tid, sig); @@ -488,8 +534,9 @@ int TgKill(pid_t pid, tid_t tid, int sig) { #endif } #endif +#endif -#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_SOLARIS && !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN u64 NanoTime() { #if SANITIZER_FREEBSD timeval tv; @@ -506,11 +553,19 @@ uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { } #endif // !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if SANITIZER_EMSCRIPTEN +int __clock_gettime(__sanitizer_clockid_t clk_id, void *tp); + +uptr internal_clock_gettime(__sanitizer_clockid_t clk_id, void *tp) { + return __clock_gettime(clk_id, tp); +} +#endif + // Like getenv, but reads env directly from /proc (on Linux) or parses the // 'environ' array (on some others) and does not use libc. This function // should be called first inside __asan_init. const char *GetEnv(const char *name) { -#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN if (::environ != 0) { uptr NameLen = internal_strlen(name); for (char **Env = ::environ; *Env != 0; Env++) { @@ -579,6 +634,7 @@ static void ReadNullSepFileToArray(const char *path, char ***arr, } #endif +#if !SANITIZER_EMSCRIPTEN static void GetArgsAndEnv(char ***argv, char ***envp) { #if SANITIZER_FREEBSD // On FreeBSD, retrieving the argument and environment arrays is done via the @@ -630,6 +686,8 @@ char **GetEnviron() { return envp; } +#endif // !SANITIZER_EMSCRIPTEN + #if !SANITIZER_SOLARIS enum MutexState { MtxUnlocked = 0, @@ -651,6 +709,8 @@ void BlockingMutex::Lock() { _umtx_op(m, UMTX_OP_WAIT_UINT, MtxSleeping, 0, 0); #elif SANITIZER_NETBSD sched_yield(); /* No userspace futex-like synchronization */ +#elif SANITIZER_EMSCRIPTEN + emscripten_futex_wait(m, MtxSleeping, INFINITY); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAIT_PRIVATE, MtxSleeping, 0, 0, 0); @@ -667,6 +727,8 @@ void BlockingMutex::Unlock() { _umtx_op(m, UMTX_OP_WAKE, 1, 0, 0); #elif SANITIZER_NETBSD /* No userspace futex-like synchronization */ +#elif SANITIZER_EMSCRIPTEN + emscripten_futex_wake(m, 1); #else internal_syscall(SYSCALL(futex), (uptr)m, FUTEX_WAKE_PRIVATE, 1, 0, 0, 0); #endif @@ -703,11 +765,13 @@ struct linux_dirent { #endif #if !SANITIZER_SOLARIS && !SANITIZER_NETBSD +#if !SANITIZER_EMSCRIPTEN // Syscall wrappers. uptr internal_ptrace(int request, int pid, void *addr, void *data) { return internal_syscall(SYSCALL(ptrace), request, pid, (uptr)addr, (uptr)data); } +#endif uptr internal_waitpid(int pid, int *status, int options) { return internal_syscall(SYSCALL(wait4), pid, (uptr)status, options, @@ -741,7 +805,12 @@ uptr internal_getdents(fd_t fd, struct linux_dirent *dirp, unsigned int count) { } uptr internal_lseek(fd_t fd, OFF_T offset, int whence) { +#if SANITIZER_EMSCRIPTEN + __wasi_filesize_t result; + return __wasi_syscall_ret(__wasi_fd_seek(fd, offset, whence, &result)) ? -1 : result; +#else return internal_syscall(SYSCALL(lseek), fd, offset, whence); +#endif } #if SANITIZER_LINUX @@ -750,12 +819,17 @@ uptr internal_prctl(int option, uptr arg2, uptr arg3, uptr arg4, uptr arg5) { } #endif +#if !SANITIZER_EMSCRIPTEN uptr internal_sigaltstack(const void *ss, void *oss) { return internal_syscall(SYSCALL(sigaltstack), (uptr)ss, (uptr)oss); } +#endif int internal_fork() { -#if SANITIZER_USES_CANONICAL_LINUX_SYSCALLS +#if SANITIZER_EMSCRIPTEN + Report("fork not supported on emscripten\n"); + return -1; +#elif SANITIZER_USES_CANONICAL_LINUX_SYSCALLS return internal_syscall(SYSCALL(clone), SIGCHLD, 0); #else return internal_syscall(SYSCALL(fork)); @@ -850,6 +924,8 @@ uptr internal_sigprocmask(int how, __sanitizer_sigset_t *set, __sanitizer_sigset_t *oldset) { #if SANITIZER_FREEBSD return internal_syscall(SYSCALL(sigprocmask), how, set, oldset); +#elif SANITIZER_EMSCRIPTEN + return NULL; #else __sanitizer_kernel_sigset_t *k_set = (__sanitizer_kernel_sigset_t *)set; __sanitizer_kernel_sigset_t *k_oldset = (__sanitizer_kernel_sigset_t *)oldset; @@ -899,7 +975,7 @@ bool internal_sigismember(__sanitizer_sigset_t *set, int signum) { #endif #endif // !SANITIZER_SOLARIS -#if !SANITIZER_NETBSD +#if !SANITIZER_NETBSD && !SANITIZER_EMSCRIPTEN // ThreadLister implementation. ThreadLister::ThreadLister(pid_t pid) : pid_(pid), buffer_(4096) { char task_directory_path[80]; @@ -1080,19 +1156,23 @@ uptr GetPageSize() { int rv = internal_sysctl(mib, 2, &pz, &pzl, nullptr, 0); CHECK_EQ(rv, 0); return (uptr)pz; -#elif SANITIZER_USE_GETAUXVAL - return getauxval(AT_PAGESZ); #else return sysconf(_SC_PAGESIZE); // EXEC_PAGESIZE may not be trustworthy. #endif } #endif // !SANITIZER_ANDROID +#if SANITIZER_EMSCRIPTEN +extern "C" uptr emscripten_get_module_name(char *buf, uptr buf_len); +#endif + uptr ReadBinaryName(/*out*/char *buf, uptr buf_len) { #if SANITIZER_SOLARIS const char *default_module_name = getexecname(); CHECK_NE(default_module_name, NULL); return internal_snprintf(buf, buf_len, "%s", default_module_name); +#elif SANITIZER_EMSCRIPTEN + return emscripten_get_module_name(buf, buf_len); #else #if SANITIZER_FREEBSD || SANITIZER_NETBSD #if SANITIZER_FREEBSD @@ -2118,11 +2198,9 @@ static void GetPcSpBp(void *context, uptr *pc, uptr *sp, uptr *bp) { # endif *bp = ucontext->uc_mcontext.gregs[11]; *sp = ucontext->uc_mcontext.gregs[15]; -#elif defined(__riscv) - ucontext_t *ucontext = (ucontext_t*)context; - *pc = ucontext->uc_mcontext.__gregs[REG_PC]; - *bp = ucontext->uc_mcontext.__gregs[REG_S0]; - *sp = ucontext->uc_mcontext.__gregs[REG_SP]; +#elif SANITIZER_EMSCRIPTEN + Report("GetPcSpBp not implemented on emscripten"); + Abort(); #else # error "Unsupported arch" #endif diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h index 24902d1b6bcef..bb432f75aa86a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_linux.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_linux.h @@ -14,7 +14,7 @@ #include "sanitizer_platform.h" #if SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_NETBSD || \ - SANITIZER_SOLARIS + SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN #include "sanitizer_common.h" #include "sanitizer_internal_defs.h" #include "sanitizer_platform_limits_freebsd.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h index 96c01bad870d1..79cb5a2a5deec 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform.h @@ -15,7 +15,7 @@ #if !defined(__linux__) && !defined(__FreeBSD__) && !defined(__NetBSD__) && \ !defined(__APPLE__) && !defined(_WIN32) && \ !defined(__Fuchsia__) && !defined(__rtems__) && \ - !(defined(__sun__) && defined(__svr4__)) + !(defined(__sun__) && defined(__svr4__)) && !defined(__EMSCRIPTEN__) # error "This operating system is not supported" #endif @@ -117,9 +117,15 @@ # define SANITIZER_RTEMS 0 #endif +#if defined(__EMSCRIPTEN__) +# define SANITIZER_EMSCRIPTEN 1 +#else +# define SANITIZER_EMSCRIPTEN 0 +#endif + #define SANITIZER_POSIX \ (SANITIZER_FREEBSD || SANITIZER_LINUX || SANITIZER_MAC || \ - SANITIZER_NETBSD || SANITIZER_SOLARIS) + SANITIZER_NETBSD || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN) #if __LP64__ || defined(_WIN64) # define SANITIZER_WORDSIZE 64 diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h index 068fc9829e57d..ee08024e06987 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_interceptors.h @@ -138,12 +138,24 @@ #define SI_POSIX_NOT_MAC 0 #endif +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN +# define SI_POSIX_NOT_EMSCRIPTEN 1 +#else +# define SI_POSIX_NOT_EMSCRIPTEN 0 +#endif + #if SANITIZER_LINUX && !SANITIZER_FREEBSD #define SI_LINUX_NOT_FREEBSD 1 #else #define SI_LINUX_NOT_FREEBSD 0 #endif +#if SANITIZER_EMSCRIPTEN +# define SI_EMSCRIPTEN 1 +#else +# define SI_EMSCRIPTEN 0 +#endif + #define SANITIZER_INTERCEPT_STRLEN SI_NOT_FUCHSIA #define SANITIZER_INTERCEPT_STRNLEN (SI_NOT_MAC && SI_NOT_FUCHSIA) #define SANITIZER_INTERCEPT_STRCMP SI_NOT_FUCHSIA @@ -266,7 +278,7 @@ #define SANITIZER_INTERCEPT_SENDMMSG SI_LINUX #define SANITIZER_INTERCEPT_SYSMSG SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_GETPEERNAME SI_POSIX -#define SANITIZER_INTERCEPT_IOCTL SI_POSIX +#define SANITIZER_INTERCEPT_IOCTL SI_POSIX && !SI_EMSCRIPTEN #define SANITIZER_INTERCEPT_INET_ATON SI_POSIX #define SANITIZER_INTERCEPT_SYSINFO SI_LINUX #define SANITIZER_INTERCEPT_READDIR SI_POSIX @@ -304,7 +316,7 @@ (SI_FREEBSD || SI_NETBSD || SI_MAC || SI_LINUX_NOT_ANDROID || SI_SOLARIS) #define SANITIZER_INTERCEPT_SCHED_GETAFFINITY SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCHED_GETPARAM SI_LINUX_NOT_ANDROID || SI_SOLARIS -#define SANITIZER_INTERCEPT_STRERROR SI_POSIX +#define SANITIZER_INTERCEPT_STRERROR SI_POSIX_NOT_EMSCRIPTEN #define SANITIZER_INTERCEPT_STRERROR_R SI_POSIX #define SANITIZER_INTERCEPT_XPG_STRERROR_R SI_LINUX_NOT_ANDROID #define SANITIZER_INTERCEPT_SCANDIR \ diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp index 12dd39e674ac8..fe8b04a9c4880 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.cpp @@ -11,7 +11,7 @@ // Sizes and layouts of platform-specific POSIX data structures. //===----------------------------------------------------------------------===// -#if defined(__linux__) || defined(__APPLE__) +#if defined(__linux__) || defined(__APPLE__) || defined(__EMSCRIPTEN__) // Tests in this file assume that off_t-dependent data structures match the // libc ABI. For example, struct dirent here is what readdir() function (as // exported from libc) returns, and not the user-facing "dirent", which @@ -23,7 +23,7 @@ // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_platform.h" -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN // Must go after undef _FILE_OFFSET_BITS. #include "sanitizer_glibc_version.h" @@ -59,7 +59,7 @@ #include #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN #include #include #include @@ -160,7 +160,7 @@ typedef struct user_fpregs elf_fpregset_t; #include #include #include -#else +#elif !SANITIZER_EMSCRIPTEN #include #endif // SANITIZER_LINUX @@ -211,7 +211,7 @@ namespace __sanitizer { #if SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC unsigned struct_fstab_sz = sizeof(struct fstab); #endif // SANITIZER_GLIBC || SANITIZER_FREEBSD || SANITIZER_NETBSD || SANITIZER_MAC -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN unsigned struct_statfs_sz = sizeof(struct statfs); unsigned struct_sockaddr_sz = sizeof(struct sockaddr); unsigned ucontext_t_sz = sizeof(ucontext_t); @@ -403,7 +403,10 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); // ioctl arguments unsigned struct_ifreq_sz = sizeof(struct ifreq); unsigned struct_termios_sz = sizeof(struct termios); + +#if !SANITIZER_EMSCRIPTEN unsigned struct_winsize_sz = sizeof(struct winsize); +#endif #if SANITIZER_LINUX unsigned struct_arpreq_sz = sizeof(struct arpreq); @@ -485,15 +488,18 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned struct_ppp_stats_sz = sizeof(struct ppp_stats); #endif // SANITIZER_GLIBC -#if !SANITIZER_ANDROID && !SANITIZER_MAC +#if !SANITIZER_ANDROID && !SANITIZER_MAC && !SANITIZER_EMSCRIPTEN unsigned struct_sioc_sg_req_sz = sizeof(struct sioc_sg_req); unsigned struct_sioc_vif_req_sz = sizeof(struct sioc_vif_req); #endif +#if !SANITIZER_EMSCRIPTEN const unsigned long __sanitizer_bufsiz = BUFSIZ; +#endif const unsigned IOCTL_NOT_PRESENT = 0; +#if !SANITIZER_EMSCRIPTEN unsigned IOCTL_FIOASYNC = FIOASYNC; unsigned IOCTL_FIOCLEX = FIOCLEX; unsigned IOCTL_FIOGETOWN = FIOGETOWN; @@ -542,6 +548,7 @@ unsigned struct_ElfW_Phdr_sz = sizeof(Elf_Phdr); unsigned IOCTL_SIOCGETSGCNT = SIOCGETSGCNT; unsigned IOCTL_SIOCGETVIFCNT = SIOCGETVIFCNT; #endif +#endif #if SANITIZER_LINUX unsigned IOCTL_EVIOCGABS = EVIOCGABS(0); @@ -1044,6 +1051,7 @@ CHECK_SIZE_AND_OFFSET(mmsghdr, msg_len); #endif COMPILER_CHECK(sizeof(__sanitizer_dirent) <= sizeof(dirent)); +#if !SANITIZER_EMSCRIPTEN CHECK_SIZE_AND_OFFSET(dirent, d_ino); #if SANITIZER_MAC CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); @@ -1053,6 +1061,7 @@ CHECK_SIZE_AND_OFFSET(dirent, d_seekoff); CHECK_SIZE_AND_OFFSET(dirent, d_off); #endif CHECK_SIZE_AND_OFFSET(dirent, d_reclen); +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX && !SANITIZER_ANDROID COMPILER_CHECK(sizeof(__sanitizer_dirent64) <= sizeof(dirent64)); @@ -1072,6 +1081,7 @@ CHECK_SIZE_AND_OFFSET(pollfd, revents); CHECK_TYPE_SIZE(nfds_t); +#if !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(sigset_t); COMPILER_CHECK(sizeof(__sanitizer_sigaction) == sizeof(struct sigaction)); @@ -1086,6 +1096,7 @@ CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_flags); #if SANITIZER_LINUX && (!SANITIZER_ANDROID || !SANITIZER_MIPS32) CHECK_STRUCT_SIZE_AND_OFFSET(sigaction, sa_restorer); #endif +#endif // !SANITIZER_EMSCRIPTEN #if SANITIZER_LINUX CHECK_TYPE_SIZE(__sysctl_args); @@ -1139,7 +1150,9 @@ CHECK_SIZE_AND_OFFSET(mntent, mnt_freq); CHECK_SIZE_AND_OFFSET(mntent, mnt_passno); #endif +#if !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ether_addr); +#endif #if SANITIZER_GLIBC || SANITIZER_FREEBSD CHECK_TYPE_SIZE(ipc_perm); @@ -1177,7 +1190,7 @@ CHECK_TYPE_SIZE(clock_t); CHECK_TYPE_SIZE(clockid_t); #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(ifaddrs); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_next); CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_name); @@ -1207,7 +1220,7 @@ CHECK_SIZE_AND_OFFSET(ifaddrs, ifa_data); COMPILER_CHECK(sizeof(__sanitizer_struct_mallinfo) == sizeof(struct mallinfo)); #endif -#if !SANITIZER_ANDROID +#if !SANITIZER_ANDROID && !SANITIZER_EMSCRIPTEN CHECK_TYPE_SIZE(timeb); CHECK_SIZE_AND_OFFSET(timeb, time); CHECK_SIZE_AND_OFFSET(timeb, millitm); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h index 836b178c131ba..769fe36a90f78 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_platform_limits_posix.h @@ -14,7 +14,7 @@ #ifndef SANITIZER_PLATFORM_LIMITS_POSIX_H #define SANITIZER_PLATFORM_LIMITS_POSIX_H -#if SANITIZER_LINUX || SANITIZER_MAC +#if SANITIZER_LINUX || SANITIZER_MAC || SANITIZER_EMSCRIPTEN #include "sanitizer_internal_defs.h" #include "sanitizer_platform.h" @@ -506,7 +506,7 @@ typedef long long __sanitizer_clock_t; typedef long __sanitizer_clock_t; #endif -#if SANITIZER_LINUX +#if SANITIZER_LINUX || SANITIZER_EMSCRIPTEN typedef int __sanitizer_clockid_t; #endif @@ -559,6 +559,8 @@ struct __sanitizer_sigset_t { // The size is determined by looking at sizeof of real sigset_t on linux. uptr val[128 / sizeof(uptr)]; }; +#elif SANITIZER_EMSCRIPTEN +typedef unsigned long __sanitizer_sigset_t; #endif struct __sanitizer_siginfo { diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp index 2e080098283fd..fd9025882db1e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix.cpp @@ -220,6 +220,16 @@ static inline bool IntervalsAreSeparate(uptr start1, uptr end1, return (end1 < start2) || (end2 < start1); } +#if SANITIZER_EMSCRIPTEN +bool MemoryRangeIsAvailable(uptr /*range_start*/, uptr /*range_end*/) { + // TODO: actually implement this. + return true; +} + +void DumpProcessMap() { + Report("Cannot dump memory map on emscripten"); +} +#else // FIXME: this is thread-unsafe, but should not cause problems most of the time. // When the shadow is mapped only a single thread usually exists (plus maybe // several worker threads on Mac, which aren't expected to map big chunks of @@ -254,6 +264,7 @@ void DumpProcessMap() { UnmapOrDie(filename, kBufSize); } #endif +#endif const char *GetPwd() { return GetEnv("PWD"); @@ -274,6 +285,10 @@ void ReportFile::Write(const char *buffer, uptr length) { } bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { +#if SANITIZER_EMSCRIPTEN + // Code is not mapped in memory in Emscripten, so this operation is meaningless + // and thus always fails. +#else MemoryMappingLayout proc_maps(/*cache_enabled*/false); InternalScopedString buff(kMaxPathLength); MemoryMappedSegment segment(buff.data(), kMaxPathLength); @@ -285,6 +300,7 @@ bool GetCodeRangeForFile(const char *module, uptr *start, uptr *end) { return true; } } +#endif return false; } diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp index d29438cf9dbd5..623c9e361701a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_posix_libcdep.cpp @@ -211,7 +211,9 @@ void InstallDeadlySignalHandlers(SignalHandlerType handler) { // Set the alternate signal stack for the main thread. // This will cause SetAlternateSignalStack to be called twice, but the stack // will be actually set only once. +#if !SANITIZER_EMSCRIPTEN if (common_flags()->use_sigaltstack) SetAlternateSignalStack(); +#endif MaybeInstallSigaction(SIGSEGV, handler); MaybeInstallSigaction(SIGBUS, handler); MaybeInstallSigaction(SIGABRT, handler); @@ -271,6 +273,11 @@ bool SignalContext::IsStackOverflow() const { #endif // SANITIZER_GO bool IsAccessibleMemoryRange(uptr beg, uptr size) { +#if SANITIZER_EMSCRIPTEN + // Avoid pulling in __sys_pipe for the trick below, which doesn't work on + // WebAssembly anyways because there are no memory protections. + return true; +#else uptr page_size = GetPageSizeCached(); // Checking too large memory ranges is slow. CHECK_LT(size, page_size * 10); @@ -290,6 +297,7 @@ bool IsAccessibleMemoryRange(uptr beg, uptr size) { internal_close(sock_pair[0]); internal_close(sock_pair[1]); return result; +#endif // SANITIZER_EMSCRIPTEN } void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { @@ -297,7 +305,9 @@ void PlatformPrepareForSandboxing(__sanitizer_sandbox_arguments *args) { // to read the file mappings from /proc/self/maps. Luckily, neither the // process will be able to load additional libraries, so it's fine to use the // cached mappings. +#ifndef SANITIZER_EMSCRIPTEN MemoryMappingLayout::CacheMemoryMappings(); +#endif } static bool MmapFixed(uptr fixed_addr, uptr size, int additional_flags, diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp index b0487d8987db2..d84d9c9fba93c 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.cpp @@ -50,9 +50,11 @@ uptr StackTrace::GetNextInstructionPc(uptr pc) { #endif } +#if !defined(__EMSCRIPTEN__) uptr StackTrace::GetCurrentPc() { return GET_CALLER_PC(); } +#endif void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { size = cnt + !!extra_top_pc; @@ -63,8 +65,8 @@ void BufferedStackTrace::Init(const uptr *pcs, uptr cnt, uptr extra_top_pc) { top_frame_bp = 0; } -// Sparc implemention is in its own file. -#if !defined(__sparc__) +// Sparc and Emscripten implementions are in their own files. +#if !defined(__sparc__) && !defined(__EMSCRIPTEN__) // In GCC on ARM bp points to saved lr, not fp, so we should check the next // cell in stack to be a saved frame pointer. GetCanonicFrame returns the diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h index 15616f899d01e..03d4d2dd1568e 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace.h @@ -32,7 +32,7 @@ static const u32 kStackTraceMax = 256; // Fast unwind is the only option on Mac for now; we will need to // revisit this macro when slow unwind works on Mac, see // https://github.com/google/sanitizers/issues/137 -#if SANITIZER_MAC || SANITIZER_RTEMS +#if SANITIZER_MAC || SANITIZER_RTEMS || SANITIZER_EMSCRIPTEN # define SANITIZER_CAN_SLOW_UNWIND 0 #else # define SANITIZER_CAN_SLOW_UNWIND 1 @@ -64,6 +64,9 @@ struct StackTrace { return request_fast_unwind; } +#if SANITIZER_EMSCRIPTEN + static bool snapshot_stack; +#endif static uptr GetCurrentPc(); static inline uptr GetPreviousInstructionPc(uptr pc); static uptr GetNextInstructionPc(uptr pc); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp index 7808ba9b0f572..d0ef5f31547fa 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_stacktrace_libcdep.cpp @@ -29,9 +29,15 @@ void StackTrace::Print() const { bool symbolize = RenderNeedsSymbolization(common_flags()->stack_trace_format); uptr frame_num = 0; for (uptr i = 0; i < size && trace[i]; i++) { +#if !SANITIZER_EMSCRIPTEN // PCs in stack traces are actually the return addresses, that is, // addresses of the next instructions after the call. uptr pc = GetPreviousInstructionPc(trace[i]); +#else + // On Emscripten, the stack traces are obtained from JavaScript, and the + // addresses are not return addresses. + uptr pc = trace[i]; +#endif SymbolizedStack *frames; if (symbolize) frames = Symbolizer::GetOrInit()->SymbolizePC(pc); diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp index 4dd5cc3ad7cbe..ef7635cf792b4 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_posix_libcdep.cpp @@ -12,7 +12,7 @@ //===----------------------------------------------------------------------===// #include "sanitizer_platform.h" -#if SANITIZER_POSIX +#if SANITIZER_POSIX && !SANITIZER_EMSCRIPTEN #include "sanitizer_allocator_internal.h" #include "sanitizer_common.h" #include "sanitizer_file.h" diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp index c99a6ceaa5623..1e3d16141b80a 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp +++ b/compiler-rt/lib/sanitizer_common/sanitizer_symbolizer_report.cpp @@ -40,7 +40,21 @@ void ReportErrorSummary(const char *error_type, const AddressInfo &info, } #endif -#if !SANITIZER_FUCHSIA +#if SANITIZER_EMSCRIPTEN +#include + +static inline bool ReportSupportsColors() { + return !!EM_ASM_INT({ + var setting = Module['printWithColors']; + if (setting != null) { + return setting; + } else { + return ENVIRONMENT_IS_NODE && process.stderr.isTTY; + } + }); +} + +#elif !SANITIZER_FUCHSIA bool ReportFile::SupportsColors() { SpinMutexLock l(mu); @@ -57,7 +71,7 @@ static inline bool ReportSupportsColors() { // Fuchsia's logs always go through post-processing that handles colorization. static inline bool ReportSupportsColors() { return true; } -#endif // !SANITIZER_FUCHSIA +#endif // SANITIZER_EMSCRIPTEN, !SANITIZER_FUCHSIA bool ColorizeReports() { // FIXME: Add proper Windows support to AnsiColorDecorator and re-enable color diff --git a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc index 8829985b5b07f..ba7ed46f861cc 100644 --- a/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc +++ b/compiler-rt/lib/sanitizer_common/sanitizer_syscall_generic.inc @@ -13,7 +13,7 @@ // NetBSD uses libc calls directly #if !SANITIZER_NETBSD -#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS +#if SANITIZER_FREEBSD || SANITIZER_MAC || SANITIZER_SOLARIS || SANITIZER_EMSCRIPTEN # define SYSCALL(name) SYS_ ## name #else # define SYSCALL(name) __NR_ ## name diff --git a/compiler-rt/lib/ubsan/ubsan_checks.inc b/compiler-rt/lib/ubsan/ubsan_checks.inc index 846cd89ee19f8..4e0c2bcf0e65f 100644 --- a/compiler-rt/lib/ubsan/ubsan_checks.inc +++ b/compiler-rt/lib/ubsan/ubsan_checks.inc @@ -20,11 +20,6 @@ UBSAN_CHECK(GenericUB, "undefined-behavior", "undefined") UBSAN_CHECK(NullPointerUse, "null-pointer-use", "null") UBSAN_CHECK(NullPointerUseWithNullability, "null-pointer-use", "nullability-assign") -UBSAN_CHECK(NullptrWithOffset, "nullptr-with-offset", "pointer-overflow") -UBSAN_CHECK(NullptrWithNonZeroOffset, "nullptr-with-nonzero-offset", - "pointer-overflow") -UBSAN_CHECK(NullptrAfterNonZeroOffset, "nullptr-after-nonzero-offset", - "pointer-overflow") UBSAN_CHECK(PointerOverflow, "pointer-overflow", "pointer-overflow") UBSAN_CHECK(MisalignedPointerUse, "misaligned-pointer-use", "alignment") UBSAN_CHECK(AlignmentAssumption, "alignment-assumption", "alignment") diff --git a/compiler-rt/lib/ubsan/ubsan_diag.cpp b/compiler-rt/lib/ubsan/ubsan_diag.cpp index 1b2828d236d6e..c8f7960db42ac 100644 --- a/compiler-rt/lib/ubsan/ubsan_diag.cpp +++ b/compiler-rt/lib/ubsan/ubsan_diag.cpp @@ -404,7 +404,7 @@ static const char *kSuppressionTypes[] = { void __ubsan::InitializeSuppressions() { CHECK_EQ(nullptr, suppression_ctx); - suppression_ctx = new (suppression_placeholder) + suppression_ctx = new (suppression_placeholder) // NOLINT SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes)); suppression_ctx->ParseFromFile(flags()->suppressions); } diff --git a/compiler-rt/lib/ubsan/ubsan_flags.cpp b/compiler-rt/lib/ubsan/ubsan_flags.cpp index 25cefd46ce27c..48bb217d45695 100644 --- a/compiler-rt/lib/ubsan/ubsan_flags.cpp +++ b/compiler-rt/lib/ubsan/ubsan_flags.cpp @@ -19,6 +19,11 @@ #include +#if SANITIZER_EMSCRIPTEN +extern "C" void emscripten_builtin_free(void *); +#include +#endif + namespace __ubsan { static const char *GetFlag(const char *flag) { @@ -50,7 +55,12 @@ void InitializeFlags() { { CommonFlags cf; cf.CopyFrom(*common_flags()); + cf.print_summary = false; +#if !SANITIZER_EMSCRIPTEN + // getenv on emscripten uses malloc, which we can't when using some sanitizers. + // You can't run external symbolizers anyway. cf.external_symbolizer_path = GetFlag("UBSAN_SYMBOLIZER_PATH"); +#endif OverrideCommonFlags(cf); } @@ -64,7 +74,18 @@ void InitializeFlags() { // Override from user-specified string. parser.ParseString(__ubsan_default_options()); // Override from environment variable. +#if SANITIZER_EMSCRIPTEN + char *options = (char*) EM_ASM_INT({ + return withBuiltinMalloc(function () { + return allocateUTF8(Module['UBSAN_OPTIONS'] || 0); + }); + }); + parser.ParseString(options); + emscripten_builtin_free(options); +#else parser.ParseStringFromEnv("UBSAN_OPTIONS"); +#endif // SANITIZER_EMSCRIPTEN + InitializeCommonFlags(); if (Verbosity()) ReportUnrecognizedFlags(); diff --git a/compiler-rt/lib/ubsan/ubsan_handlers.cpp b/compiler-rt/lib/ubsan/ubsan_handlers.cpp index e201e6bba2207..b070a378c0d47 100644 --- a/compiler-rt/lib/ubsan/ubsan_handlers.cpp +++ b/compiler-rt/lib/ubsan/ubsan_handlers.cpp @@ -766,33 +766,14 @@ static void handlePointerOverflowImpl(PointerOverflowData *Data, ValueHandle Result, ReportOptions Opts) { SourceLocation Loc = Data->Loc.acquire(); - ErrorType ET; - - if (Base == 0 && Result == 0) - ET = ErrorType::NullptrWithOffset; - else if (Base == 0 && Result != 0) - ET = ErrorType::NullptrWithNonZeroOffset; - else if (Base != 0 && Result == 0) - ET = ErrorType::NullptrAfterNonZeroOffset; - else - ET = ErrorType::PointerOverflow; + ErrorType ET = ErrorType::PointerOverflow; if (ignoreReport(Loc, Opts, ET)) return; ScopedReport R(Opts, Loc, ET); - if (ET == ErrorType::NullptrWithOffset) { - Diag(Loc, DL_Error, ET, "applying zero offset to null pointer"); - } else if (ET == ErrorType::NullptrWithNonZeroOffset) { - Diag(Loc, DL_Error, ET, "applying non-zero offset %0 to null pointer") - << Result; - } else if (ET == ErrorType::NullptrAfterNonZeroOffset) { - Diag( - Loc, DL_Error, ET, - "applying non-zero offset to non-null pointer %0 produced null pointer") - << (void *)Base; - } else if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { + if ((sptr(Base) >= 0) == (sptr(Result) >= 0)) { if (Base > Result) Diag(Loc, DL_Error, ET, "addition of unsigned offset to %0 overflowed to %1") diff --git a/compiler-rt/lib/ubsan/ubsan_platform.h b/compiler-rt/lib/ubsan/ubsan_platform.h index 32d949d75b9c0..82efd0c3414ee 100644 --- a/compiler-rt/lib/ubsan/ubsan_platform.h +++ b/compiler-rt/lib/ubsan/ubsan_platform.h @@ -16,7 +16,8 @@ #if defined(__linux__) || defined(__FreeBSD__) || defined(__APPLE__) || \ defined(__NetBSD__) || \ (defined(__sun__) && defined(__svr4__)) || \ - defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) + defined(_WIN32) || defined(__Fuchsia__) || defined(__rtems__) || \ + defined(__EMSCRIPTEN__) # define CAN_SANITIZE_UB 1 #else # define CAN_SANITIZE_UB 0 diff --git a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp index 2c91db8ca3974..8d980e1a26391 100644 --- a/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp +++ b/compiler-rt/lib/ubsan/ubsan_signals_standalone.cpp @@ -26,7 +26,7 @@ // debuggerd handler, but before the ART handler. // * Interceptors don't work at all when ubsan runtime is loaded late, ex. when // it is part of an APK that does not use wrap.sh method. -#if SANITIZER_FUCHSIA || SANITIZER_ANDROID +#if SANITIZER_FUCHSIA || SANITIZER_ANDROID || SANITIZER_EMSCRIPTEN namespace __ubsan { void InitializeDeadlySignals() {} @@ -45,9 +45,8 @@ namespace __ubsan { static void OnStackUnwind(const SignalContext &sig, const void *, BufferedStackTrace *stack) { - ubsan_GetStackTrace(stack, kStackTraceMax, - StackTrace::GetNextInstructionPc(sig.pc), sig.bp, - sig.context, common_flags()->fast_unwind_on_fatal); + ubsan_GetStackTrace(stack, kStackTraceMax, sig.pc, sig.bp, sig.context, + common_flags()->fast_unwind_on_fatal); } static void UBsanOnDeadlySignal(int signo, void *siginfo, void *context) { diff --git a/libcxx/include/__config b/libcxx/include/__config index a3838c89e8e16..f3df1c770dfc8 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -1,3 +1,6 @@ +// XXX EMSCRIPTEN: macros that would ordinarily be added from __config_site.in +#define _LIBCPP_HAS_NO_VENDOR_AVAILABILITY_ANNOTATIONS + // -*- C++ -*- //===--------------------------- __config ---------------------------------===// // @@ -101,7 +104,8 @@ // Previously libc++ used "unsigned int" exclusively. # define _LIBCPP_ABI_VARIANT_INDEX_TYPE_OPTIMIZATION // Unstable attempt to provide a more optimized std::function -# define _LIBCPP_ABI_OPTIMIZED_FUNCTION +// XXX EMSCRIPTEN https://github.com/emscripten-core/emscripten/issues/11022 +//# define _LIBCPP_ABI_OPTIMIZED_FUNCTION // All the regex constants must be distinct and nonzero. # define _LIBCPP_ABI_REGEX_CONSTANTS_NONZERO // Re-worked external template instantiations for std::string with a focus on @@ -318,7 +322,7 @@ // random data even when using sandboxing mechanisms such as chroots, // Capsicum, etc. # define _LIBCPP_USING_ARC4_RANDOM -#elif defined(__Fuchsia__) || defined(__wasi__) +#elif defined(__Fuchsia__) || defined(__wasi__) || defined(__EMSCRIPTEN__) # define _LIBCPP_USING_GETENTROPY #elif defined(__native_client__) // NaCl's sandbox (which PNaCl also runs in) doesn't allow filesystem access, @@ -920,7 +924,7 @@ typedef unsigned int char32_t; #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) // Most unix variants have catopen. These are the specific ones that don't. -# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) +# if !defined(__BIONIC__) && !defined(_NEWLIB_VERSION) && !defined(__EMSCRIPTEN__) // XXX Emscripten catopen always returns -1 # define _LIBCPP_HAS_CATOPEN 1 # endif #endif @@ -1132,6 +1136,7 @@ extern "C" _LIBCPP_FUNC_VIS void __sanitizer_annotate_contiguous_container( defined(__CloudABI__) || \ defined(__sun__) || \ defined(__MVS__) || \ + defined(__EMSCRIPTEN__) || \ (defined(__MINGW32__) && __has_include()) # define _LIBCPP_HAS_THREAD_API_PTHREAD # elif defined(__Fuchsia__) diff --git a/libcxx/include/typeinfo b/libcxx/include/typeinfo index 048e57614affd..5f43b4df3b6a5 100644 --- a/libcxx/include/typeinfo +++ b/libcxx/include/typeinfo @@ -324,6 +324,9 @@ public: return __impl::__hash(__type_name); } + // XXX Emscripten: adding `always_inline` fixes + // https://github.com/emscripten-core/emscripten/issues/13330 + __attribute__((always_inline)) _LIBCPP_INLINE_VISIBILITY bool operator==(const type_info& __arg) const _NOEXCEPT { diff --git a/libcxx/src/include/config_elast.h b/libcxx/src/include/config_elast.h index 3113f9fb5cd17..c5df5423ef140 100644 --- a/libcxx/src/include/config_elast.h +++ b/libcxx/src/include/config_elast.h @@ -33,6 +33,8 @@ #define _LIBCPP_ELAST 4095 #elif defined(__APPLE__) // No _LIBCPP_ELAST needed on Apple +#elif defined(__EMSCRIPTEN__) // XXX EMSCRIPTEN added ELAST value +#define _LIBCPP_ELAST 256 #elif defined(__sun__) #define _LIBCPP_ELAST ESTALE #elif defined(_LIBCPP_MSVCRT_LIKE) diff --git a/libcxx/src/new.cpp b/libcxx/src/new.cpp index 9d01330ba7d5f..c2faf3d92a5cc 100644 --- a/libcxx/src/new.cpp +++ b/libcxx/src/new.cpp @@ -74,8 +74,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCPP_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; diff --git a/libcxx/src/support/runtime/exception_fallback.ipp b/libcxx/src/support/runtime/exception_fallback.ipp index faa112f7f3a43..376a0381f5452 100644 --- a/libcxx/src/support/runtime/exception_fallback.ipp +++ b/libcxx/src/support/runtime/exception_fallback.ipp @@ -49,6 +49,7 @@ get_terminate() _NOEXCEPT return __libcpp_atomic_load(&__terminate_handler); } +#ifndef __EMSCRIPTEN__ // We provide this in JS _LIBCPP_NORETURN void terminate() _NOEXCEPT @@ -71,7 +72,9 @@ terminate() _NOEXCEPT } #endif // _LIBCPP_NO_EXCEPTIONS } +#endif // !__EMSCRIPTEN__ +#if !defined(__EMSCRIPTEN__) bool uncaught_exception() _NOEXCEPT { return uncaught_exceptions() > 0; } int uncaught_exceptions() _NOEXCEPT @@ -80,6 +83,7 @@ int uncaught_exceptions() _NOEXCEPT fprintf(stderr, "uncaught_exceptions not yet implemented\n"); ::abort(); } +#endif // !__EMSCRIPTEN__ exception::~exception() _NOEXCEPT diff --git a/libcxxabi/include/cxxabi.h b/libcxxabi/include/cxxabi.h index 43ce6f5f740d5..8b5368150b8e3 100644 --- a/libcxxabi/include/cxxabi.h +++ b/libcxxabi/include/cxxabi.h @@ -40,20 +40,24 @@ extern "C" { // 2.4.2 Allocating the Exception Object extern _LIBCXXABI_FUNC_VIS void * -__cxa_allocate_exception(size_t thrown_size) throw(); +__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_free_exception(void *thrown_exception) throw(); +__cxa_free_exception(void *thrown_exception) _NOEXCEPT; // 2.4.3 Throwing the Exception Object extern _LIBCXXABI_FUNC_VIS _LIBCXXABI_NORETURN void __cxa_throw(void *thrown_exception, std::type_info *tinfo, +#ifdef __USING_WASM_EXCEPTIONS__ + void *(*dest)(void *)); +#else void (*dest)(void *)); +#endif // 2.5.3 Exception Handlers extern _LIBCXXABI_FUNC_VIS void * -__cxa_get_exception_ptr(void *exceptionObject) throw(); +__cxa_get_exception_ptr(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void * -__cxa_begin_catch(void *exceptionObject) throw(); +__cxa_begin_catch(void *exceptionObject) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_end_catch(); #if defined(_LIBCXXABI_ARM_EHABI) extern _LIBCXXABI_FUNC_VIS bool @@ -148,17 +152,17 @@ extern _LIBCXXABI_FUNC_VIS char *__cxa_demangle(const char *mangled_name, // Apple additions to support C++ 0x exception_ptr class // These are primitives to wrap a smart pointer around an exception object -extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() throw(); +extern _LIBCXXABI_FUNC_VIS void *__cxa_current_primary_exception() _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void __cxa_rethrow_primary_exception(void *primary_exception); extern _LIBCXXABI_FUNC_VIS void -__cxa_increment_exception_refcount(void *primary_exception) throw(); +__cxa_increment_exception_refcount(void *primary_exception) _NOEXCEPT; extern _LIBCXXABI_FUNC_VIS void -__cxa_decrement_exception_refcount(void *primary_exception) throw(); +__cxa_decrement_exception_refcount(void *primary_exception) _NOEXCEPT; // Apple extension to support std::uncaught_exception() -extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() throw(); -extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() throw(); +extern _LIBCXXABI_FUNC_VIS bool __cxa_uncaught_exception() _NOEXCEPT; +extern _LIBCXXABI_FUNC_VIS unsigned int __cxa_uncaught_exceptions() _NOEXCEPT; #if defined(__linux__) || defined(__Fuchsia__) // Linux and Fuchsia TLS support. Not yet an official part of the Itanium ABI. diff --git a/libcxxabi/src/abort_message.cpp b/libcxxabi/src/abort_message.cpp index ad44063facb71..4aa4f71321428 100644 --- a/libcxxabi/src/abort_message.cpp +++ b/libcxxabi/src/abort_message.cpp @@ -33,12 +33,21 @@ void abort_message(const char* format, ...) // formatting into the variable-sized buffer fails. #if !defined(NDEBUG) || !defined(LIBCXXABI_BAREMETAL) { +#if defined(__EMSCRIPTEN__) && defined(NDEBUG) + // Just trap in a non-debug build. These internal libcxxabi assertions are + // very rare, and it's not worth linking in vfprintf stdio support or + // even minimal logging for them, as we'll have a proper call stack, which + // will show a call into "abort_message", and can help debugging. (In a + // debug build that won't be inlined.) + __builtin_trap(); +#else fprintf(stderr, "libc++abi: "); va_list list; va_start(list, format); vfprintf(stderr, format, list); va_end(list); fprintf(stderr, "\n"); +#endif } #endif diff --git a/libcxxabi/src/cxa_exception.cpp b/libcxxabi/src/cxa_exception.cpp index ebb05ce54213d..2a7483cb4a986 100644 --- a/libcxxabi/src/cxa_exception.cpp +++ b/libcxxabi/src/cxa_exception.cpp @@ -180,7 +180,7 @@ extern "C" { // object. Zero-fill the object. If memory can't be allocated, call // std::terminate. Return a pointer to the memory to be used for the // user's exception object. -void *__cxa_allocate_exception(size_t thrown_size) throw() { +void *__cxa_allocate_exception(size_t thrown_size) _NOEXCEPT { size_t actual_size = cxa_exception_size_from_exception_thrown_size(thrown_size); // Allocate extra space before the __cxa_exception header to ensure the @@ -198,7 +198,7 @@ void *__cxa_allocate_exception(size_t thrown_size) throw() { // Free a __cxa_exception object allocated with __cxa_allocate_exception. -void __cxa_free_exception(void *thrown_object) throw() { +void __cxa_free_exception(void *thrown_object) _NOEXCEPT { // Compute the size of the padding before the header. size_t header_offset = get_cxa_exception_offset(); char *raw_buffer = @@ -254,7 +254,12 @@ will call terminate, assuming that there was no handler for the exception. */ void +#ifdef __USING_WASM_EXCEPTIONS__ +// In wasm, destructors return their argument +__cxa_throw(void *thrown_object, std::type_info *tinfo, void *(*dest)(void *)) { +#else __cxa_throw(void *thrown_object, std::type_info *tinfo, void (*dest)(void *)) { +#endif __cxa_eh_globals *globals = __cxa_get_globals(); __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -292,7 +297,7 @@ The adjusted pointer is computed by the personality routine during phase 1 Requires: exception is native */ -void *__cxa_get_exception_ptr(void *unwind_exception) throw() { +void *__cxa_get_exception_ptr(void *unwind_exception) _NOEXCEPT { #if defined(_LIBCXXABI_ARM_EHABI) return reinterpret_cast( static_cast<_Unwind_Control_Block*>(unwind_exception)->barrier_cache.bitpattern[0]); @@ -307,7 +312,7 @@ void *__cxa_get_exception_ptr(void *unwind_exception) throw() { The routine to be called before the cleanup. This will save __cxa_exception in __cxa_eh_globals, so that __cxa_end_cleanup() can recover later. */ -bool __cxa_begin_cleanup(void *unwind_arg) throw() { +bool __cxa_begin_cleanup(void *unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); __cxa_eh_globals* globals = __cxa_get_globals(); __cxa_exception* exception_header = @@ -418,7 +423,7 @@ to terminate or unexpected during unwinding. _Unwind_Exception and return a pointer to that. */ void* -__cxa_begin_catch(void* unwind_arg) throw() +__cxa_begin_catch(void* unwind_arg) _NOEXCEPT { _Unwind_Exception* unwind_exception = static_cast<_Unwind_Exception*>(unwind_arg); bool native_exception = __isOurExceptionClass(unwind_exception); @@ -626,7 +631,7 @@ void __cxa_rethrow() { Requires: If thrown_object is not NULL, it is a native exception. */ void -__cxa_increment_exception_refcount(void *thrown_object) throw() { +__cxa_increment_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -643,7 +648,7 @@ __cxa_increment_exception_refcount(void *thrown_object) throw() { Requires: If thrown_object is not NULL, it is a native exception. */ _LIBCXXABI_NO_CFI -void __cxa_decrement_exception_refcount(void *thrown_object) throw() { +void __cxa_decrement_exception_refcount(void *thrown_object) _NOEXCEPT { if (thrown_object != NULL ) { __cxa_exception* exception_header = cxa_exception_from_thrown_object(thrown_object); @@ -666,7 +671,7 @@ void __cxa_decrement_exception_refcount(void *thrown_object) throw() { been no exceptions thrown, ever, on this thread, we can return NULL without the need to allocate the exception-handling globals. */ -void *__cxa_current_primary_exception() throw() { +void *__cxa_current_primary_exception() _NOEXCEPT { // get the current exception __cxa_eh_globals* globals = __cxa_get_globals_fast(); if (NULL == globals) @@ -738,10 +743,10 @@ __cxa_rethrow_primary_exception(void* thrown_object) } bool -__cxa_uncaught_exception() throw() { return __cxa_uncaught_exceptions() != 0; } +__cxa_uncaught_exception() _NOEXCEPT { return __cxa_uncaught_exceptions() != 0; } unsigned int -__cxa_uncaught_exceptions() throw() +__cxa_uncaught_exceptions() _NOEXCEPT { // This does not report foreign exceptions in flight __cxa_eh_globals* globals = __cxa_get_globals_fast(); diff --git a/libcxxabi/src/cxa_exception.h b/libcxxabi/src/cxa_exception.h index 8c6c8bca853c6..6adc4c597792d 100644 --- a/libcxxabi/src/cxa_exception.h +++ b/libcxxabi/src/cxa_exception.h @@ -43,7 +43,12 @@ struct _LIBCXXABI_HIDDEN __cxa_exception { // Manage the exception object itself. std::type_info *exceptionType; +#ifdef __USING_WASM_EXCEPTIONS__ + // In wasm, destructors return their argument + void *(*exceptionDestructor)(void *); +#else void (*exceptionDestructor)(void *); +#endif std::unexpected_handler unexpectedHandler; std::terminate_handler terminateHandler; diff --git a/libcxxabi/src/cxa_handlers.cpp b/libcxxabi/src/cxa_handlers.cpp index f520a4db6edac..713f02b3c6597 100644 --- a/libcxxabi/src/cxa_handlers.cpp +++ b/libcxxabi/src/cxa_handlers.cpp @@ -19,6 +19,32 @@ #include "private_typeinfo.h" #include "include/atomic_support.h" +namespace __cxxabiv1 { + +#ifdef __USING_EMSCRIPTEN_EXCEPTIONS__ +// XXX EMSCRIPTEN: Copied from cxa_exception.cpp since we don't compile that +// file in Emscripten EH mode. Note that in no-exceptions builds we include +// cxa_noexception.cpp which provides stubs of those anyhow. + +// Is it one of ours? +uint64_t __getExceptionClass(const _Unwind_Exception* unwind_exception) { +// On x86 and some ARM unwinders, unwind_exception->exception_class is +// a uint64_t. On other ARM unwinders, it is a char[8] +// See: http://infocenter.arm.com/help/topic/com.arm.doc.ihi0038b/IHI0038B_ehabi.pdf +// So we just copy it into a uint64_t to be sure. + uint64_t exClass; + ::memcpy(&exClass, &unwind_exception->exception_class, sizeof(exClass)); + return exClass; +} + +bool __isOurExceptionClass(const _Unwind_Exception* unwind_exception) { + return (__getExceptionClass(unwind_exception) & get_vendor_and_language) == + (kOurExceptionClass & get_vendor_and_language); +} +#endif + +} + namespace std { diff --git a/libcxxabi/src/cxa_personality.cpp b/libcxxabi/src/cxa_personality.cpp index 81aa85165dd3d..bbe5f0278b4fb 100644 --- a/libcxxabi/src/cxa_personality.cpp +++ b/libcxxabi/src/cxa_personality.cpp @@ -22,6 +22,8 @@ #include "private_typeinfo.h" #include "unwind.h" +#define __USING_SJLJ_OR_WASM_EXCEPTIONS__ (__USING_SJLJ_EXCEPTIONS__ || __USING_WASM_EXCEPTIONS__) + #if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) #include #include @@ -61,7 +63,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, +------------------+--+-----+-----+------------------------+--------------------------+ | callSiteTableLength | (ULEB128) | Call Site Table length, used to find Action table | +---------------------+-----------+---------------------------------------------------+ -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip lies within the | | ... (start, length) range of one of these | @@ -75,7 +77,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#else // __USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------+-----------+------------------------------------------------+ | Beginning of Call Site Table The current ip is a 1-based index into | | ... this table. Or it is -1 meaning no | @@ -88,7 +90,7 @@ extern "C" EXCEPTION_DISPOSITION _GCC_specific_handler(PEXCEPTION_RECORD, | +-------------+---------------------------------+------------------------------+ | | ... | +----------------------------------------------------------------------------------+ -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ +---------------------------------------------------------------------+ | Beginning of Action Table ttypeIndex == 0 : cleanup | | ... ttypeIndex > 0 : catch | @@ -529,7 +531,7 @@ void set_registers(_Unwind_Exception* unwind_exception, _Unwind_Context* context, const scan_results& results) { -#if defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ #define __builtin_eh_return_data_regno(regno) regno #endif _Unwind_SetGR(context, __builtin_eh_return_data_regno(0), @@ -616,7 +618,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Get beginning current frame's code (as defined by the // emitted dwarf code) uintptr_t funcStart = _Unwind_GetRegionStart(context); -#ifdef __USING_SJLJ_EXCEPTIONS__ +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (ip == uintptr_t(-1)) { // no action @@ -626,9 +628,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, else if (ip == 0) call_terminate(native_exception, unwind_exception); // ip is 1-based index into call site table -#else // !__USING_SJLJ_EXCEPTIONS__ +#else // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ uintptr_t ipOffset = ip - funcStart; -#endif // !defined(_USING_SLJL_EXCEPTIONS__) +#endif // __USING_SJLJ_OR_WASM_EXCEPTIONS__ const uint8_t* classInfo = NULL; // Note: See JITDwarfEmitter::EmitExceptionTable(...) for corresponding // dwarf emission @@ -649,8 +651,8 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Walk call-site table looking for range that // includes current PC. uint8_t callSiteEncoding = *lsda++; -#ifdef __USING_SJLJ_EXCEPTIONS__ - (void)callSiteEncoding; // When using SjLj exceptions, callSiteEncoding is never used +#ifdef __USING_SJLJ_OR_WASM_EXCEPTIONS__ + (void)callSiteEncoding; // When using SjLj/Wasm exceptions, callSiteEncoding is never used #endif uint32_t callSiteTableLength = static_cast(readULEB128(&lsda)); const uint8_t* callSiteTableStart = lsda; @@ -660,7 +662,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, while (callSitePtr < callSiteTableEnd) { // There is one entry per call site. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ // The call sites are non-overlapping in [start, start+length) // The call sites are ordered in increasing value of start uintptr_t start = readEncodedPointer(&callSitePtr, callSiteEncoding); @@ -668,15 +670,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, uintptr_t landingPad = readEncodedPointer(&callSitePtr, callSiteEncoding); uintptr_t actionEntry = readULEB128(&callSitePtr); if ((start <= ipOffset) && (ipOffset < (start + length))) -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ // ip is 1-based index into this table uintptr_t landingPad = readULEB128(&callSitePtr); uintptr_t actionEntry = readULEB128(&callSitePtr); if (--ip == 0) -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ { // Found the call site containing ip. -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ if (landingPad == 0) { // No handler here @@ -685,9 +687,9 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, } landingPad = (uintptr_t)lpStart + landingPad; results.landingPad = landingPad; -#else // __USING_SJLJ_EXCEPTIONS__ +#else // __USING_SJLJ_OR_WASM_EXCEPTIONS__ ++landingPad; -#endif // __USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ if (actionEntry == 0) { // Found a cleanup @@ -714,6 +716,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, native_exception, unwind_exception); if (catchType == 0) { +#error fixme + /* +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else + if ((actions & _UA_SEARCH_PHASE) || (actions & _UA_HANDLER_FRAME)) +#endif +*/ // Found catch (...) catches everything, including // foreign exceptions. This is search phase, cleanup // phase with foreign exception, or forced unwinding. @@ -741,6 +752,15 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, } if (catchType->can_catch(excpType, adjustedPtr)) { +#error fixme + /* +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else + if (actions & _UA_SEARCH_PHASE) +#endif +*/ // Found a matching handler. This is either search // phase or forced unwinding. assert(actions & @@ -774,10 +794,17 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, ttypeEncoding, excpType, adjustedPtr, unwind_exception)) { +#error fixme + /* +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm does not do two-phase unwinding and only uses cleanup phase + if (actions & _UA_CLEANUP_PHASE) +#else + if (actions & _UA_SEARCH_PHASE) +#endif +*/ // Native exception caught by exception // specification. - assert(actions & _UA_SEARCH_PHASE); - results.ttypeIndex = ttypeIndex; results.actionRecord = actionRecord; results.adjustedPtr = adjustedPtr; results.reason = _URC_HANDLER_FOUND; @@ -812,7 +839,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, action += actionOffset; } // there is no break out of this loop, only return } -#ifndef __USING_SJLJ_EXCEPTIONS__ +#ifndef __USING_SJLJ_OR_WASM_EXCEPTIONS__ else if (ipOffset < start) { // There is no call site for this ip @@ -820,7 +847,7 @@ static void scan_eh_tab(scan_results &results, _Unwind_Action actions, // Possible stack corruption. call_terminate(native_exception, unwind_exception); } -#endif // !__USING_SJLJ_EXCEPTIONS__ +#endif // !__USING_SJLJ_OR_WASM_EXCEPTIONS__ } // there might be some tricky cases which break out of this loop // It is possible that no eh table entry specify how to handle @@ -877,7 +904,9 @@ _UA_CLEANUP_PHASE */ #if !defined(_LIBCXXABI_ARM_EHABI) -#if defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) +#ifdef __USING_WASM_EXCEPTIONS__ +_Unwind_Reason_Code __gxx_personality_wasm0 +#elif defined(__SEH__) && !defined(__USING_SJLJ_EXCEPTIONS__) static _Unwind_Reason_Code __gxx_personality_imp #else _LIBCXXABI_FUNC_VIS _Unwind_Reason_Code @@ -940,6 +969,16 @@ __gxx_personality_v0 assert(actions & _UA_CLEANUP_PHASE); assert(results.reason == _URC_HANDLER_FOUND); set_registers(unwind_exception, context, results); +#ifdef __USING_WASM_EXCEPTIONS__ + // Wasm uses only one phase in _UA_CLEANUP_PHASE, so we should set + // these here. + __cxa_exception* exception_header = (__cxa_exception*)(unwind_exception+1) - 1; + exception_header->handlerSwitchValue = static_cast(results.ttypeIndex); + exception_header->actionRecord = results.actionRecord; + exception_header->languageSpecificData = results.languageSpecificData; + exception_header->catchTemp = reinterpret_cast(results.landingPad); + exception_header->adjustedPtr = results.adjustedPtr; +#endif return _URC_INSTALL_CONTEXT; } diff --git a/libcxxabi/src/private_typeinfo.cpp b/libcxxabi/src/private_typeinfo.cpp index c77ad669c49e3..8072ebb7ef2d0 100644 --- a/libcxxabi/src/private_typeinfo.cpp +++ b/libcxxabi/src/private_typeinfo.cpp @@ -1323,4 +1323,35 @@ __base_class_type_info::search_below_dst(__dynamic_cast_info* info, use_strcmp); } +// XXX EMSCRIPTEN + +#ifndef __USING_WASM_EXCEPTIONS__ + +// These functions are used by the emscripten-style exception handling +// mechanism. +// Note that they need to be included even in the `-noexcept` build of +// libc++abi to support the case where some parts of a project are built +// with exception catching enabled, but at link time exception catching +// is disabled. In this case dependencies to these functions (and the JS +// functions which call them) will still exist in the final build. +extern "C" { + +int __cxa_can_catch(__shim_type_info* catchType, __shim_type_info* excpType, void **thrown) { + //std::type_info *t1 = static_cast(catchType); + //std::type_info *t2 = static_cast(excpType); + //printf("can %s catch %s (%p)?\n", t1->name(), t2->name(), thrown); + + void *temp = *thrown; + int ret = catchType->can_catch(excpType, temp); + if (ret) *thrown = temp; // apply changes only if we are catching + return ret; +} + +int __cxa_is_pointer_type(__shim_type_info* type) { + return !!dynamic_cast<__pointer_type_info*>(type); +} + +} +#endif // __USING_EMSCRIPTEN_EXCEPTIONS__ + } // __cxxabiv1 diff --git a/libcxxabi/src/stdlib_new_delete.cpp b/libcxxabi/src/stdlib_new_delete.cpp index 8ef3057dd45e4..14370c862211b 100644 --- a/libcxxabi/src/stdlib_new_delete.cpp +++ b/libcxxabi/src/stdlib_new_delete.cpp @@ -37,8 +37,17 @@ operator new(std::size_t size) _THROW_BAD_ALLOC else #ifndef _LIBCXXABI_NO_EXCEPTIONS throw std::bad_alloc(); +#else +#ifdef __EMSCRIPTEN__ + // Abort here so that when exceptions are disabled, we do not just + // return 0 when malloc returns 0. + // We could also do this with set_new_handler, but that adds a + // global constructor and a table entry, overhead that we can avoid + // by doing it this way. + abort(); #else break; +#endif #endif } return p; From llvm-branch-commits at lists.llvm.org Mon May 24 22:37:56 2021 From: llvm-branch-commits at lists.llvm.org (Tom Stellard via llvm-branch-commits) Date: Mon, 24 May 2021 22:37:56 -0700 (PDT) Subject: [llvm-branch-commits] [llvm] 328a6ec - Force visibility of llvm::Any to external Message-ID: <60ac8d34.1c69fb81.758fe.9aec@mx.google.com> Author: serge-sans-paille Date: 2021-05-24T21:39:54-07:00 New Revision: 328a6ec955327c6d56b6bc3478c723dd3cd468ef URL: https://github.com/llvm/llvm-project/commit/328a6ec955327c6d56b6bc3478c723dd3cd468ef DIFF: https://github.com/llvm/llvm-project/commit/328a6ec955327c6d56b6bc3478c723dd3cd468ef.diff LOG: Force visibility of llvm::Any to external llvm::Any::TypeId::Id relies on the uniqueness of the address of a static variable defined in a template function. hidden visibility implies vague linkage for that variable, which does not guarantee the uniqueness of the address across a binary and a shared library. This totally breaks the implementation of llvm::Any. Ideally, setting visibility to llvm::Any::TypeId::Id should be enough, unfortunately this doesn't work as expected and we lack time (before 12.0.1 release) to understand why setting the visibility to llvm::Any does work. See https://gcc.gnu.org/wiki/Visibility and https://gcc.gnu.org/onlinedocs/gcc/Vague-Linkage.html for more information on that topic. Differential Revision: https://reviews.llvm.org/D101972 (cherry picked from commit 3d3abc22b3ef189813a3b9061c2a90ba86a32f44) Added: Modified: llvm/include/llvm/ADT/Any.h Removed: ################################################################################ diff --git a/llvm/include/llvm/ADT/Any.h b/llvm/include/llvm/ADT/Any.h index 0aded628cda4a..1e3abca706792 100644 --- a/llvm/include/llvm/ADT/Any.h +++ b/llvm/include/llvm/ADT/Any.h @@ -23,7 +23,12 @@ namespace llvm { -class Any { +class LLVM_EXTERNAL_VISIBILITY Any { + + // The `Typeid::Id` static data member below is a globally unique + // identifier for the type `T`. It is explicitly marked with default + // visibility so that when `-fvisibility=hidden` is used, the loader still + // merges duplicate definitions across DSO boundaries. template struct TypeId { static const char Id; }; struct StorageBase {