diff --git a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp --- a/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp +++ b/llvm/lib/Transforms/Instrumentation/DataFlowSanitizer.cpp @@ -543,13 +543,25 @@ /// 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 &Shadows, + const std::vector &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 @@ 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 @@ 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 @@ 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 @@ 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 @@ 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 &Shadows, + const std::vector &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(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 Shadows(Size); + std::vector 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::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 @@ 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 @@ 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 @@ Value *TrueShadow = DFSF.getShadow(I.getTrueValue()); Value *FalseShadow = DFSF.getShadow(I.getFalseValue()); Value *ShadowSel = nullptr; + const bool ShouldTrackOrigins = DFSF.DFS.shouldTrackOrigins(); + std::vector Shadows; + std::vector Origins; + Value *TrueOrigin = + ShouldTrackOrigins ? DFSF.getOrigin(I.getTrueValue()) : nullptr; + Value *FalseOrigin = + ShouldTrackOrigins ? DFSF.getOrigin(I.getFalseValue()) : nullptr; if (isa(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 @@ 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 @@ 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 @@ 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 --- /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> + 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 --- /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