diff --git a/llvm/include/llvm/Transforms/IPO/Instrumentor.h b/llvm/include/llvm/Transforms/IPO/Instrumentor.h index 64a3a2afd04b7..3f45543d3fe2d 100644 --- a/llvm/include/llvm/Transforms/IPO/Instrumentor.h +++ b/llvm/include/llvm/Transforms/IPO/Instrumentor.h @@ -1072,8 +1072,6 @@ struct CastIO final InstrumentorIRBuilderTy &IIRB); static Value *getResultSize(Value &V, Type &Ty, InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB); - static Value *getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, - InstrumentorIRBuilderTy &IIRB); static void populate(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB) { @@ -1086,6 +1084,55 @@ struct CastIO final } }; +/// Instrumentation opportunity for numeric operations. This includes Add, FAdd, +/// Sub, FSub, Mul, FMul, UDiv, FDiv, SDiv, URem, SRem, FRem, Shl, LShr, AShr, +/// And, Or, Xor, and FNeg. +struct NumericIO : public InstructionIO< + Instruction::Add, Instruction::FAdd, Instruction::Sub, + Instruction::FSub, Instruction::Mul, Instruction::FMul, + Instruction::UDiv, Instruction::FDiv, Instruction::SDiv, + Instruction::URem, Instruction::SRem, Instruction::FRem, + Instruction::Shl, Instruction::LShr, Instruction::AShr, + Instruction::And, Instruction::Or, Instruction::Xor, + Instruction::FNeg> { + NumericIO(InstrumentationLocation::KindTy Kind) : InstructionIO(Kind) {} + + enum ConfigKind { + PassTypeId, + PassSize, + PassOpcode, + PassResult, + ReplaceResult, + PassLeft, + PassRight, + PassId, + NumConfig, + }; + + using ConfigTy = BaseConfigTy; + ConfigTy Config; + + StringRef getName() const override { return "numeric"; } + + void init(InstrumentationConfig &IConf, InstrumentorIRBuilderTy &IIRB, + ConfigTy *UserConfig = nullptr); + + static Value *getLeft(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB); + static Value *getRight(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB); + + static void populate(InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { + auto *PreIO = + IConf.allocate(InstrumentationLocation::INSTRUCTION_PRE); + PreIO->init(IConf, IIRB); + auto *PostIO = + IConf.allocate(InstrumentationLocation::INSTRUCTION_POST); + PostIO->init(IConf, IIRB); + } +}; + } // namespace instrumentor /// The Instrumentor pass. diff --git a/llvm/lib/Transforms/IPO/Instrumentor.cpp b/llvm/lib/Transforms/IPO/Instrumentor.cpp index 8b374b5c0eb96..46cbb85b7196c 100644 --- a/llvm/lib/Transforms/IPO/Instrumentor.cpp +++ b/llvm/lib/Transforms/IPO/Instrumentor.cpp @@ -555,6 +555,7 @@ void InstrumentationConfig::populate(InstrumentorIRBuilderTy &IIRB) { LoadIO::populate(*this, IIRB); StoreIO::populate(*this, IIRB); CastIO::populate(*this, IIRB); + NumericIO::populate(*this, IIRB); } void InstrumentationConfig::addChoice(InstrumentationOpportunity &IO, @@ -998,7 +999,23 @@ Value *FunctionIO::isMainFunction(Value &V, Type &Ty, return getCI(&Ty, Fn.getName() == "main"); } -///} +static Value *getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { + auto &I = cast(V); + return getCI(&Ty, I.getOpcode()); +} + +static Value *getTypeId(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { + return getCI(&Ty, V.getType()->getTypeID()); +} + +static Value *getSize(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { + auto &I = cast(V); + auto &DL = I.getDataLayout(); + return getCI(&Ty, DL.getTypeStoreSize(V.getType())); +} /// UnreachableIO ///{ @@ -1670,10 +1687,55 @@ Value *CastIO::getResultSize(Value &V, Type &Ty, InstrumentationConfig &IConf, auto &DL = CI.getDataLayout(); return getCI(&Ty, DL.getTypeStoreSize(CI.getDestTy())); } +///} -Value *CastIO::getOpcode(Value &V, Type &Ty, InstrumentationConfig &IConf, - InstrumentorIRBuilderTy &IIRB) { +Value *NumericIO::getLeft(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { auto &I = cast(V); - return getCI(&Ty, I.getOpcode()); + return I.getOperand(0); +} + +Value *NumericIO::getRight(Value &V, Type &Ty, InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB) { + auto &I = cast(V); + if (I.getNumOperands() > 1) + return I.getOperand(1); + else + return PoisonValue::get(&Ty); +} + +void NumericIO::init(InstrumentationConfig &IConf, + InstrumentorIRBuilderTy &IIRB, ConfigTy *UserConfig) { + if (UserConfig) + Config = UserConfig; + bool IsPRE = getLocationKind() == InstrumentationLocation::INSTRUCTION_PRE; + const auto ValArgOpts = + IRTArg::POTENTIALLY_INDIRECT | + (Config.has(PassSize) ? IRTArg::INDIRECT_HAS_SIZE : IRTArg::NONE); + if (Config.has(PassTypeId)) + IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "type_id", + "The operation's type id.", IRTArg::NONE, + getTypeId)); + if (Config.has(PassSize)) + IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "size", "The operation's type size.", + IRTArg::NONE, getSize)); + if (Config.has(PassOpcode)) + IRTArgs.push_back(IRTArg(IIRB.Int32Ty, "opcode", "The instruction opcode.", + IRTArg::NONE, getOpcode)); + if (Config.has(PassLeft)) + IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "left", + "The operation's left operand.", ValArgOpts, + getLeft)); + if (Config.has(PassRight)) + IRTArgs.push_back(IRTArg(IIRB.Int64Ty, "right", + "The operation's right operand. This value is " + "poison for unary operations.", + ValArgOpts, getRight)); + if (!IsPRE && Config.has(PassResult)) + IRTArgs.push_back( + IRTArg(IIRB.Int64Ty, "result", "Result of the operation.", + IRTArg::REPLACABLE | ValArgOpts, getValue, + Config.has(ReplaceResult) ? replaceValue : nullptr)); + addCommonArgs(IConf, IIRB.Ctx, Config.has(PassId)); + IConf.addChoice(*this, IIRB.Ctx); } -///} diff --git a/llvm/test/Instrumentation/Instrumentor/default_config.json b/llvm/test/Instrumentation/Instrumentor/default_config.json index fc4177ae74929..8357389c9c43b 100644 --- a/llvm/test/Instrumentation/Instrumentor/default_config.json +++ b/llvm/test/Instrumentation/Instrumentor/default_config.json @@ -223,6 +223,23 @@ "opcode.description": "The opcode of the cast instruction.", "id": true, "id.description": "A unique ID associated with the given instrumentor call" + }, + "numeric": { + "enabled": true, + "filter": "", + "filter.description": "Static property filter to exclude instrumentation.", + "type_id": true, + "type_id.description": "The operation's type id.", + "size": true, + "size.description": "The operation's type size.", + "opcode": true, + "opcode.description": "The instruction opcode.", + "left": true, + "left.description": "The operation's left operand.", + "right": true, + "right.description": "The operation's right operand. This value is poison for unary operations.", + "id": true, + "id.description": "A unique ID associated with the given instrumentor call" } }, "instruction_post": { @@ -316,6 +333,26 @@ "opcode.description": "The opcode of the cast instruction.", "id": true, "id.description": "A unique ID associated with the given instrumentor call" + }, + "numeric": { + "enabled": true, + "filter": "", + "filter.description": "Static property filter to exclude instrumentation.", + "type_id": true, + "type_id.description": "The operation's type id.", + "size": true, + "size.description": "The operation's type size.", + "opcode": true, + "opcode.description": "The instruction opcode.", + "left": true, + "left.description": "The operation's left operand.", + "right": true, + "right.description": "The operation's right operand. This value is poison for unary operations.", + "result": true, + "result.replace": true, + "result.description": "Result of the operation.", + "id": true, + "id.description": "A unique ID associated with the given instrumentor call" } }, "special_value": { diff --git a/llvm/test/Instrumentation/Instrumentor/module_and_globals.ll b/llvm/test/Instrumentation/Instrumentor/module_and_globals.ll index e771e6d408706..2e5730c39cc68 100644 --- a/llvm/test/Instrumentation/Instrumentor/module_and_globals.ll +++ b/llvm/test/Instrumentation/Instrumentor/module_and_globals.ll @@ -32,7 +32,7 @@ entry: ;. ; CHECK-LABEL: define i32 @foo() { ; CHECK-NEXT: [[ENTRY:.*:]] -; CHECK-NEXT: call void @__instrumentor_pre_function(ptr @foo, ptr @__instrumentor_.str.5, i32 0, ptr null, i8 0, i32 12) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: call void @__instrumentor_pre_function(ptr @foo, ptr @__instrumentor_.str.5, i32 0, ptr null, i8 0, i32 14) #[[ATTR0:[0-9]+]] ; CHECK-NEXT: [[Z_SHADOW_LOAD:%.*]] = load ptr, ptr @__instrumentor_shadow.Z, align 8 ; CHECK-NEXT: [[TMP0:%.*]] = call ptr @__instrumentor_post_base_pointer_info(ptr [[Z_SHADOW_LOAD]], i32 2, i32 -11) #[[ATTR0]] ; CHECK-NEXT: [[Y_SHADOW_LOAD:%.*]] = load ptr, ptr @__instrumentor_shadow.Y, align 8 @@ -45,18 +45,30 @@ entry: ; CHECK-NEXT: [[TMP13:%.*]] = call i64 @__instrumentor_post_load(ptr [[X_SHADOW_LOAD]], i32 0, ptr [[TMP2]], i64 [[TMP12]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 -9) #[[ATTR0]] ; CHECK-NEXT: [[TMP14:%.*]] = trunc i64 [[TMP13]] to i32 ; CHECK-NEXT: [[TMP8:%.*]] = call ptr @__instrumentor_pre_load(ptr [[Y_SHADOW_LOAD]], i32 0, ptr [[TMP1]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 10) #[[ATTR0]] -; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP8]], align 4 -; CHECK-NEXT: [[TMP18:%.*]] = zext i32 [[TMP9]] to i64 -; CHECK-NEXT: [[TMP19:%.*]] = call i64 @__instrumentor_post_load(ptr [[Y_SHADOW_LOAD]], i32 0, ptr [[TMP1]], i64 [[TMP18]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 -10) #[[ATTR0]] -; CHECK-NEXT: [[TMP20:%.*]] = trunc i64 [[TMP19]] to i32 -; CHECK-NEXT: [[TMP21:%.*]] = call ptr @__instrumentor_pre_load(ptr [[Z_SHADOW_LOAD]], i32 0, ptr [[TMP0]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 11) #[[ATTR0]] -; CHECK-NEXT: [[TMP22:%.*]] = load i32, ptr [[TMP21]], align 4 -; CHECK-NEXT: [[TMP15:%.*]] = zext i32 [[TMP22]] to i64 -; CHECK-NEXT: [[TMP16:%.*]] = call i64 @__instrumentor_post_load(ptr [[Z_SHADOW_LOAD]], i32 0, ptr [[TMP0]], i64 [[TMP15]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 -11) #[[ATTR0]] -; CHECK-NEXT: [[TMP17:%.*]] = trunc i64 [[TMP16]] to i32 -; CHECK-NEXT: [[ADD1:%.*]] = add nsw i32 [[TMP14]], [[TMP20]] -; CHECK-NEXT: [[ADD2:%.*]] = add nsw i32 [[ADD1]], [[TMP17]] -; CHECK-NEXT: call void @__instrumentor_post_function(ptr @foo, ptr @__instrumentor_.str.5, i32 0, ptr null, i8 0, i32 -13) #[[ATTR0]] +; CHECK-NEXT: [[TMP4:%.*]] = load i32, ptr [[TMP8]], align 4 +; CHECK-NEXT: [[TMP15:%.*]] = zext i32 [[TMP4]] to i64 +; CHECK-NEXT: [[TMP21:%.*]] = call i64 @__instrumentor_post_load(ptr [[Y_SHADOW_LOAD]], i32 0, ptr [[TMP1]], i64 [[TMP15]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 -10) #[[ATTR0]] +; CHECK-NEXT: [[TMP25:%.*]] = trunc i64 [[TMP21]] to i32 +; CHECK-NEXT: [[TMP26:%.*]] = call ptr @__instrumentor_pre_load(ptr [[Z_SHADOW_LOAD]], i32 0, ptr [[TMP0]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 11) #[[ATTR0]] +; CHECK-NEXT: [[TMP9:%.*]] = load i32, ptr [[TMP26]], align 4 +; CHECK-NEXT: [[TMP16:%.*]] = zext i32 [[TMP9]] to i64 +; CHECK-NEXT: [[TMP27:%.*]] = call i64 @__instrumentor_post_load(ptr [[Z_SHADOW_LOAD]], i32 0, ptr [[TMP0]], i64 [[TMP16]], i64 4, i64 4, i32 12, i32 0, i8 1, i8 0, i32 -11) #[[ATTR0]] +; CHECK-NEXT: [[TMP28:%.*]] = trunc i64 [[TMP27]] to i32 +; CHECK-NEXT: [[TMP29:%.*]] = zext i32 [[TMP14]] to i64 +; CHECK-NEXT: [[TMP30:%.*]] = zext i32 [[TMP25]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 14, i64 [[TMP29]], i64 [[TMP30]], i32 12) #[[ATTR0]] +; CHECK-NEXT: [[ADD:%.*]] = add nsw i32 [[TMP14]], [[TMP25]] +; CHECK-NEXT: [[TMP17:%.*]] = zext i32 [[ADD]] to i64 +; CHECK-NEXT: [[TMP18:%.*]] = call i64 @__instrumentor_post_numeric(i64 12, i32 4, i32 14, i64 [[TMP29]], i64 [[TMP30]], i64 [[TMP17]], i32 -12) #[[ATTR0]] +; CHECK-NEXT: [[TMP19:%.*]] = trunc i64 [[TMP18]] to i32 +; CHECK-NEXT: [[TMP20:%.*]] = zext i32 [[TMP19]] to i64 +; CHECK-NEXT: [[TMP24:%.*]] = zext i32 [[TMP28]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 14, i64 [[TMP20]], i64 [[TMP24]], i32 13) #[[ATTR0]] +; CHECK-NEXT: [[ADD3:%.*]] = add nsw i32 [[TMP19]], [[TMP28]] +; CHECK-NEXT: [[TMP22:%.*]] = zext i32 [[ADD3]] to i64 +; CHECK-NEXT: [[TMP23:%.*]] = call i64 @__instrumentor_post_numeric(i64 12, i32 4, i32 14, i64 [[TMP20]], i64 [[TMP24]], i64 [[TMP22]], i32 -13) #[[ATTR0]] +; CHECK-NEXT: [[ADD2:%.*]] = trunc i64 [[TMP23]] to i32 +; CHECK-NEXT: call void @__instrumentor_post_function(ptr @foo, ptr @__instrumentor_.str.5, i32 0, ptr null, i8 0, i32 -15) #[[ATTR0]] ; CHECK-NEXT: ret i32 [[ADD2]] ; ; diff --git a/llvm/test/Instrumentation/Instrumentor/operations.json b/llvm/test/Instrumentation/Instrumentor/operations.json new file mode 100644 index 0000000000000..72c9d60669f85 --- /dev/null +++ b/llvm/test/Instrumentation/Instrumentor/operations.json @@ -0,0 +1,28 @@ +{ + "configuration": { + "runtime_prefix": "__instrumentor_" + }, + "instruction_pre": { + "numeric": { + "enabled": true, + "type_id": true, + "size": true, + "opcode": true, + "left": true, + "right": true, + "id": true + } + }, + "instruction_post": { + "numeric": { + "enabled": true, + "type_id": true, + "size": true, + "opcode": true, + "left": true, + "right": true, + "result": true, + "id": true + } + } +} diff --git a/llvm/test/Instrumentation/Instrumentor/operations.ll b/llvm/test/Instrumentation/Instrumentor/operations.ll new file mode 100644 index 0000000000000..8a4e67b00cee5 --- /dev/null +++ b/llvm/test/Instrumentation/Instrumentor/operations.ll @@ -0,0 +1,280 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6 +; RUN: opt < %s -passes=instrumentor -instrumentor-read-config-files=%S/operations.json -S | FileCheck %s + +define float @test_float(float %p1, float %p2) { +; CHECK-LABEL: define float @test_float( +; CHECK-SAME: float [[P1:%.*]], float [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = bitcast float [[P1]] to i32 +; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[TMP0]] to i64 +; CHECK-NEXT: [[TMP2:%.*]] = bitcast float [[P2]] to i32 +; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[TMP2]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 2, i32 4, i32 15, i64 [[TMP1]], i64 [[TMP3]], i32 1) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: [[A1:%.*]] = fadd float [[P1]], [[P2]] +; CHECK-NEXT: [[TMP4:%.*]] = bitcast float [[A1]] to i32 +; CHECK-NEXT: [[TMP5:%.*]] = zext i32 [[TMP4]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 2, i32 4, i32 15, i64 [[TMP1]], i64 [[TMP3]], i64 [[TMP5]], i32 -1) #[[ATTR0]] +; CHECK-NEXT: [[TMP6:%.*]] = bitcast float [[P1]] to i32 +; CHECK-NEXT: [[TMP7:%.*]] = zext i32 [[TMP6]] to i64 +; CHECK-NEXT: [[TMP8:%.*]] = bitcast float [[A1]] to i32 +; CHECK-NEXT: [[TMP9:%.*]] = zext i32 [[TMP8]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 2, i32 4, i32 19, i64 [[TMP7]], i64 [[TMP9]], i32 2) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = fmul float [[P1]], [[A1]] +; CHECK-NEXT: [[TMP10:%.*]] = bitcast float [[A2]] to i32 +; CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[TMP10]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 2, i32 4, i32 19, i64 [[TMP7]], i64 [[TMP9]], i64 [[TMP11]], i32 -2) #[[ATTR0]] +; CHECK-NEXT: [[TMP12:%.*]] = bitcast float [[A2]] to i32 +; CHECK-NEXT: [[TMP13:%.*]] = zext i32 [[TMP12]] to i64 +; CHECK-NEXT: [[TMP14:%.*]] = bitcast float [[P2]] to i32 +; CHECK-NEXT: [[TMP15:%.*]] = zext i32 [[TMP14]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 2, i32 4, i32 22, i64 [[TMP13]], i64 [[TMP15]], i32 3) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = fdiv float [[A2]], [[P2]] +; CHECK-NEXT: [[TMP16:%.*]] = bitcast float [[A3]] to i32 +; CHECK-NEXT: [[TMP17:%.*]] = zext i32 [[TMP16]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 2, i32 4, i32 22, i64 [[TMP13]], i64 [[TMP15]], i64 [[TMP17]], i32 -3) #[[ATTR0]] +; CHECK-NEXT: [[TMP18:%.*]] = bitcast float [[A3]] to i32 +; CHECK-NEXT: [[TMP19:%.*]] = zext i32 [[TMP18]] to i64 +; CHECK-NEXT: [[TMP20:%.*]] = bitcast float [[A1]] to i32 +; CHECK-NEXT: [[TMP21:%.*]] = zext i32 [[TMP20]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 2, i32 4, i32 17, i64 [[TMP19]], i64 [[TMP21]], i32 4) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = fsub float [[A3]], [[A1]] +; CHECK-NEXT: [[TMP22:%.*]] = bitcast float [[A4]] to i32 +; CHECK-NEXT: [[TMP23:%.*]] = zext i32 [[TMP22]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 2, i32 4, i32 17, i64 [[TMP19]], i64 [[TMP21]], i64 [[TMP23]], i32 -4) #[[ATTR0]] +; CHECK-NEXT: [[TMP24:%.*]] = bitcast float [[A4]] to i32 +; CHECK-NEXT: [[TMP25:%.*]] = zext i32 [[TMP24]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 2, i32 4, i32 13, i64 [[TMP25]], i64 poison, i32 5) #[[ATTR0]] +; CHECK-NEXT: [[A5:%.*]] = fneg float [[A4]] +; CHECK-NEXT: [[TMP26:%.*]] = bitcast float [[A5]] to i32 +; CHECK-NEXT: [[TMP27:%.*]] = zext i32 [[TMP26]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 2, i32 4, i32 13, i64 [[TMP25]], i64 poison, i64 [[TMP27]], i32 -5) #[[ATTR0]] +; CHECK-NEXT: ret float [[A5]] +; +entry: + %a1 = fadd float %p1, %p2 + %a2 = fmul float %p1, %a1 + %a3 = fdiv float %a2, %p2 + %a4 = fsub float %a3, %a1 + %a5 = fneg float %a4 + ret float %a5 +} + +define double @test_double(double %p1, double %p2) { +; CHECK-LABEL: define double @test_double( +; CHECK-SAME: double [[P1:%.*]], double [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = bitcast double [[P1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = bitcast double [[P2]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 3, i32 8, i32 15, i64 [[TMP0]], i64 [[TMP1]], i32 6) #[[ATTR0]] +; CHECK-NEXT: [[A1:%.*]] = fadd double [[P1]], [[P2]] +; CHECK-NEXT: [[TMP2:%.*]] = bitcast double [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 3, i32 8, i32 15, i64 [[TMP0]], i64 [[TMP1]], i64 [[TMP2]], i32 -6) #[[ATTR0]] +; CHECK-NEXT: [[TMP3:%.*]] = bitcast double [[P1]] to i64 +; CHECK-NEXT: [[TMP4:%.*]] = bitcast double [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 3, i32 8, i32 19, i64 [[TMP3]], i64 [[TMP4]], i32 7) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = fmul double [[P1]], [[A1]] +; CHECK-NEXT: [[TMP5:%.*]] = bitcast double [[A2]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 3, i32 8, i32 19, i64 [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], i32 -7) #[[ATTR0]] +; CHECK-NEXT: [[TMP6:%.*]] = bitcast double [[A2]] to i64 +; CHECK-NEXT: [[TMP7:%.*]] = bitcast double [[P2]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 3, i32 8, i32 25, i64 [[TMP6]], i64 [[TMP7]], i32 8) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = frem double [[A2]], [[P2]] +; CHECK-NEXT: [[TMP8:%.*]] = bitcast double [[A3]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 3, i32 8, i32 25, i64 [[TMP6]], i64 [[TMP7]], i64 [[TMP8]], i32 -8) #[[ATTR0]] +; CHECK-NEXT: [[TMP9:%.*]] = bitcast double [[A3]] to i64 +; CHECK-NEXT: [[TMP10:%.*]] = bitcast double [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 3, i32 8, i32 17, i64 [[TMP9]], i64 [[TMP10]], i32 9) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = fsub double [[A3]], [[A1]] +; CHECK-NEXT: [[TMP11:%.*]] = bitcast double [[A4]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 3, i32 8, i32 17, i64 [[TMP9]], i64 [[TMP10]], i64 [[TMP11]], i32 -9) #[[ATTR0]] +; CHECK-NEXT: [[TMP12:%.*]] = bitcast double [[A4]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 3, i32 8, i32 13, i64 [[TMP12]], i64 poison, i32 10) #[[ATTR0]] +; CHECK-NEXT: [[A5:%.*]] = fneg double [[A4]] +; CHECK-NEXT: [[TMP13:%.*]] = bitcast double [[A5]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 3, i32 8, i32 13, i64 [[TMP12]], i64 poison, i64 [[TMP13]], i32 -10) #[[ATTR0]] +; CHECK-NEXT: ret double [[A5]] +; +entry: + %a1 = fadd double %p1, %p2 + %a2 = fmul double %p1, %a1 + %a3 = frem double %a2, %p2 + %a4 = fsub double %a3, %a1 + %a5 = fneg double %a4 + ret double %a5 +} + +define fp128 @test_fp128(fp128 %p1, fp128 %p2) { +; CHECK-LABEL: define fp128 @test_fp128( +; CHECK-SAME: fp128 [[P1:%.*]], fp128 [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = alloca i64, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = alloca fp128, align 16 +; CHECK-NEXT: [[TMP2:%.*]] = alloca fp128, align 16 +; CHECK-NEXT: [[TMP3:%.*]] = alloca fp128, align 16 +; CHECK-NEXT: store fp128 [[P1]], ptr [[TMP3]], align 16 +; CHECK-NEXT: store fp128 [[P2]], ptr [[TMP2]], align 16 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 5, i32 16, i32 15, ptr [[TMP3]], ptr [[TMP2]], i32 11) #[[ATTR0]] +; CHECK-NEXT: [[A1:%.*]] = fadd fp128 [[P1]], [[P2]] +; CHECK-NEXT: store fp128 [[A1]], ptr [[TMP1]], align 16 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 5, i32 16, i32 15, ptr [[TMP3]], ptr [[TMP2]], ptr [[TMP1]], i32 -11) #[[ATTR0]] +; CHECK-NEXT: store fp128 [[P1]], ptr [[TMP3]], align 16 +; CHECK-NEXT: store fp128 [[A1]], ptr [[TMP1]], align 16 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 5, i32 16, i32 19, ptr [[TMP3]], ptr [[TMP1]], i32 12) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = fmul fp128 [[P1]], [[A1]] +; CHECK-NEXT: store fp128 [[A2]], ptr [[TMP2]], align 16 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 5, i32 16, i32 19, ptr [[TMP3]], ptr [[TMP1]], ptr [[TMP2]], i32 -12) #[[ATTR0]] +; CHECK-NEXT: store fp128 [[A2]], ptr [[TMP3]], align 16 +; CHECK-NEXT: store fp128 [[P2]], ptr [[TMP2]], align 16 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 5, i32 16, i32 22, ptr [[TMP3]], ptr [[TMP2]], i32 13) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = fdiv fp128 [[A2]], [[P2]] +; CHECK-NEXT: store fp128 [[A3]], ptr [[TMP1]], align 16 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 5, i32 16, i32 22, ptr [[TMP3]], ptr [[TMP2]], ptr [[TMP1]], i32 -13) #[[ATTR0]] +; CHECK-NEXT: store fp128 [[A3]], ptr [[TMP3]], align 16 +; CHECK-NEXT: store fp128 [[A1]], ptr [[TMP1]], align 16 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 5, i32 16, i32 17, ptr [[TMP3]], ptr [[TMP1]], i32 14) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = fsub fp128 [[A3]], [[A1]] +; CHECK-NEXT: store fp128 [[A4]], ptr [[TMP2]], align 16 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 5, i32 16, i32 17, ptr [[TMP3]], ptr [[TMP1]], ptr [[TMP2]], i32 -14) #[[ATTR0]] +; CHECK-NEXT: store fp128 [[A4]], ptr [[TMP3]], align 16 +; CHECK-NEXT: store i64 poison, ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 5, i32 16, i32 13, ptr [[TMP3]], ptr [[TMP0]], i32 15) #[[ATTR0]] +; CHECK-NEXT: [[A5:%.*]] = fneg fp128 [[A4]] +; CHECK-NEXT: store fp128 [[A5]], ptr [[TMP2]], align 16 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 5, i32 16, i32 13, ptr [[TMP3]], ptr [[TMP0]], ptr [[TMP2]], i32 -15) #[[ATTR0]] +; CHECK-NEXT: ret fp128 [[A5]] +; +entry: + %a1 = fadd fp128 %p1, %p2 + %a2 = fmul fp128 %p1, %a1 + %a3 = fdiv fp128 %a2, %p2 + %a4 = fsub fp128 %a3, %a1 + %a5 = fneg fp128 %a4 + ret fp128 %a5 +} + +define i32 @test_i32(i32 %p1, i32 %p2) { +; CHECK-LABEL: define i32 @test_i32( +; CHECK-SAME: i32 [[P1:%.*]], i32 [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[P1]] to i64 +; CHECK-NEXT: [[TMP1:%.*]] = zext i32 [[P2]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 14, i64 [[TMP0]], i64 [[TMP1]], i32 16) #[[ATTR0]] +; CHECK-NEXT: [[A1:%.*]] = add i32 [[P1]], [[P2]] +; CHECK-NEXT: [[TMP2:%.*]] = zext i32 [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 4, i32 14, i64 [[TMP0]], i64 [[TMP1]], i64 [[TMP2]], i32 -16) #[[ATTR0]] +; CHECK-NEXT: [[TMP3:%.*]] = zext i32 [[P1]] to i64 +; CHECK-NEXT: [[TMP4:%.*]] = zext i32 [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 18, i64 [[TMP3]], i64 [[TMP4]], i32 17) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = mul i32 [[P1]], [[A1]] +; CHECK-NEXT: [[TMP5:%.*]] = zext i32 [[A2]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 4, i32 18, i64 [[TMP3]], i64 [[TMP4]], i64 [[TMP5]], i32 -17) #[[ATTR0]] +; CHECK-NEXT: [[TMP6:%.*]] = zext i32 [[A2]] to i64 +; CHECK-NEXT: [[TMP7:%.*]] = zext i32 [[P2]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 21, i64 [[TMP6]], i64 [[TMP7]], i32 18) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = sdiv i32 [[A2]], [[P2]] +; CHECK-NEXT: [[TMP8:%.*]] = zext i32 [[A3]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 4, i32 21, i64 [[TMP6]], i64 [[TMP7]], i64 [[TMP8]], i32 -18) #[[ATTR0]] +; CHECK-NEXT: [[TMP9:%.*]] = zext i32 [[A3]] to i64 +; CHECK-NEXT: [[TMP10:%.*]] = zext i32 [[A1]] to i64 +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 4, i32 16, i64 [[TMP9]], i64 [[TMP10]], i32 19) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = sub i32 [[A3]], [[A1]] +; CHECK-NEXT: [[TMP11:%.*]] = zext i32 [[A4]] to i64 +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 4, i32 16, i64 [[TMP9]], i64 [[TMP10]], i64 [[TMP11]], i32 -19) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[A4]] +; +entry: + %a1 = add i32 %p1, %p2 + %a2 = mul i32 %p1, %a1 + %a3 = sdiv i32 %a2, %p2 + %a4 = sub i32 %a3, %a1 + ret i32 %a4 +} + +define i64 @test_i64(i64 %p1, i64 %p2) { +; CHECK-LABEL: define i64 @test_i64( +; CHECK-SAME: i64 [[P1:%.*]], i64 [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 14, i64 [[P1]], i64 [[P2]], i32 20) #[[ATTR0]] +; CHECK-NEXT: [[A1:%.*]] = add i64 [[P1]], [[P2]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 14, i64 [[P1]], i64 [[P2]], i64 [[A1]], i32 -20) #[[ATTR0]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 18, i64 [[P1]], i64 [[A1]], i32 21) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = mul i64 [[P1]], [[A1]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 18, i64 [[P1]], i64 [[A1]], i64 [[A2]], i32 -21) #[[ATTR0]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 20, i64 [[A2]], i64 [[P2]], i32 22) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = udiv i64 [[A2]], [[P2]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 20, i64 [[A2]], i64 [[P2]], i64 [[A3]], i32 -22) #[[ATTR0]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 16, i64 [[A3]], i64 [[A1]], i32 23) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = sub i64 [[A3]], [[A1]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 16, i64 [[A3]], i64 [[A1]], i64 [[A4]], i32 -23) #[[ATTR0]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 29, i64 [[A4]], i64 [[A2]], i32 24) #[[ATTR0]] +; CHECK-NEXT: [[A5:%.*]] = and i64 [[A4]], [[A2]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 29, i64 [[A4]], i64 [[A2]], i64 [[A5]], i32 -24) #[[ATTR0]] +; CHECK-NEXT: call void @__instrumentor_pre_numeric(i64 12, i32 8, i32 31, i64 [[A5]], i64 [[A3]], i32 25) #[[ATTR0]] +; CHECK-NEXT: [[A6:%.*]] = xor i64 [[A5]], [[A3]] +; CHECK-NEXT: call void @__instrumentor_post_numeric(i64 12, i32 8, i32 31, i64 [[A5]], i64 [[A3]], i64 [[A6]], i32 -25) #[[ATTR0]] +; CHECK-NEXT: ret i64 [[A6]] +; +entry: + %a1 = add i64 %p1, %p2 + %a2 = mul i64 %p1, %a1 + %a3 = udiv i64 %a2, %p2 + %a4 = sub i64 %a3, %a1 + %a5 = and i64 %a4, %a2 + %a6 = xor i64 %a5, %a3 + ret i64 %a6 +} + +define i128 @test_i128(i128 %p1, i128 %p2) { +; CHECK-LABEL: define i128 @test_i128( +; CHECK-SAME: i128 [[P1:%.*]], i128 [[P2:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[TMP0:%.*]] = alloca i128, align 8 +; CHECK-NEXT: [[TMP1:%.*]] = alloca i128, align 8 +; CHECK-NEXT: [[TMP2:%.*]] = alloca i128, align 8 +; CHECK-NEXT: store i128 [[P1]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[P2]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 14, ptr [[TMP2]], ptr [[TMP1]], i32 26) #[[ATTR0]] +; CHECK-NEXT: [[A1:%.*]] = add i128 [[P1]], [[P2]] +; CHECK-NEXT: store i128 [[A1]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 14, ptr [[TMP2]], ptr [[TMP1]], ptr [[TMP0]], i32 -26) #[[ATTR0]] +; CHECK-NEXT: store i128 [[P1]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[A1]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 18, ptr [[TMP2]], ptr [[TMP0]], i32 27) #[[ATTR0]] +; CHECK-NEXT: [[A2:%.*]] = mul i128 [[P1]], [[A1]] +; CHECK-NEXT: store i128 [[A2]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 18, ptr [[TMP2]], ptr [[TMP0]], ptr [[TMP1]], i32 -27) #[[ATTR0]] +; CHECK-NEXT: store i128 [[A2]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[P2]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 24, ptr [[TMP2]], ptr [[TMP1]], i32 28) #[[ATTR0]] +; CHECK-NEXT: [[A3:%.*]] = srem i128 [[A2]], [[P2]] +; CHECK-NEXT: store i128 [[A3]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 24, ptr [[TMP2]], ptr [[TMP1]], ptr [[TMP0]], i32 -28) #[[ATTR0]] +; CHECK-NEXT: store i128 [[A3]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[A1]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 16, ptr [[TMP2]], ptr [[TMP0]], i32 29) #[[ATTR0]] +; CHECK-NEXT: [[A4:%.*]] = sub i128 [[A3]], [[A1]] +; CHECK-NEXT: store i128 [[A4]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 16, ptr [[TMP2]], ptr [[TMP0]], ptr [[TMP1]], i32 -29) #[[ATTR0]] +; CHECK-NEXT: store i128 [[A4]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[A2]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 30, ptr [[TMP2]], ptr [[TMP1]], i32 30) #[[ATTR0]] +; CHECK-NEXT: [[A5:%.*]] = or i128 [[A4]], [[A2]] +; CHECK-NEXT: store i128 [[A5]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 30, ptr [[TMP2]], ptr [[TMP1]], ptr [[TMP0]], i32 -30) #[[ATTR0]] +; CHECK-NEXT: store i128 [[A5]], ptr [[TMP2]], align 4 +; CHECK-NEXT: store i128 [[A3]], ptr [[TMP0]], align 4 +; CHECK-NEXT: call void @__instrumentor_pre_numeric_ind(i64 12, i32 16, i32 26, ptr [[TMP2]], ptr [[TMP0]], i32 31) #[[ATTR0]] +; CHECK-NEXT: [[A6:%.*]] = shl i128 [[A5]], [[A3]] +; CHECK-NEXT: store i128 [[A6]], ptr [[TMP1]], align 4 +; CHECK-NEXT: call void @__instrumentor_post_numeric_ind(i64 12, i32 16, i32 26, ptr [[TMP2]], ptr [[TMP0]], ptr [[TMP1]], i32 -31) #[[ATTR0]] +; CHECK-NEXT: ret i128 [[A6]] +; +entry: + %a1 = add i128 %p1, %p2 + %a2 = mul i128 %p1, %a1 + %a3 = srem i128 %a2, %p2 + %a4 = sub i128 %a3, %a1 + %a5 = or i128 %a4, %a2 + %a6 = shl i128 %a5, %a3 + ret i128 %a6 +}