|
| 1 | +# Custom-LLVM for Interprocedural Dependencies Checking on Hardware Register. |
| 2 | + |
| 3 | +한국어 : https://github.com/rollrat/custom-llvm2/blob/master/README.md |
| 4 | + |
| 5 | +This custom-llvm has been forked to determine the variable dependencies (Dominated, Maybe) |
| 6 | +of the specific register specified by llvm.annotation in the IR step. This project can help |
| 7 | +you to output variable dependencies of the IR level from an object file(Not yet). See Commits |
| 8 | +for more details on the code changes. Also refer to the develop and test branches for testing |
| 9 | +and etcs. |
| 10 | + |
| 11 | +*** |
| 12 | + |
| 13 | +## 1. Representation in the IR stage |
| 14 | +Please read the following article while referring to b.cpp and b.ll. [Test Folder](https://github.com/rollrat/custom-llvm2/tree/master/test/Dependency%20Test) |
| 15 | + |
| 16 | +### 1.1. Variable marking using llvm.annotation |
| 17 | +`__attribute__((annotate("message")))` is an annotation feature provided by clang / llvm. This function allows you to know the annotated variables until the final stage of IR. You can also see the contents of `" message "` in an annotated variable. |
| 18 | +``` c++ |
| 19 | + int __attribute__((annotate("a"))) a = 0; |
| 20 | +``` |
| 21 | +``` llvm |
| 22 | +@.str.2 = private unnamed_addr constant [2 x i8] c"a\00", section "llvm.metadata" |
| 23 | +
|
| 24 | + %a = alloca i32, align 4 |
| 25 | + %1 = bitcast i32* %a to i8* |
| 26 | + call void @llvm.lifetime.start.p0i8(i64 4, i8* nonnull %1) #2 |
| 27 | + call void @llvm.var.annotation(i8* nonnull %1, i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str.1, i32 0, i32 0), i32 10) |
| 28 | +``` |
| 29 | +The variable `a` has been annotated via the above C ++ syntax. The following IR representation shows that the function `@ llvm.var.annotation` calls `%1` and that `%1` bitcasts`%a`. `%a` points to the annotated variable a. With the llvm annotation function, `StoreInst` tells which values are assigned to`%a`. |
| 30 | +``` llvm |
| 31 | + %add4 = add nsw i32 %4, %call |
| 32 | + store i32 %add4, i32* %a, align 4, !tbaa !3 |
| 33 | +``` |
| 34 | +The above statement shows that the value of `%add4` is stored in `%a`. This function works on all annotated variables and does not disappear in the optimization phase. |
| 35 | + |
| 36 | +### 1.2. Variable marking via extern function |
| 37 | +When variable marking using `llvm.annotation`, I found that marking disappears in some situations during maximum optimization on testing. |
| 38 | +We could not find another way to mark the variable itself, but we could find the virtual register used in the process of changing the variable by calling the bodyless function. |
| 39 | +``` c++ |
| 40 | +#define ANNORATE(msg) __attribute__((annotate(msg))) |
| 41 | +extern void __my__annotate(void *); |
| 42 | + |
| 43 | +void SHA256_Mixing(SHA_PULONG indexs, SHA_PULONG outdexs) |
| 44 | +{ |
| 45 | + SHA_ULONG w[64]; |
| 46 | + SHA_ULONG i, a, b, c, d, e, f, g, h, ANNORATE("t1") t1, ANNORATE("t2") t2; |
| 47 | + |
| 48 | + for (i = 0; i < 16; i++) |
| 49 | + w[i] = CONVERT_TO_LITTLE_ENDIAN(indexs[i]); |
| 50 | + |
| 51 | + for (i = 16; i < 64; i++) |
| 52 | + w[i] = SHA_256_s0(w[i - 15]) + w[i - 16] + w[i - 7] + SHA_256_s1(w[i - 2]); |
| 53 | + |
| 54 | + for (i = 0; i < 64; i++) { |
| 55 | + |
| 56 | + __my__annotate(t1); |
| 57 | + SHA_256_LOOP(a, b, c, d, e, f, g, h, i, t1, t2); |
| 58 | + SHA_256_XROLL(a, b, c, d, e, f, g, h, t1, t2); |
| 59 | + } |
| 60 | +``` |
| 61 | +The above t1 is marked, but no annotation is left in -O2 optimization. With the extern function, you can get the following results from the .ll file: |
| 62 | +``` llvm |
| 63 | + ; Before |
| 64 | +for.body73: ; preds = %for.body73, %for.end62 |
| 65 | + %add112215 = phi i32 [ %26, %for.end62 ], [ %add112, %for.body73 ] |
| 66 | + %i.2214 = phi i32 [ 0, %for.end62 ], [ %inc114, %for.body73 ] |
| 67 | + %h.0213 = phi i32 [ %35, %for.end62 ], [ %g.0212, %for.body73 ] |
| 68 | + %g.0212 = phi i32 [ %34, %for.end62 ], [ %f.0211, %for.body73 ] |
| 69 | + %f.0211 = phi i32 [ %33, %for.end62 ], [ %e.0210, %for.body73 ] |
| 70 | + %e.0210 = phi i32 [ %32, %for.end62 ], [ %add111, %for.body73 ] |
| 71 | + %d.0209 = phi i32 [ %31, %for.end62 ], [ %c.0208, %for.body73 ] |
| 72 | + %c.0208 = phi i32 [ %30, %for.end62 ], [ %b.0207, %for.body73 ] |
| 73 | + %b.0207 = phi i32 [ %29, %for.end62 ], [ %add112215, %for.body73 ] |
| 74 | + %shr74 = lshr i32 %e.0210, 6 |
| 75 | + %shl75 = shl i32 %e.0210, 26 |
| 76 | + %or76 = or i32 %shr74, %shl75 |
| 77 | + %shr77 = lshr i32 %e.0210, 11 |
| 78 | + %shl78 = shl i32 %e.0210, 21 |
| 79 | + ... |
| 80 | +
|
| 81 | + ; After |
| 82 | +for.body73: ; preds = %for.body73, %for.end62 |
| 83 | + %t1.0216 = phi i32 [ undef, %for.end62 ], [ %add93, %for.body73 ] |
| 84 | + %h.0215 = phi i32 [ %31, %for.end62 ], [ %g.0214, %for.body73 ] |
| 85 | + %g.0214 = phi i32 [ %30, %for.end62 ], [ %f.0213, %for.body73 ] |
| 86 | + %f.0213 = phi i32 [ %29, %for.end62 ], [ %e.0212, %for.body73 ] |
| 87 | + %e.0212 = phi i32 [ %28, %for.end62 ], [ %add111, %for.body73 ] |
| 88 | + %d.0211 = phi i32 [ %27, %for.end62 ], [ %c.0210, %for.body73 ] |
| 89 | + %c.0210 = phi i32 [ %26, %for.end62 ], [ %b.0209, %for.body73 ] |
| 90 | + %b.0209 = phi i32 [ %25, %for.end62 ], [ %35, %for.body73 ] |
| 91 | + %i.2208 = phi i32 [ 0, %for.end62 ], [ %inc114, %for.body73 ] |
| 92 | + %32 = inttoptr i32 %t1.0216 to i8* |
| 93 | + ; extern function called |
| 94 | + call void @__my__annotate(i8* %32) #2 |
| 95 | + %shr74 = lshr i32 %e.0212, 6 |
| 96 | + %shl75 = shl i32 %e.0212, 26 |
| 97 | + %or76 = or i32 %shr74, %shl75 |
| 98 | + %shr77 = lshr i32 %e.0212, 11 |
| 99 | + %shl78 = shl i32 %e.0212, 21 |
| 100 | +``` |
| 101 | +Like this, when marking with extern function, the kind of marking of argument of function is marked as `Annotated` which will be described below. |
| 102 | +The extern function used is removed from llc processing via `eraseFromParent`. |
| 103 | + |
| 104 | +*** |
| 105 | + |
| 106 | + |
| 107 | +## 2. Dependency Pass |
| 108 | +This is the pass to mark the dependency of the variable in the Instruction. It is executed once for each function just before the SDNode generation, not the optimization step. |
| 109 | +This [link](https://github.com/rollrat/custom-llvm2/commit/583681378edf38a3d837135f9815c621c3021590#diff-825e43e63961002d7541aec6d4d4f7a4R468) |
| 110 | +Indicates the above procedure. You can know that `c-> runOnFunction` immediately precedes the creation of the SDNode by` SelectAllBasicBlocks`. |
| 111 | + |
| 112 | +The source of the following links is a full source code of Dependency Pass. |
| 113 | +``` |
| 114 | +https://github.com/rollrat/custom-llvm2/blob/master/include/llvm/DependencyInfo.h |
| 115 | +https://github.com/rollrat/custom-llvm2/blob/master/lib/Transforms/Scalar/Dependency.cpp |
| 116 | +``` |
| 117 | + |
| 118 | +The following link is the git link that developed the pass before creating the custom-llvm repository. |
| 119 | +``` |
| 120 | +https://github.com/rollrat/llvm-control-pass |
| 121 | +``` |
| 122 | + |
| 123 | +### 2.1. Instruction Marking Type |
| 124 | +The following 4 items are marking type on Dependency Pass. |
| 125 | +``` |
| 126 | +Annotated : Instruction to be substituted by StoreInst. |
| 127 | +Perpect : A fully connected Instruction. |
| 128 | +Dominated : Includes Perpect, and includes instructions to change the branch associated with the parent BasicBlock. |
| 129 | +Maybe : Dominated, and includes all instructions that change the branch of this BB with respect to all connected BasicBlocks. |
| 130 | +``` |
| 131 | +`Annotated` >> `Perpect` >> `Dominated` >> `Maybe` Priority is determined in that order. |
| 132 | +For example, `Instruction` with `Annotated` marking includes `Maybe` marking. |
| 133 | + |
| 134 | +### 2.2. Branch Map |
| 135 | +Branch Map is Control-Flow-Graph of Function BasicBlock. This is used to distinguish between Dominated and Maybe. |
| 136 | +Look up the Branch Map, use `Dominated` if one parent BasicBlock is one, or use `Maybe` if more than one. |
| 137 | + |
| 138 | + |
| 139 | +### 2.3. Function dependency |
| 140 | +An `Annotated` variable can be changed inside a called function if it is a pointer to a function's arguments. |
| 141 | +Also, if the return value of a function is `Dominated` by a variable that has been `Annotated`, the arguments of that function can affect the return value. |
| 142 | +To exploring these two things, we use the following classes to examine the call function. |
| 143 | +``` |
| 144 | +FunctionReturnDependencyChecker: Checks which function arguments affect the return value. |
| 145 | +FunctionArgumentDependencyCheck: Checks which function arguments affect other function arguments. |
| 146 | +``` |
| 147 | +If you need to check for function dependencies, use `run` function in` DependencyChecker` to check only once per function. |
| 148 | +This checking process is independent of whether or not `Annotate` is present. |
| 149 | + |
| 150 | +### 2.4. Marking decision |
| 151 | +The followings are the classes and functions used for `Instruction` marking. |
| 152 | +``` c++ |
| 153 | + class FunctionReturnDependencyChecker; |
| 154 | + class FunctionArgumentDependencyCheck |
| 155 | + class BottomUpDependencyChecker; |
| 156 | +``` |
| 157 | +Only `BottomUpDependencyChecker` in the above class has `Instruction` marking privilege. |
| 158 | +``` |
| 159 | +runPerpectBottomUp: Used on Perpect marking. (This function is called once per `Annotated` variable.) |
| 160 | +runBottomUp: Used on Dominated, Maybe marking. |
| 161 | +runSearch: Checks for changes in value by Store and function dependency. Used for `Annotated` marking with limited conditions. |
| 162 | + (This function conditionally calls runBottomUp.) |
| 163 | +processBranches: Use the Branch Map to conditionally call runSearch, runBottomUp. |
| 164 | +``` |
| 165 | + |
| 166 | +
|
| 167 | +#### 2.4.1. runBottomUp Function |
| 168 | +`Instruction` through `runBottomUp` examines `Value` related to `Instruction` obtained through `getOperand`. |
| 169 | +`Dominated`, `Maybe` is marked, but marking distinction is not done in this function. Marking distinction through `processBranches` |
| 170 | +Is done. |
| 171 | +``` vb.net |
| 172 | +runBottomUp [Instruction: I, bool: P] |
| 173 | + if (P == true) |
| 174 | + I := Dominated |
| 175 | + else |
| 176 | + I := Maybe |
| 177 | +
|
| 178 | + for each Operand in I.getOperand |
| 179 | + runBottomUp(Operand, P) |
| 180 | + runSearch(Operand, P) |
| 181 | +
|
| 182 | + processBranches(I) |
| 183 | +``` |
| 184 | +This iteration is repeated until the operand is not `Instruction`. |
| 185 | +If `Instruction` is` CallInst`, only function arguments with `ReturnDependency` are checked. |
| 186 | + |
| 187 | +#### 2.4.2. runSearch Function |
| 188 | +`runSearch` checks for `Instruction` which is used as argument to `StoreInst` or` CallInst`. |
| 189 | +The `ROOT : bool` variable for `Annotated` marking is used, and this variable is only `true` in the call to marking `entry`. |
| 190 | +``` vb.net |
| 191 | +runSearch [Instruction: I, bool: P, bool: ROOT (= false)] |
| 192 | + for each Instruction in Function.BasicBlock |
| 193 | + if (type(Instruction) :: StoreInst) |
| 194 | + if (StoreInst.Pointer == I) |
| 195 | + if (ROOT == true) |
| 196 | + I := Annotated |
| 197 | + runPerpectBottomUp (StoreInst.Value) |
| 198 | + runBottomUp(StoreInst.Value, P && ROOT) |
| 199 | + runSearch(StoreInst.Value, P && ROOT) |
| 200 | + |
| 201 | + else if (type(Instruction) :: CallInst) |
| 202 | + for each Oprand in FunctionArgumentDependency(CallInst.CalledFunction, Instruction.getOperand) |
| 203 | + runBottomUp(Operand, P && ROOT) |
| 204 | + runSearch(Operand, P && ROOT) |
| 205 | + |
| 206 | + processBranches(I) |
| 207 | +``` |
| 208 | +`P && ROOT` is exists, because we can not determine `Dominated`, `Maybe` at runSearch level. |
| 209 | +However, if `ROOT` is `true`, `P` is also` true` and subordinate `Instruction` is marked as `Dominated`. |
| 210 | + |
| 211 | +#### 2.4.3. processBranches Function |
| 212 | +Using Branch Map, we tracks the Compare element that determines the branch. |
| 213 | +If the branch is not conditional, the compare element trace is skipped. |
| 214 | +``` vb.net |
| 215 | +processBranches [Instruction: I] |
| 216 | + processBlock(getNodeFromInstruction(I)) |
| 217 | + |
| 218 | +processBlock [BlockNode: BN] |
| 219 | + if (BN.getFromNodes.Size == 1) |
| 220 | + is_perpect := true |
| 221 | + else |
| 222 | + is_perepct := false |
| 223 | + |
| 224 | + for each BlockNode in BN.getFromNodes |
| 225 | + if (BlockNode is Conditional) |
| 226 | + runBottomUp(BlockNode.getCondition, is_perpect) |
| 227 | + runSearch(BlockNode.getCondition, is_perpect) |
| 228 | + |
| 229 | + processBlock(BlockNode) |
| 230 | +``` |
| 231 | +The `BlockNode` once executed with `processBlock` will not be executed again. |
| 232 | + |
| 233 | +#### 2.4.4. runPerpectBottomUp Function |
| 234 | +This function recursively traverses each Operand in `Instruction` to mark the `Perpect`. |
| 235 | +``` vb.net |
| 236 | +runPerpectBottomUp [Instruction: I] |
| 237 | + I := Perpect |
| 238 | + |
| 239 | + for each Operand in I.getOperand |
| 240 | + runPerpectBottomUp(Operand) |
| 241 | +``` |
| 242 | + |
| 243 | +*** |
| 244 | + |
| 245 | +## 3. SelectionDAG Traking |
| 246 | +When the SelectionDAG is created, the `Instruction` Dependency information is passed to the DAGNode. |
| 247 | +The following procedure shows the code that the PassManager calls as it creates the SelectionDAG. |
| 248 | +``` |
| 249 | +Reference: https://github.com/draperlaboratory/fracture/wiki/How-An-IR-Statement-Becomes-An-Instruction |
| 250 | +
|
| 251 | +FunctionPass |
| 252 | + -> MachineFunctionPass |
| 253 | + -> SelelctionDAGISel |
| 254 | + -> TargetDAGToDAGISel |
| 255 | +
|
| 256 | +include/llvm/Pass.h |
| 257 | +-> virtual bool runOnFunction(Function &F) = 0; |
| 258 | +
|
| 259 | +lib/CodeGen/MachineFunctionPass.cpp |
| 260 | +-> runOnMachineFunction(MF) |
| 261 | +
|
| 262 | +lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp |
| 263 | +-> bool SelectionDAGISel::runOnMachineFunction(MachineFunction &mf) |
| 264 | +The runOnMachineFunction function runs Dependency Checking before the SelectAllBasicBlocks function is executed. |
| 265 | +
|
| 266 | +lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp |
| 267 | +-> void SelectionDAGISel::SelectAllBasicBlocks(const Function &Fn) |
| 268 | +The SelectAllBasicBlocks function calls `FastISel` and` SelectBasicBlock`. |
| 269 | +`FastISel` is an InstructionSelection for debugging that runs only on -O0, |
| 270 | +`SelectBasicBlocks` generates a SelectionDAGNode by executing `DoInstructionSelection`. |
| 271 | +
|
| 272 | +lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp |
| 273 | +-> void SelectionDAGISel::CodeGenAndEmitDAG() { |
| 274 | +In the CodeGenAndEmitDAG function, DAGCombine, DAGLegalize is executed. |
| 275 | +Instruction Schedule is also executed. |
| 276 | +``` |
| 277 | + |
| 278 | +*** |
| 279 | + |
| 280 | +## 4. Bugs |
| 281 | +The current version may not run the Dependency Pass for the following functions / functions, or an error may occur. |
| 282 | +``` |
| 283 | +* Can not determine the ArgumentDependency of the function with the variable argument. |
| 284 | +``` |
0 commit comments