shouc created this revision. shouc added reviewers: morehouse, rnk, vitalybuka. Herald added subscribers: abrachet, hiraditya. shouc requested review of this revision. Herald added projects: clang, Sanitizers, LLVM. Herald added subscribers: llvm-commits, Sanitizers, cfe-commits.
Fuzzers need to add branch instrumentation. Current callbacks only consider integer instrumentation (i.e., integer related branches). This commit adds similar sancov trace callback funcs for floating point (half, float, and double) comparisons: + void __sanitizer_cov_trace_cmp_fp2(half Arg1, half Arg2); + void __sanitizer_cov_trace_cmp_fp4(float Arg1, float Arg2); + void __sanitizer_cov_trace_cmp_fp8(double Arg1, double Arg2); + void __sanitizer_cov_trace_const_cmp_fp2(half Arg1, half Arg2); + void __sanitizer_cov_trace_const_cmp_fp4(float Arg1, float Arg2); + void __sanitizer_cov_trace_const_cmp_fp8(double Arg1, double Arg2); Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D119621 Files: clang/docs/SanitizerCoverage.rst compiler-rt/lib/dfsan/done_abilist.txt compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp llvm/test/Instrumentation/SanitizerCoverage/cmp-tracing-api-x86_32.ll
Index: llvm/test/Instrumentation/SanitizerCoverage/cmp-tracing-api-x86_32.ll =================================================================== --- llvm/test/Instrumentation/SanitizerCoverage/cmp-tracing-api-x86_32.ll +++ llvm/test/Instrumentation/SanitizerCoverage/cmp-tracing-api-x86_32.ll @@ -12,10 +12,16 @@ ; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp2(i16 zeroext, i16 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp4(i32 zeroext, i32 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp8(i64, i64) +; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp_fp2(half, half) +; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp_fp4(float, float) +; CHECK-DAG: declare void @__sanitizer_cov_trace_cmp_fp8(double, double) ; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp1(i8 zeroext, i8 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp2(i16 zeroext, i16 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp4(i32 zeroext, i32 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp8(i64, i64) +; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp_fp2(half, half) +; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp_fp4(float, float) +; CHECK-DAG: declare void @__sanitizer_cov_trace_const_cmp_fp8(double, double) ; CHECK-DAG: declare void @__sanitizer_cov_trace_div4(i32 zeroext) ; CHECK-DAG: declare void @__sanitizer_cov_trace_div8(i64) ; CHECK-DAG: declare void @__sanitizer_cov_trace_gep(i64) Index: llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp =================================================================== --- llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp +++ llvm/lib/Transforms/Instrumentation/SanitizerCoverage.cpp @@ -52,10 +52,16 @@ const char SanCovTraceCmp2[] = "__sanitizer_cov_trace_cmp2"; const char SanCovTraceCmp4[] = "__sanitizer_cov_trace_cmp4"; const char SanCovTraceCmp8[] = "__sanitizer_cov_trace_cmp8"; +const char SanCovTraceCmpF2[] = "__sanitizer_cov_trace_cmp_fp2"; +const char SanCovTraceCmpF4[] = "__sanitizer_cov_trace_cmp_fp4"; +const char SanCovTraceCmpF8[] = "__sanitizer_cov_trace_cmp_fp8"; const char SanCovTraceConstCmp1[] = "__sanitizer_cov_trace_const_cmp1"; const char SanCovTraceConstCmp2[] = "__sanitizer_cov_trace_const_cmp2"; const char SanCovTraceConstCmp4[] = "__sanitizer_cov_trace_const_cmp4"; const char SanCovTraceConstCmp8[] = "__sanitizer_cov_trace_const_cmp8"; +const char SanCovTraceConstCmpF2[] = "__sanitizer_cov_trace_const_cmp_fp2"; +const char SanCovTraceConstCmpF4[] = "__sanitizer_cov_trace_const_cmp_fp4"; +const char SanCovTraceConstCmpF8[] = "__sanitizer_cov_trace_const_cmp_fp8"; const char SanCovLoad1[] = "__sanitizer_cov_load1"; const char SanCovLoad2[] = "__sanitizer_cov_load2"; const char SanCovLoad4[] = "__sanitizer_cov_load4"; @@ -257,8 +263,8 @@ std::string getSectionEnd(const std::string &Section) const; FunctionCallee SanCovTracePCIndir; FunctionCallee SanCovTracePC, SanCovTracePCGuard; - std::array<FunctionCallee, 4> SanCovTraceCmpFunction; - std::array<FunctionCallee, 4> SanCovTraceConstCmpFunction; + std::array<FunctionCallee, 7> SanCovTraceCmpFunction; + std::array<FunctionCallee, 7> SanCovTraceConstCmpFunction; std::array<FunctionCallee, 5> SanCovLoadFunction; std::array<FunctionCallee, 5> SanCovStoreFunction; std::array<FunctionCallee, 2> SanCovTraceDivFunction; @@ -267,7 +273,8 @@ GlobalVariable *SanCovLowestStack; Type *Int128PtrTy, *IntptrTy, *IntptrPtrTy, *Int64Ty, *Int64PtrTy, *Int32Ty, *Int32PtrTy, *Int16PtrTy, *Int16Ty, *Int8Ty, *Int8PtrTy, *Int1Ty, - *Int1PtrTy; + *Int1PtrTy, + *Fp16Ty, *Fp16PtrTy, *Fp32Ty, *Fp32PtrTy, *Fp64Ty, *Fp64PtrTy; Module *CurModule; std::string CurModuleUniqueId; Triple TargetTriple; @@ -443,11 +450,17 @@ Int32PtrTy = PointerType::getUnqual(IRB.getInt32Ty()); Int8PtrTy = PointerType::getUnqual(IRB.getInt8Ty()); Int1PtrTy = PointerType::getUnqual(IRB.getInt1Ty()); + Fp16PtrTy = PointerType::getUnqual(IRB.getHalfTy()); + Fp32PtrTy = PointerType::getUnqual(IRB.getFloatTy()); + Fp64PtrTy = PointerType::getUnqual(IRB.getDoubleTy()); Int64Ty = IRB.getInt64Ty(); Int32Ty = IRB.getInt32Ty(); Int16Ty = IRB.getInt16Ty(); Int8Ty = IRB.getInt8Ty(); Int1Ty = IRB.getInt1Ty(); + Fp16Ty = IRB.getHalfTy(); + Fp32Ty = IRB.getFloatTy(); + Fp64Ty = IRB.getDoubleTy(); SanCovTracePCIndir = M.getOrInsertFunction(SanCovTracePCIndirName, VoidTy, IntptrTy); @@ -470,6 +483,9 @@ IRB.getInt32Ty(), IRB.getInt32Ty()); SanCovTraceCmpFunction[3] = M.getOrInsertFunction(SanCovTraceCmp8, VoidTy, Int64Ty, Int64Ty); + SanCovTraceCmpFunction[4] = M.getOrInsertFunction(SanCovTraceCmpF2, VoidTy, Fp16Ty, Fp16Ty); + SanCovTraceCmpFunction[5] = M.getOrInsertFunction(SanCovTraceCmpF4, VoidTy, Fp32Ty, Fp32Ty); + SanCovTraceCmpFunction[6] = M.getOrInsertFunction(SanCovTraceCmpF8, VoidTy, Fp64Ty, Fp64Ty); SanCovTraceConstCmpFunction[0] = M.getOrInsertFunction( SanCovTraceConstCmp1, SanCovTraceCmpZeroExtAL, VoidTy, Int8Ty, Int8Ty); @@ -479,6 +495,12 @@ SanCovTraceConstCmp4, SanCovTraceCmpZeroExtAL, VoidTy, Int32Ty, Int32Ty); SanCovTraceConstCmpFunction[3] = M.getOrInsertFunction(SanCovTraceConstCmp8, VoidTy, Int64Ty, Int64Ty); + SanCovTraceConstCmpFunction[4] = + M.getOrInsertFunction(SanCovTraceConstCmpF2, VoidTy, Fp16Ty, Fp16Ty); + SanCovTraceConstCmpFunction[5] = + M.getOrInsertFunction(SanCovTraceConstCmpF4, VoidTy, Fp32Ty, Fp32Ty); + SanCovTraceConstCmpFunction[6] = + M.getOrInsertFunction(SanCovTraceConstCmpF8, VoidTy, Fp64Ty, Fp64Ty); // Loads. SanCovLoadFunction[0] = M.getOrInsertFunction(SanCovLoad1, VoidTy, Int8PtrTy); @@ -633,7 +655,7 @@ // // Note that Cmp pruning is controlled by the same flag as the // BB pruning. -static bool IsInterestingCmp(ICmpInst *CMP, const DominatorTree *DT, +static bool IsInterestingCmp(Instruction *CMP, const DominatorTree *DT, const SanitizerCoverageOptions &Options) { if (!Options.NoPrune) if (CMP->hasOneUse()) @@ -678,7 +700,8 @@ SplitAllCriticalEdges(F, CriticalEdgeSplittingOptions().setIgnoreUnreachableDests()); SmallVector<Instruction *, 8> IndirCalls; SmallVector<BasicBlock *, 16> BlocksToInstrument; - SmallVector<Instruction *, 8> CmpTraceTargets; + SmallVector<Instruction *, 8> ICmpTraceTargets; + SmallVector<Instruction *, 8> FCmpTraceTargets; SmallVector<Instruction *, 8> SwitchTraceTargets; SmallVector<BinaryOperator *, 8> DivTraceTargets; SmallVector<GetElementPtrInst *, 8> GepTraceTargets; @@ -701,7 +724,10 @@ if (Options.TraceCmp) { if (ICmpInst *CMP = dyn_cast<ICmpInst>(&Inst)) if (IsInterestingCmp(CMP, DT, Options)) - CmpTraceTargets.push_back(&Inst); + ICmpTraceTargets.push_back(&Inst); + if (FCmpInst *CMP = dyn_cast<FCmpInst>(&Inst)) + if (IsInterestingCmp(CMP, DT, Options)) + FCmpTraceTargets.push_back(&Inst); if (isa<SwitchInst>(&Inst)) SwitchTraceTargets.push_back(&Inst); } @@ -728,7 +754,8 @@ InjectCoverage(F, BlocksToInstrument, IsLeafFunc); InjectCoverageForIndirectCalls(F, IndirCalls); - InjectTraceForCmp(F, CmpTraceTargets); + InjectTraceForCmp(F, ICmpTraceTargets); + InjectTraceForCmp(F, FCmpTraceTargets); InjectTraceForSwitch(F, SwitchTraceTargets); InjectTraceForDiv(F, DivTraceTargets); InjectTraceForGep(F, GepTraceTargets); @@ -952,22 +979,40 @@ void ModuleSanitizerCoverage::InjectTraceForCmp( Function &, ArrayRef<Instruction *> CmpTraceTargets) { for (auto I : CmpTraceTargets) { - if (ICmpInst *ICMP = dyn_cast<ICmpInst>(I)) { - IRBuilder<> IRB(ICMP); - Value *A0 = ICMP->getOperand(0); - Value *A1 = ICMP->getOperand(1); - if (!A0->getType()->isIntegerTy()) - continue; + if (isa<ICmpInst>(I) || isa<FCmpInst>(I)) { + auto IsIntComparison = isa<ICmpInst>(I); + IRBuilder<> IRB(I); + Value *A0 = I->getOperand(0); + Value *A1 = I->getOperand(1); + int CallbackIdx; + Type *CallbackArgsTy; uint64_t TypeSize = DL->getTypeStoreSizeInBits(A0->getType()); - int CallbackIdx = TypeSize == 8 ? 0 : - TypeSize == 16 ? 1 : - TypeSize == 32 ? 2 : - TypeSize == 64 ? 3 : -1; + CallbackIdx = IsIntComparison ? + (TypeSize == 8 ? 0 : + TypeSize == 16 ? 1 : + TypeSize == 32 ? 2 : + TypeSize == 64 ? 3 : -1) : + (A0->getType()->isHalfTy() ? 4 : + A0->getType()->isFloatTy() ? 5 : + A0->getType()->isDoubleTy() ? 6 : -1); if (CallbackIdx < 0) continue; + if (IsIntComparison) { + // integer comparison + if (!A0->getType()->isIntegerTy()) + continue; + CallbackArgsTy = Type::getIntNTy(*C, TypeSize); + } else { + // float comparison + if (!A0->getType()->isFloatingPointTy()) + continue; + CallbackArgsTy = (TypeSize == 16 ? Type::getHalfTy(*C) : + TypeSize == 32 ? Type::getFloatTy(*C) : + Type::getDoubleTy(*C)); + } // __sanitizer_cov_trace_cmp((type_size << 32) | predicate, A0, A1); auto CallbackFunc = SanCovTraceCmpFunction[CallbackIdx]; - bool FirstIsConst = isa<ConstantInt>(A0); - bool SecondIsConst = isa<ConstantInt>(A1); + bool FirstIsConst = isa<ConstantInt>(A0) || isa<ConstantFP>(A0); + bool SecondIsConst = isa<ConstantInt>(A1) || isa<ConstantFP>(A1); // If both are const, then we don't need such a comparison. if (FirstIsConst && SecondIsConst) continue; // If only one is const, then make it the first callback argument. @@ -976,10 +1021,8 @@ if (SecondIsConst) std::swap(A0, A1); } - - auto Ty = Type::getIntNTy(*C, TypeSize); - IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, Ty, true), - IRB.CreateIntCast(A1, Ty, true)}); + IRB.CreateCall(CallbackFunc, {IRB.CreateIntCast(A0, CallbackArgsTy, true), + IRB.CreateIntCast(A1, CallbackArgsTy, true)}); } } } Index: compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_coverage_libcdep_new.cpp @@ -247,10 +247,16 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} Index: compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc +++ compiler-rt/lib/sanitizer_common/sanitizer_coverage_interface.inc @@ -17,10 +17,16 @@ INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp2) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp4) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp_fp2) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp_fp4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_cmp_fp8) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp1) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp2) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp4) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp8) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp_fp2) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp_fp4) +INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_const_cmp_fp8) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div4) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_div8) INTERFACE_WEAK_FUNCTION(__sanitizer_cov_trace_gep) Index: compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp =================================================================== --- compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp +++ compiler-rt/lib/sanitizer_common/sanitizer_coverage_fuchsia.cpp @@ -239,10 +239,16 @@ SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_cmp_fp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp1, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp2, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp8, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp2, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp4, void) {} +SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_const_cmp_fp8, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_switch, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div4, void) {} SANITIZER_INTERFACE_WEAK_DEF(void, __sanitizer_cov_trace_div8, void) {} Index: compiler-rt/lib/dfsan/done_abilist.txt =================================================================== --- compiler-rt/lib/dfsan/done_abilist.txt +++ compiler-rt/lib/dfsan/done_abilist.txt @@ -401,6 +401,12 @@ fun:__sanitizer_cov_trace_cmp4=uninstrumented fun:__sanitizer_cov_trace_cmp8=custom fun:__sanitizer_cov_trace_cmp8=uninstrumented +fun:__sanitizer_cov_trace_cmp_fp2=custom +fun:__sanitizer_cov_trace_cmp_fp2=uninstrumented +fun:__sanitizer_cov_trace_cmp_fp4=custom +fun:__sanitizer_cov_trace_cmp_fp4=uninstrumented +fun:__sanitizer_cov_trace_cmp_fp8=custom +fun:__sanitizer_cov_trace_cmp_fp8=uninstrumented fun:__sanitizer_cov_trace_const_cmp1=custom fun:__sanitizer_cov_trace_const_cmp1=uninstrumented fun:__sanitizer_cov_trace_const_cmp2=custom @@ -409,6 +415,12 @@ fun:__sanitizer_cov_trace_const_cmp4=uninstrumented fun:__sanitizer_cov_trace_const_cmp8=custom fun:__sanitizer_cov_trace_const_cmp8=uninstrumented +fun:__sanitizer_cov_trace_const_cmp_fp2=custom +fun:__sanitizer_cov_trace_const_cmp_fp2=uninstrumented +fun:__sanitizer_cov_trace_const_cmp_fp4=custom +fun:__sanitizer_cov_trace_const_cmp_fp4=uninstrumented +fun:__sanitizer_cov_trace_const_cmp_fp8=custom +fun:__sanitizer_cov_trace_const_cmp_fp8=uninstrumented # Similar for __sanitizer_cov_trace_switch fun:__sanitizer_cov_trace_switch=custom fun:__sanitizer_cov_trace_switch=uninstrumented Index: clang/docs/SanitizerCoverage.rst =================================================================== --- clang/docs/SanitizerCoverage.rst +++ clang/docs/SanitizerCoverage.rst @@ -293,6 +293,9 @@ void __sanitizer_cov_trace_cmp2(uint16_t Arg1, uint16_t Arg2); void __sanitizer_cov_trace_cmp4(uint32_t Arg1, uint32_t Arg2); void __sanitizer_cov_trace_cmp8(uint64_t Arg1, uint64_t Arg2); + void __sanitizer_cov_trace_cmp_fp2(half Arg1, half Arg2); + void __sanitizer_cov_trace_cmp_fp4(float Arg1, float Arg2); + void __sanitizer_cov_trace_cmp_fp8(double Arg1, double Arg2); // Called before a comparison instruction if exactly one of the arguments is constant. // Arg1 and Arg2 are arguments of the comparison, Arg1 is a compile-time constant. @@ -301,6 +304,9 @@ void __sanitizer_cov_trace_const_cmp2(uint16_t Arg1, uint16_t Arg2); void __sanitizer_cov_trace_const_cmp4(uint32_t Arg1, uint32_t Arg2); void __sanitizer_cov_trace_const_cmp8(uint64_t Arg1, uint64_t Arg2); + void __sanitizer_cov_trace_const_cmp_fp2(half Arg1, half Arg2); + void __sanitizer_cov_trace_const_cmp_fp4(float Arg1, float Arg2); + void __sanitizer_cov_trace_const_cmp_fp8(double Arg1, double Arg2); // Called before a switch statement. // Val is the switch operand.
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits