[llvm] 7424efd - [dfsan] Propagate origins at non-memory/phi/call instructions
Jianzhou Zhao via llvm-commits
llvm-commits at lists.llvm.org
Mon Feb 22 18:13:21 PST 2021
Author: Jianzhou Zhao
Date: 2021-02-23T02:12:45Z
New Revision: 7424efd5ad57d18de65e1a5e572a04e1348a7e04
URL: https://github.com/llvm/llvm-project/commit/7424efd5ad57d18de65e1a5e572a04e1348a7e04
DIFF: https://github.com/llvm/llvm-project/commit/7424efd5ad57d18de65e1a5e572a04e1348a7e04.diff
LOG: [dfsan] Propagate origins at non-memory/phi/call instructions
This is a part of https://reviews.llvm.org/D95835.
Reviewed-by: morehouse
Differential Revision: https://reviews.llvm.org/D97200
Added:
llvm/test/Instrumentation/DataFlowSanitizer/origin_other_ops.ll
llvm/test/Instrumentation/DataFlowSanitizer/origin_select.ll
Modified:
llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
Removed:
################################################################################
diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
index 302e3c4e8c96..c619bbc81997 100644
--- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
+++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp
@@ -543,13 +543,25 @@ struct DFSanFunction {
/// Computes the origin address for a given function argument.
///
/// Origin = ArgOriginTLS[ArgNo].
- // Value *getArgOriginTLS(unsigned ArgNo, IRBuilder<> &IRB);
+ Value *getArgOriginTLS(unsigned ArgNo, IRBuilder<> &IRB);
/// Computes the origin address for a return value.
- // Value *getRetvalOriginTLS();
+ Value *getRetvalOriginTLS();
+
+ Value *getOrigin(Value *V);
+ void setOrigin(Instruction *I, Value *Origin);
+ /// Generates IR to compute the origin of the last operand with a taint label.
+ Value *combineOperandOrigins(Instruction *Inst);
+ /// Before the instruction Pos, generates IR to compute the last origin with a
+ /// taint label. Labels and origins are from vectors Shadows and Origins
+ /// correspondingly. The generated IR is like
+ /// Sn-1 != Zero ? On-1: ... S2 != Zero ? O2: S1 != Zero ? O1: O0
+ /// When Zero is nullptr, it uses ZeroPrimitiveShadow. Otherwise it can be
+ /// zeros with other bitwidths.
+ Value *combineOrigins(const std::vector<Value *> &Shadows,
+ const std::vector<Value *> &Origins, Instruction *Pos,
+ ConstantInt *Zero = nullptr);
- // Value *getOrigin(Value *V);
- // void setOrigin(Instruction *I, Value *Origin);
Value *getShadow(Value *V);
void setShadow(Instruction *I, Value *Shadow);
/// Generates IR to compute the union of the two given shadows, inserting it
@@ -612,9 +624,8 @@ class DFSanVisitor : public InstVisitor<DFSanVisitor> {
return DFSF.F->getParent()->getDataLayout();
}
- // Combines shadow values for all of I's operands. Returns the combined shadow
- // value.
- Value *visitOperandShadowInst(Instruction &I);
+ // Combines shadow values and origins for all of I's operands.
+ void visitInstOperands(Instruction &I);
void visitUnaryOperator(UnaryOperator &UO);
void visitBinaryOperator(BinaryOperator &BO);
@@ -639,6 +650,9 @@ class DFSanVisitor : public InstVisitor<DFSanVisitor> {
private:
// Returns false when this is an invoke of a custom function.
bool visitWrappedCallBase(Function &F, CallBase &CB);
+
+ // Combines origins for all of I's operands.
+ void visitInstOperandOrigins(Instruction &I);
};
} // end anonymous namespace
@@ -1465,7 +1479,7 @@ Value *DFSanFunction::getRetvalTLS(Type *T, IRBuilder<> &IRB) {
return IRB.CreatePointerCast(
DFS.RetvalTLS, PointerType::get(DFS.getShadowTy(T), 0), "_dfsret");
}
-/*
+
Value *DFSanFunction::getRetvalOriginTLS() { return DFS.RetvalOriginTLS; }
Value *DFSanFunction::getArgOriginTLS(unsigned ArgNo, IRBuilder<> &IRB) {
@@ -1514,7 +1528,7 @@ void DFSanFunction::setOrigin(Instruction *I, Value *Origin) {
assert(Origin->getType() == DFS.OriginTy);
ValOriginMap[I] = Origin;
}
-*/
+
Value *DFSanFunction::getShadowForTLSArgument(Argument *A) {
unsigned ArgOffset = 0;
const DataLayout &DL = F->getParent()->getDataLayout();
@@ -1735,10 +1749,56 @@ Value *DFSanFunction::combineOperandShadows(Instruction *Inst) {
return expandFromPrimitiveShadow(Inst->getType(), Shadow, Inst);
}
-Value *DFSanVisitor::visitOperandShadowInst(Instruction &I) {
+void DFSanVisitor::visitInstOperands(Instruction &I) {
Value *CombinedShadow = DFSF.combineOperandShadows(&I);
DFSF.setShadow(&I, CombinedShadow);
- return CombinedShadow;
+ visitInstOperandOrigins(I);
+}
+
+Value *DFSanFunction::combineOrigins(const std::vector<Value *> &Shadows,
+ const std::vector<Value *> &Origins,
+ Instruction *Pos, ConstantInt *Zero) {
+ assert(Shadows.size() == Origins.size());
+ size_t Size = Origins.size();
+ if (Size == 0)
+ return DFS.ZeroOrigin;
+ Value *Origin = nullptr;
+ if (!Zero)
+ Zero = DFS.ZeroPrimitiveShadow;
+ for (size_t I = 0; I != Size; ++I) {
+ Value *OpOrigin = Origins[I];
+ Constant *ConstOpOrigin = dyn_cast<Constant>(OpOrigin);
+ if (ConstOpOrigin && ConstOpOrigin->isNullValue())
+ continue;
+ if (!Origin) {
+ Origin = OpOrigin;
+ continue;
+ }
+ Value *OpShadow = Shadows[I];
+ Value *PrimitiveShadow = collapseToPrimitiveShadow(OpShadow, Pos);
+ IRBuilder<> IRB(Pos);
+ Value *Cond = IRB.CreateICmpNE(PrimitiveShadow, Zero);
+ Origin = IRB.CreateSelect(Cond, OpOrigin, Origin);
+ }
+ return Origin ? Origin : DFS.ZeroOrigin;
+}
+
+Value *DFSanFunction::combineOperandOrigins(Instruction *Inst) {
+ size_t Size = Inst->getNumOperands();
+ std::vector<Value *> Shadows(Size);
+ std::vector<Value *> Origins(Size);
+ for (unsigned I = 0; I != Size; ++I) {
+ Shadows[I] = getShadow(Inst->getOperand(I));
+ Origins[I] = getOrigin(Inst->getOperand(I));
+ }
+ return combineOrigins(Shadows, Origins, Inst);
+}
+
+void DFSanVisitor::visitInstOperandOrigins(Instruction &I) {
+ if (!DFSF.DFS.shouldTrackOrigins())
+ return;
+ Value *CombinedOrigin = DFSF.combineOperandOrigins(&I);
+ DFSF.setOrigin(&I, CombinedOrigin);
}
Value *DFSanFunction::loadFast16ShadowFast(Value *ShadowAddr, uint64_t Size,
@@ -2009,42 +2069,43 @@ void DFSanVisitor::visitStoreInst(StoreInst &SI) {
}
void DFSanVisitor::visitUnaryOperator(UnaryOperator &UO) {
- visitOperandShadowInst(UO);
+ visitInstOperands(UO);
}
void DFSanVisitor::visitBinaryOperator(BinaryOperator &BO) {
- visitOperandShadowInst(BO);
+ visitInstOperands(BO);
}
-void DFSanVisitor::visitCastInst(CastInst &CI) { visitOperandShadowInst(CI); }
+void DFSanVisitor::visitCastInst(CastInst &CI) { visitInstOperands(CI); }
void DFSanVisitor::visitCmpInst(CmpInst &CI) {
- Value *CombinedShadow = visitOperandShadowInst(CI);
+ visitInstOperands(CI);
if (ClEventCallbacks) {
IRBuilder<> IRB(&CI);
+ Value *CombinedShadow = DFSF.getShadow(&CI);
IRB.CreateCall(DFSF.DFS.DFSanCmpCallbackFn, CombinedShadow);
}
}
void DFSanVisitor::visitGetElementPtrInst(GetElementPtrInst &GEPI) {
- visitOperandShadowInst(GEPI);
+ visitInstOperands(GEPI);
}
void DFSanVisitor::visitExtractElementInst(ExtractElementInst &I) {
- visitOperandShadowInst(I);
+ visitInstOperands(I);
}
void DFSanVisitor::visitInsertElementInst(InsertElementInst &I) {
- visitOperandShadowInst(I);
+ visitInstOperands(I);
}
void DFSanVisitor::visitShuffleVectorInst(ShuffleVectorInst &I) {
- visitOperandShadowInst(I);
+ visitInstOperands(I);
}
void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) {
if (!DFSF.DFS.shouldTrackFieldsAndIndices()) {
- visitOperandShadowInst(I);
+ visitInstOperands(I);
return;
}
@@ -2053,11 +2114,12 @@ void DFSanVisitor::visitExtractValueInst(ExtractValueInst &I) {
Value *AggShadow = DFSF.getShadow(Agg);
Value *ResShadow = IRB.CreateExtractValue(AggShadow, I.getIndices());
DFSF.setShadow(&I, ResShadow);
+ visitInstOperandOrigins(I);
}
void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) {
if (!DFSF.DFS.shouldTrackFieldsAndIndices()) {
- visitOperandShadowInst(I);
+ visitInstOperands(I);
return;
}
@@ -2066,6 +2128,7 @@ void DFSanVisitor::visitInsertValueInst(InsertValueInst &I) {
Value *InsShadow = DFSF.getShadow(I.getInsertedValueOperand());
Value *Res = IRB.CreateInsertValue(AggShadow, InsShadow, I.getIndices());
DFSF.setShadow(&I, Res);
+ visitInstOperandOrigins(I);
}
void DFSanVisitor::visitAllocaInst(AllocaInst &I) {
@@ -2094,22 +2157,51 @@ void DFSanVisitor::visitSelectInst(SelectInst &I) {
Value *TrueShadow = DFSF.getShadow(I.getTrueValue());
Value *FalseShadow = DFSF.getShadow(I.getFalseValue());
Value *ShadowSel = nullptr;
+ const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins();
+ std::vector<Value *> Shadows;
+ std::vector<Value *> Origins;
+ Value *TrueOrigin =
+ ShouldTrackOrigins ? DFSF.getOrigin(I.getTrueValue()) : nullptr;
+ Value *FalseOrigin =
+ ShouldTrackOrigins ? DFSF.getOrigin(I.getFalseValue()) : nullptr;
if (isa<VectorType>(I.getCondition()->getType())) {
ShadowSel = DFSF.combineShadowsThenConvert(I.getType(), TrueShadow,
FalseShadow, &I);
+ if (ShouldTrackOrigins) {
+ Shadows.push_back(TrueShadow);
+ Shadows.push_back(FalseShadow);
+ Origins.push_back(TrueOrigin);
+ Origins.push_back(FalseOrigin);
+ }
} else {
if (TrueShadow == FalseShadow) {
ShadowSel = TrueShadow;
+ if (ShouldTrackOrigins) {
+ Shadows.push_back(TrueShadow);
+ Origins.push_back(TrueOrigin);
+ }
} else {
ShadowSel =
SelectInst::Create(I.getCondition(), TrueShadow, FalseShadow, "", &I);
+ if (ShouldTrackOrigins) {
+ Shadows.push_back(ShadowSel);
+ Origins.push_back(SelectInst::Create(I.getCondition(), TrueOrigin,
+ FalseOrigin, "", &I));
+ }
}
}
DFSF.setShadow(&I, ClTrackSelectControlFlow
? DFSF.combineShadowsThenConvert(
I.getType(), CondShadow, ShadowSel, &I)
: ShadowSel);
+ if (ShouldTrackOrigins) {
+ if (ClTrackSelectControlFlow) {
+ Shadows.push_back(CondShadow);
+ Origins.push_back(DFSF.getOrigin(I.getCondition()));
+ }
+ DFSF.setOrigin(&I, DFSF.combineOrigins(Shadows, Origins, &I));
+ }
}
void DFSanVisitor::visitMemSetInst(MemSetInst &I) {
@@ -2162,6 +2254,10 @@ void DFSanVisitor::visitReturnInst(ReturnInst &RI) {
IRB.CreateAlignedStore(S, DFSF.getRetvalTLS(RT, IRB),
kShadowTLSAlignment);
}
+ if (DFSF.DFS.shouldTrackOrigins()) {
+ Value *O = DFSF.getOrigin(RI.getReturnValue());
+ IRB.CreateStore(O, DFSF.getRetvalOriginTLS());
+ }
break;
}
case DataFlowSanitizer::IA_Args: {
@@ -2193,7 +2289,7 @@ bool DFSanVisitor::visitWrappedCallBase(Function &F, CallBase &CB) {
return true;
case DataFlowSanitizer::WK_Functional:
CB.setCalledFunction(&F);
- visitOperandShadowInst(CB);
+ visitInstOperands(CB);
return true;
case DataFlowSanitizer::WK_Custom:
// Don't try to handle invokes of custom functions, it's too complicated.
@@ -2311,7 +2407,7 @@ bool DFSanVisitor::visitWrappedCallBase(Function &F, CallBase &CB) {
void DFSanVisitor::visitCallBase(CallBase &CB) {
Function *F = CB.getCalledFunction();
if ((F && F->isIntrinsic()) || CB.isInlineAsm()) {
- visitOperandShadowInst(CB);
+ visitInstOperands(CB);
return;
}
diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/origin_other_ops.ll b/llvm/test/Instrumentation/DataFlowSanitizer/origin_other_ops.ll
new file mode 100644
index 000000000000..1d71aa08e82c
--- /dev/null
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/origin_other_ops.ll
@@ -0,0 +1,136 @@
+; RUN: opt < %s -dfsan -dfsan-track-origins=1 -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=CHECK
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define float @unop(float %f) {
+ ; CHECK: @"dfs$unop"
+ ; CHECK: [[FO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: store i32 [[FO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %r = fneg float %f
+ ret float %r
+}
+
+define i1 @binop(i1 %a, i1 %b) {
+ ; CHECK: @"dfs$binop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[MO:%.*]] = select i1 [[NE]], i32 [[BO]], i32 [[AO]]
+ ; CHECK: store i32 [[MO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %r = add i1 %a, %b
+ ret i1 %r
+}
+
+define i8 @castop(i32* %p) {
+ ; CHECK: @"dfs$castop"
+ ; CHECK: [[PO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: store i32 [[PO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %r = ptrtoint i32* %p to i8
+ ret i8 %r
+}
+
+define i1 @cmpop(i1 %a, i1 %b) {
+ ; CHECK: @"dfs$cmpop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[MO:%.*]] = select i1 [[NE]], i32 [[BO]], i32 [[AO]]
+ ; CHECK: store i32 [[MO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %r = icmp eq i1 %a, %b
+ ret i1 %r
+}
+
+define i32* @gepop([10 x [20 x i32]]* %p, i32 %a, i32 %b, i32 %c) {
+ ; CHECK: @"dfs$gepop"
+ ; CHECK: [[CO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 3), align 4
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[PO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[CS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 6) to i16*), align 2
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 4) to i16*), align 2
+ ; CHECK: [[AS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[AS_NE:%.*]] = icmp ne i16 [[AS]], 0
+ ; CHECK: [[APO:%.*]] = select i1 [[AS_NE]], i32 [[AO]], i32 [[PO]]
+ ; CHECK: [[BS_NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[ABPO:%.*]] = select i1 [[BS_NE]], i32 [[BO]], i32 [[APO]]
+ ; CHECK: [[CS_NE:%.*]] = icmp ne i16 [[CS]], 0
+ ; CHECK: [[ABCPO:%.*]] = select i1 [[CS_NE]], i32 [[CO]], i32 [[ABPO]]
+ ; CHECK: store i32 [[ABCPO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = getelementptr [10 x [20 x i32]], [10 x [20 x i32]]* %p, i32 %a, i32 %b, i32 %c
+ ret i32* %e
+}
+
+define i32 @eeop(<4 x i32> %a, i32 %b) {
+ ; CHECK: @"dfs$eeop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[MO:%.*]] = select i1 [[NE]], i32 [[BO]], i32 [[AO]]
+ ; CHECK: store i32 [[MO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = extractelement <4 x i32> %a, i32 %b
+ ret i32 %e
+}
+
+define <4 x i32> @ieop(<4 x i32> %p, i32 %a, i32 %b) {
+ ; CHECK: @"dfs$ieop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[PO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 4) to i16*), align 2
+ ; CHECK: [[AS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[AS_NE:%.*]] = icmp ne i16 [[AS]], 0
+ ; CHECK: [[APO:%.*]] = select i1 [[AS_NE]], i32 [[AO]], i32 [[PO]]
+ ; CHECK: [[BS_NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[ABPO:%.*]] = select i1 [[BS_NE]], i32 [[BO]], i32 [[APO]]
+ ; CHECK: store i32 [[ABPO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = insertelement <4 x i32> %p, i32 %a, i32 %b
+ ret <4 x i32> %e
+}
+
+define <4 x i32> @svop(<4 x i32> %a, <4 x i32> %b) {
+ ; CHECK: @"dfs$svop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 2) to i16*), align 2
+ ; CHECK: [[NE:%.*]] = icmp ne i16 [[BS]], 0
+ ; CHECK: [[MO:%.*]] = select i1 [[NE]], i32 [[BO]], i32 [[AO]]
+ ; CHECK: store i32 [[MO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = shufflevector <4 x i32> %a, <4 x i32> %b, <4 x i32> <i32 0, i32 4, i32 1, i32 5>
+ ret <4 x i32> %e
+}
+
+define i32 @evop({i32, float} %a) {
+ ; CHECK: @"dfs$evop"
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: store i32 [[AO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = extractvalue {i32, float} %a, 0
+ ret i32 %e
+}
+
+define {i32, {float, float}} @ivop({i32, {float, float}} %a, {float, float} %b) {
+ ; CHECK: @"dfs$ivop"
+ ; CHECK: [[BO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; CHECK: [[AO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; CHECK: [[BS:%.*]] = load { i16, i16 }, { i16, i16 }* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 6) to { i16, i16 }*), align 2
+ ; CHECK: [[BS0:%.*]] = extractvalue { i16, i16 } [[BS]], 0
+ ; CHECK: [[BS1:%.*]] = extractvalue { i16, i16 } [[BS]], 1
+ ; CHECK: [[BS01:%.*]] = or i16 [[BS0]], [[BS1]]
+ ; CHECK: [[NE:%.*]] = icmp ne i16 [[BS01]], 0
+ ; CHECK: [[MO:%.*]] = select i1 [[NE]], i32 [[BO]], i32 [[AO]]
+ ; CHECK: store i32 [[MO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %e = insertvalue {i32, {float, float}} %a, {float, float} %b, 1
+ ret {i32, {float, float}} %e
+}
\ No newline at end of file
diff --git a/llvm/test/Instrumentation/DataFlowSanitizer/origin_select.ll b/llvm/test/Instrumentation/DataFlowSanitizer/origin_select.ll
new file mode 100644
index 000000000000..9690dcf9316f
--- /dev/null
+++ b/llvm/test/Instrumentation/DataFlowSanitizer/origin_select.ll
@@ -0,0 +1,67 @@
+; RUN: opt < %s -dfsan -dfsan-track-select-control-flow=1 -dfsan-track-origins=1 -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=TRACK_CONTROL_FLOW
+; RUN: opt < %s -dfsan -dfsan-track-select-control-flow=0 -dfsan-track-origins=1 -dfsan-fast-16-labels=true -S | FileCheck %s --check-prefix=NO_TRACK_CONTROL_FLOW
+target datalayout = "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
+target triple = "x86_64-unknown-linux-gnu"
+
+define i8 @select8(i1 %c, i8 %t, i8 %f) {
+ ; TRACK_CONTROL_FLOW: @"dfs$select8"
+ ; TRACK_CONTROL_FLOW: [[CO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; TRACK_CONTROL_FLOW: [[FO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; TRACK_CONTROL_FLOW: [[TO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; TRACK_CONTROL_FLOW: [[CS:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 2
+ ; TRACK_CONTROL_FLOW: [[TFO:%.*]] = select i1 %c, i32 [[TO]], i32 [[FO]]
+ ; TRACK_CONTROL_FLOW: [[CS_NE:%.*]] = icmp ne i16 [[CS]], 0
+ ; TRACK_CONTROL_FLOW: [[CTFO:%.*]] = select i1 [[CS_NE]], i32 [[CO]], i32 [[TFO]]
+ ; TRACK_CONTROL_FLOW: store i32 [[CTFO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ ; NO_TRACK_CONTROL_FLOW: @"dfs$select8"
+ ; NO_TRACK_CONTROL_FLOW: [[FO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; NO_TRACK_CONTROL_FLOW: [[TO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; NO_TRACK_CONTROL_FLOW: [[TFO:%.*]] = select i1 %c, i32 [[TO]], i32 [[FO]]
+ ; NO_TRACK_CONTROL_FLOW: store i32 [[TFO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %a = select i1 %c, i8 %t, i8 %f
+ ret i8 %a
+}
+
+define i8 @select8e(i1 %c, i8 %tf) {
+ ; TRACK_CONTROL_FLOW: @"dfs$select8e"
+ ; TRACK_CONTROL_FLOW: [[CO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; TRACK_CONTROL_FLOW: [[TFO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; TRACK_CONTROL_FLOW: [[CS:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 2
+ ; TRACK_CONTROL_FLOW: [[CS_NE:%.*]] = icmp ne i16 [[CS]], 0
+ ; TRACK_CONTROL_FLOW: [[CTFO:%.*]] = select i1 [[CS_NE]], i32 [[CO]], i32 [[TFO]]
+ ; TRACK_CONTROL_FLOW: store i32 [[CTFO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ ; NO_TRACK_CONTROL_FLOW: @"dfs$select8e"
+ ; NO_TRACK_CONTROL_FLOW: [[TFO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; NO_TRACK_CONTROL_FLOW: store i32 [[TFO]], i32* @__dfsan_retval_origin_tls, align 4
+
+%a = select i1 %c, i8 %tf, i8 %tf
+ ret i8 %a
+}
+
+define <4 x i8> @select8v(<4 x i1> %c, <4 x i8> %t, <4 x i8> %f) {
+ ; TRACK_CONTROL_FLOW: @"dfs$select8v"
+ ; TRACK_CONTROL_FLOW: [[CO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 0), align 4
+ ; TRACK_CONTROL_FLOW: [[FO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; TRACK_CONTROL_FLOW: [[TO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; TRACK_CONTROL_FLOW: [[FS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 4) to i16*), align 2
+ ; TRACK_CONTROL_FLOW: [[CS:%.*]] = load i16, i16* bitcast ([100 x i64]* @__dfsan_arg_tls to i16*), align 2
+ ; TRACK_CONTROL_FLOW: [[FS_NE:%.*]] = icmp ne i16 [[FS]], 0
+ ; TRACK_CONTROL_FLOW: [[FTO:%.*]] = select i1 [[FS_NE]], i32 [[FO]], i32 [[TO]]
+ ; TRACK_CONTROL_FLOW: [[CS_NE:%.*]] = icmp ne i16 [[CS]], 0
+ ; TRACK_CONTROL_FLOW: [[CFTO:%.*]] = select i1 [[CS_NE]], i32 [[CO]], i32 [[FTO]]
+ ; TRACK_CONTROL_FLOW: store i32 [[CFTO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ ; NO_TRACK_CONTROL_FLOW: @"dfs$select8v"
+ ; NO_TRACK_CONTROL_FLOW: [[FO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 2), align 4
+ ; NO_TRACK_CONTROL_FLOW: [[TO:%.*]] = load i32, i32* getelementptr inbounds ([200 x i32], [200 x i32]* @__dfsan_arg_origin_tls, i64 0, i64 1), align 4
+ ; NO_TRACK_CONTROL_FLOW: [[FS:%.*]] = load i16, i16* inttoptr (i64 add (i64 ptrtoint ([100 x i64]* @__dfsan_arg_tls to i64), i64 4) to i16*), align 2
+ ; NO_TRACK_CONTROL_FLOW: [[FS_NE:%.*]] = icmp ne i16 [[FS]], 0
+ ; NO_TRACK_CONTROL_FLOW: [[FTO:%.*]] = select i1 [[FS_NE]], i32 [[FO]], i32 [[TO]]
+ ; NO_TRACK_CONTROL_FLOW: store i32 [[FTO]], i32* @__dfsan_retval_origin_tls, align 4
+
+ %a = select <4 x i1> %c, <4 x i8> %t, <4 x i8> %f
+ ret <4 x i8> %a
+}
\ No newline at end of file
More information about the llvm-commits
mailing list