GCC Code Coverage Report


src/
Coverage:
low: ≥ 0%
medium: ≥ 75.0%
high: ≥ 90.0%
Lines:
741 / 779, 22 excl
95.1%
Branches:
584 / 629, 34 excl
92.8%
Functions:
83 / 84
98.8%

irgenerator/op-rule-conversion-manager.spice
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 // Std imports
4 import "std/data/vector";
5 import "std/bindings/llvm/llvm" as llvm;
6
7 // Own imports
8 import "@/ast/ast-nodes";
9 import "@/irgenerator/abi-info";
10 import "@/irgenerator/ir-generator";
11 import "@/irgenerator/llvm-expr-result";
12 import "@/irgenerator/std-function-manager";
13 import "@/model/function" as model; // Aliased, because Function clashes with llvm::Function
14 import "@/symboltablebuilder/qual-type";
15 import "@/symboltablebuilder/super-type";
16 import "@/symboltablebuilder/symbol-table-entry";
17
18 public const unsigned long DEFAULT_OP_IDX = 0l;
19
20 // ========================================================== Resolver ===========================================================
21
22 /**
23 * Kind of a resolver, see Resolver
24 */
25 public type ResolverKind enum {
26 NONE, // Resolves to nil
27 VALUE, // Resolves to the value of an expression result
28 ADDRESS, // Resolves to the address of an expression result
29 EXPR_VALUE, // Resolves to the value of an expression node
30 EXPR_ADDRESS, // Resolves to the address of an expression node
31 FIXED // Resolves to a fixed value
32 }
33
34 /**
35 * Lazily resolves an operand of an operator to its value or address. Spice lambdas cannot capture the IR generator and the
36 * expression results by reference safely, so the few kinds of resolvers are modeled explicitly here and resolved via
37 * IRGenerator.resolve().
38 */
39 230038 public type Resolver struct {
40 public ResolverKind kind
41 public QualType qualType
42 230038 public LLVMExprResult* exprResult = nil<LLVMExprResult*>
43 230038 public IVisitable* expr = nil<IVisitable*>
44 public llvm::Value fixedValue
45 }
46
47 230038 public p Resolver.ctor() {
48 230038 this.kind = ResolverKind::NONE;
49 230038 this.qualType = QualType(SuperType::TY_INVALID);
50 230038 this.exprResult = nil<LLVMExprResult*>;
51 230038 this.expr = nil<IVisitable*>;
52 230038 this.fixedValue = llvm::Value();
53 230038 }
54
55 678 public f<Resolver> noneResolver() {
56 678 Resolver resolver;
57 678 resolver.kind = ResolverKind::NONE;
58 678 return resolver;
59 }
60
61 113417 public f<Resolver> valueResolver(const QualType& qualType, LLVMExprResult* exprResult) {
62 113417 Resolver resolver;
63 113417 resolver.kind = ResolverKind::VALUE;
64 113417 resolver.qualType = qualType;
65 113417 resolver.exprResult = exprResult;
66 113417 return resolver;
67 }
68
69 113417 public f<Resolver> addressResolver(LLVMExprResult* exprResult) {
70 113417 Resolver resolver;
71 113417 resolver.kind = ResolverKind::ADDRESS;
72 113417 resolver.exprResult = exprResult;
73 113417 return resolver;
74 }
75
76 924 public f<Resolver> exprValueResolver(IVisitable* expr) {
77 924 Resolver resolver;
78 924 resolver.kind = ResolverKind::EXPR_VALUE;
79 924 resolver.expr = expr;
80 924 return resolver;
81 }
82
83 924 public f<Resolver> exprAddressResolver(IVisitable* expr) {
84 924 Resolver resolver;
85 924 resolver.kind = ResolverKind::EXPR_ADDRESS;
86 924 resolver.expr = expr;
87 924 return resolver;
88 }
89
90 678 public f<Resolver> fixedResolver(llvm::Value value) {
91 678 Resolver resolver;
92 678 resolver.kind = ResolverKind::FIXED;
93 678 resolver.fixedValue = value;
94 678 return resolver;
95 }
96
97 /**
98 * The resolvers of the operands of a binary or unary operator: lhsV, lhsP, rhsV, rhsP (value and address of the lhs and rhs)
99 */
100 61966 public type OperandResolvers struct {
101 public Vector<Resolver> resolvers
102 }
103
104 8913 public p OperandResolvers.ctor(const Resolver& lhsV, const Resolver& lhsP) {
105 8913 this.resolvers.pushBack(lhsV);
106 8913 this.resolvers.pushBack(lhsP);
107 8913 }
108
109 53053 public p OperandResolvers.ctor(const Resolver& lhsV, const Resolver& lhsP, const Resolver& rhsV, const Resolver& rhsP) {
110 53053 this.resolvers.pushBack(lhsV);
111 53053 this.resolvers.pushBack(lhsP);
112 53053 this.resolvers.pushBack(rhsV);
113 53053 this.resolvers.pushBack(rhsP);
114 53053 }
115
116 // =================================================== OpRuleConversionManager ===================================================
117
118 /**
119 * Helper class for the IRGenerator to resolve operator instructions for each valid operator/type combination
120 *
121 * Note: If an instruction takes two operands, the rhs is resolved before the lhs. Changing the order changes the generated IR.
122 */
123 public type OpRuleConversionManager struct {
124 llvm::IRBuilder* builder
125 IRGenerator* irGenerator
126 StdFunctionManager* stdFunctionManager
127 }
128
129 3499 public p OpRuleConversionManager.ctor(IRGenerator* irGenerator) {
130 3499 this.builder = irGenerator.builder;
131 3499 this.irGenerator = irGenerator;
132 3499 this.stdFunctionManager = &irGenerator.stdFunctionManager;
133 3499 }
134
135 /**
136 * Check if an operation on two integer operands has to be performed signed or unsigned. Like in C, both operands are
137 * converted to the wider of both types, so its signedness decides. For operands of the same width, the operation is
138 * unsigned if one of them is unsigned.
139 *
140 * @param lhsSTy Type of the left operand
141 * @param rhsSTy Type of the right operand
142 * @return Signed operation or not
143 */
144 17169 f<bool> isSignedOperation(const QualType& lhsSTy, const QualType& rhsSTy) {
145 17169 const unsigned int lhsWidth = getIntegerWidth(lhsSTy);
146 17169 const unsigned int rhsWidth = getIntegerWidth(rhsSTy);
147
2/2
✓ Branch 0 taken 362 times.
✓ Branch 1 taken 16807 times.
17169 if lhsWidth != rhsWidth {
148
2/2
✓ Branch 0 taken 199 times.
✓ Branch 1 taken 163 times.
362 return lhsWidth > rhsWidth ? lhsSTy.isSigned() : rhsSTy.isSigned();
149 }
150
2/2
✓ Branch 0 taken 14463 times.
✓ Branch 1 taken 2344 times.
16807 return lhsSTy.isSigned() && rhsSTy.isSigned();
151 }
152
153 // Bit width of an integer type, used to determine the common type of two integer operands
154 34338 f<unsigned int> getIntegerWidth(const QualType& integerType) {
155
4/4
✓ Branch 0 taken 4720 times.
✓ Branch 1 taken 1142 times.
✓ Branch 2 taken 28293 times.
✓ Branch 3 taken 183 times.
34338 switch integerType.getSuperType() {
156 28293 case SuperType::TY_LONG: { return 64u; }
157 4720 case SuperType::TY_INT: { return 32u; }
158 183 case SuperType::TY_SHORT: { return 16u; }
159 1142 default: { return 8u; }
160 }
161 ✗ }
162
163 // Whether an integer operation on the given types has no signed wrap (only evaluated for integer types)
164 17426 f<bool> isNSW(const QualType& lhsSTy, const QualType& rhsSTy) {
165
2/2
✓ Branch 0 taken 15558 times.
✓ Branch 1 taken 1868 times.
17426 return lhsSTy.isSigned() && rhsSTy.isSigned();
166 }
167
168 // Check if the given super types match the expected combination
169 883847 f<bool> isComb(SuperType lhs, SuperType rhs, SuperType expectedLhs, SuperType expectedRhs) {
170
2/2
✓ Branch 0 taken 741725 times.
✓ Branch 1 taken 142122 times.
883847 return lhs == expectedLhs && rhs == expectedRhs;
171 }
172
173 79110 f<llvm::Value> OpRuleConversionManager.lhsV(LLVMExprResult& lhs, const QualType& lhsSTy) {
174 79110 return this.irGenerator.resolveValue(lhsSTy, lhs);
175 }
176
177 73896 f<llvm::Value> OpRuleConversionManager.rhsV(LLVMExprResult& rhs, const QualType& rhsSTy) {
178 73896 return this.irGenerator.resolveValue(rhsSTy, rhs);
179 }
180
181 // Resolvers for the operator overload function call of a binary operator
182 51451 f<OperandResolvers> getBinaryResolvers(LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
183 51451 const Resolver lhsV = valueResolver(lhsSTy, &lhs);
184 51451 const Resolver lhsP = addressResolver(&lhs);
185 51451 const Resolver rhsV = valueResolver(rhsSTy, &rhs);
186 51451 const Resolver rhsP = addressResolver(&rhs);
187 51451 return OperandResolvers(lhsV, lhsP, rhsV, rhsP);
188 }
189
190 // Resolvers for the operator overload function call of a unary operator
191 8913 f<OperandResolvers> getUnaryResolvers(LLVMExprResult& lhs, const QualType& lhsSTy) {
192 8913 const Resolver lhsV = valueResolver(lhsSTy, &lhs);
193 8913 const Resolver lhsP = addressResolver(&lhs);
194 8913 return OperandResolvers(lhsV, lhsP);
195 }
196
197 // ----------------------------------------------------- Instruction helpers -----------------------------------------------------
198
199 // Like builder.CreateAdd(lhs, rhs, "", false, hasNSW)
200 16630 f<llvm::Value> OpRuleConversionManager.createAdd(llvm::Value lhs, llvm::Value rhs, bool hasNSW) {
201
2/2
✓ Branch 0 taken 1965 times.
✓ Branch 1 taken 14665 times.
16630 return hasNSW ? this.builder.createNSWAdd(lhs, rhs) : this.builder.createAdd(lhs, rhs);
202 }
203
204 // Like builder.CreateSub(lhs, rhs, "", false, hasNSW)
205 7252 f<llvm::Value> OpRuleConversionManager.createSub(llvm::Value lhs, llvm::Value rhs, bool hasNSW) {
206
2/2
✓ Branch 0 taken 395 times.
✓ Branch 1 taken 6857 times.
7252 return hasNSW ? this.builder.createNSWSub(lhs, rhs) : this.builder.createSub(lhs, rhs);
207 }
208
209 // Like builder.CreateMul(lhs, rhs, "", false, hasNSW)
210 2425 f<llvm::Value> OpRuleConversionManager.createMul(llvm::Value lhs, llvm::Value rhs, bool hasNSW) {
211
2/2
✓ Branch 0 taken 305 times.
✓ Branch 1 taken 2120 times.
2425 return hasNSW ? this.builder.createNSWMul(lhs, rhs) : this.builder.createMul(lhs, rhs);
212 }
213
214 41781 f<llvm::Value> OpRuleConversionManager.createICmp(llvm::LLVMIntPredicate predicate, llvm::Value lhs, llvm::Value rhs) {
215 41781 return this.builder.createICmp(predicate, lhs, rhs);
216 }
217
218 399 f<llvm::Value> OpRuleConversionManager.createFCmp(llvm::LLVMRealPredicate predicate, llvm::Value lhs, llvm::Value rhs) {
219 399 return this.builder.createFCmp(predicate, lhs, rhs);
220 }
221
222 // ------------------------------------------------------ Compound assign ops ----------------------------------------------------
223
224 1917 public f<LLVMExprResult> OpRuleConversionManager.getPlusEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
225 1917 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
226 1917 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
227 1917 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
228 1917 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
229
230 // Handle operator overloads
231
2/2
✓ Branch 0 taken 762 times.
✓ Branch 1 taken 1155 times.
1917 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
232 1524 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
233 }
234
235 1155 const SuperType l = lhsSTy.getSuperType();
236 1155 const SuperType r = rhsSTy.getSuperType();
237
2/2
✓ Branch 0 taken 59 times.
✓ Branch 1 taken 1096 times.
1155 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
238 59 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
239 59 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
240 118 return exprResultWithValue(this.builder.createFAdd(lhsV, rhsV));
241 }
242
6/6
✓ Branch 0 taken 957 times.
✓ Branch 1 taken 139 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 956 times.
✓ Branch 4 taken 1057 times.
✓ Branch 5 taken 39 times.
1096 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) {
243 1057 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
244 1057 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
245 2114 return exprResultWithValue(this.createAdd(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)));
246 }
247
14/14
✓ Branch 0 taken 34 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 11 times.
✓ Branch 4 taken 22 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 21 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 9 times.
✓ Branch 10 taken 1 time.
✓ Branch 11 taken 11 times.
✓ Branch 12 taken 31 times.
✓ Branch 13 taken 8 times.
39 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_INT) {
248 31 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
249 31 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
250 62 return exprResultWithValue(this.createAdd(lhsV, rhsCasted, isNSW(lhsSTy, rhsSTy)));
251 }
252
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 6 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 8 times.
✗ Branch 5 not taken.
8 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_INT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_LONG) {
253 8 const QualType elementSTy = lhsSTy.getContained();
254 8 const llvm::Type elementTy = elementSTy.toLLVMType(this.irGenerator.sourceFile);
255 8 const llvm::Value rhsVExt = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), this.builder.getInt64Ty(), rhsSTy.isSigned());
256 8 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
257 16 return exprResultWithValue(this.builder.createGEP(elementTy, lhsV, rhsVExt));
258 }
259 − panic(Error("Operator fallthrough: +=")); // LCOV_EXCL_LINE
260 1917 }
261
262 92 public f<LLVMExprResult> OpRuleConversionManager.getMinusEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
263 92 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
264 92 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
265 92 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
266 92 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
267
268 // Handle operator overloads
269
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 82 times.
92 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
270 20 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
271 }
272
273 82 const SuperType l = lhsSTy.getSuperType();
274 82 const SuperType r = rhsSTy.getSuperType();
275
2/2
✓ Branch 0 taken 6 times.
✓ Branch 1 taken 76 times.
82 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
276 6 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
277 6 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
278 12 return exprResultWithValue(this.builder.createFSub(lhsV, rhsV));
279 }
280
6/6
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 19 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 54 times.
✓ Branch 4 taken 38 times.
✓ Branch 5 taken 38 times.
76 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) {
281 38 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
282 38 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
283 76 return exprResultWithValue(this.createSub(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)));
284 }
285
14/14
✓ Branch 0 taken 35 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 32 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 31 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 30 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 12 times.
✓ Branch 9 taken 18 times.
✓ Branch 10 taken 2 times.
✓ Branch 11 taken 10 times.
✓ Branch 12 taken 31 times.
✓ Branch 13 taken 7 times.
38 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_INT) {
286 31 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
287 31 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
288 62 return exprResultWithValue(this.createSub(lhsV, rhsCasted, isNSW(lhsSTy, rhsSTy)));
289 }
290
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 7 times.
✗ Branch 5 not taken.
7 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_INT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_LONG) {
291 7 const QualType elementSTy = lhsSTy.getContained();
292 7 const llvm::Type elementTy = elementSTy.toLLVMType(this.irGenerator.sourceFile);
293 7 const llvm::Value rhsVExt = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), this.builder.getInt64Ty(), rhsSTy.isSigned());
294 7 const llvm::Value rhsVNeg = this.builder.createNeg(rhsVExt);
295 7 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
296 14 return exprResultWithValue(this.builder.createGEP(elementTy, lhsV, rhsVNeg));
297 }
298 − panic(Error("Operator fallthrough: -=")); // LCOV_EXCL_LINE
299 92 }
300
301 159 public f<LLVMExprResult> OpRuleConversionManager.getMulEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
302 159 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
303 159 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
304 159 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
305 159 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
306
307 // Handle operator overloads
308
2/2
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 156 times.
159 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
309 6 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
310 }
311
312 156 const SuperType l = lhsSTy.getSuperType();
313 156 const SuperType r = rhsSTy.getSuperType();
314
2/2
✓ Branch 0 taken 38 times.
✓ Branch 1 taken 118 times.
156 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
315 38 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
316 38 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
317 76 return exprResultWithValue(this.builder.createFMul(lhsV, rhsV));
318 }
319
6/6
✓ Branch 0 taken 115 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 114 times.
✓ Branch 4 taken 108 times.
✓ Branch 5 taken 10 times.
118 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) {
320 108 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
321 108 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
322 216 return exprResultWithValue(this.createMul(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)));
323 }
324
11/12
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 3 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 10 times.
✗ Branch 11 not taken.
10 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
325 10 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
326 10 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
327 20 return exprResultWithValue(this.createMul(lhsV, rhsCasted, isNSW(lhsSTy, rhsSTy)));
328 }
329 − panic(Error("Operator fallthrough: *=")); // LCOV_EXCL_LINE
330 159 }
331
332 106 public f<LLVMExprResult> OpRuleConversionManager.getDivEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
333 106 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
334 106 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
335 106 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
336 106 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
337
338 // Handle operator overloads
339
2/2
✓ Branch 0 taken 70 times.
✓ Branch 1 taken 36 times.
106 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
340 140 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
341 }
342
343 36 const SuperType l = lhsSTy.getSuperType();
344 36 const SuperType r = rhsSTy.getSuperType();
345
2/2
✓ Branch 0 taken 8 times.
✓ Branch 1 taken 28 times.
36 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
346 8 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
347 8 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
348 16 return exprResultWithValue(this.builder.createFDiv(lhsV, rhsV));
349 }
350
4/4
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 24 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 13 times.
28 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) {
351 15 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
352 15 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
353 30 return exprResultWithValue(this.generateDiv(lhsSTy, rhsSTy, lhsV, rhsV));
354 }
355
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 12 times.
13 if isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) {
356 1 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
357 1 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
358 2 return exprResultWithValue(this.generateDiv(lhsSTy, rhsSTy, lhsV, rhsV));
359 }
360
11/12
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 1 time.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 time.
✓ Branch 8 taken 1 time.
✓ Branch 9 taken 1 time.
✓ Branch 10 taken 12 times.
✗ Branch 11 not taken.
12 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
361 12 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
362 12 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
363 24 return exprResultWithValue(this.generateDiv(lhsSTy, lhsSTy, lhsV, rhsCasted));
364 }
365 − panic(Error("Operator fallthrough: /=")); // LCOV_EXCL_LINE
366 106 }
367
368 61 public f<LLVMExprResult> OpRuleConversionManager.getRemEqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
369 61 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
370 61 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
371 61 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
372
373 61 const SuperType l = lhsSTy.getSuperType();
374 61 const SuperType r = rhsSTy.getSuperType();
375
2/2
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 60 times.
61 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
376 // LLVM generates a call to fmod on Linux systems
377
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 time.
1 if this.irGenerator.cliOptions.targetTriple.isOSLinux() {
378 1 this.irGenerator.resourceManager.linker.requestLibMathLinkage();
379 1 }
380 1 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
381 1 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
382 1 return exprResultWithValue(this.builder.createFRem(lhsV, rhsV));
383 }
384
4/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 57 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 56 times.
60 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) {
385 4 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
386 4 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
387 4 return exprResultWithValue(this.generateRem(lhsSTy, rhsSTy, lhsV, rhsV));
388 }
389
4/4
✓ Branch 0 taken 1 time.
✓ Branch 1 taken 55 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 52 times.
56 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) {
390 4 const llvm::Value rhsInt = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
391 4 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
392 4 return exprResultWithValue(this.generateRem(lhsSTy, lhsSTy, lhsV, rhsInt));
393 }
394
8/8
✓ Branch 0 taken 51 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 50 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 49 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 48 times.
52 if isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
395 4 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
396 4 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
397 4 return exprResultWithValue(this.generateRem(lhsSTy, lhsSTy, lhsV, rhsCasted));
398 }
399
3/4
✓ Branch 0 taken 47 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 48 times.
✗ Branch 3 not taken.
48 if isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) {
400 48 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
401 48 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
402 48 return exprResultWithValue(this.generateRem(lhsSTy, rhsSTy, lhsV, rhsV));
403 }
404 − panic(Error("Operator fallthrough: %=")); // LCOV_EXCL_LINE
405 }
406
407 // Kinds of bitwise/shift compound assign ops, which share the same type combinations
408 type BitCompoundOp enum {
409 SHL,
410 SHR,
411 AND,
412 OR,
413 XOR
414 }
415
416 1585 f<llvm::Value> OpRuleConversionManager.createBitCompoundOp(BitCompoundOp op, const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
417
5/6
✓ Branch 0 taken 133 times.
✓ Branch 1 taken 336 times.
✓ Branch 2 taken 331 times.
✓ Branch 3 taken 457 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 328 times.
1585 switch op {
418 133 case BitCompoundOp::SHL: { return this.builder.createShl(lhsV, rhsV); }
419 336 case BitCompoundOp::SHR: { return this.generateSHR(lhsSTy, rhsSTy, lhsV, rhsV); }
420 331 case BitCompoundOp::AND: { return this.builder.createAnd(lhsV, rhsV); }
421 457 case BitCompoundOp::OR: { return this.builder.createOr(lhsV, rhsV); }
422 328 case BitCompoundOp::XOR: { return this.builder.createXor(lhsV, rhsV); }
423 }
424 ✗ }
425
426 // Shared implementation of getSHLEqualInst, getSHREqualInst, getAndEqualInst, getOrEqualInst and getXorEqualInst
427 342 f<LLVMExprResult> OpRuleConversionManager.getBitCompoundInst(BitCompoundOp op, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy, string opName) {
428 342 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
429 342 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
430 342 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
431
432 342 const SuperType l = lhsSTy.getSuperType();
433 342 const SuperType r = rhsSTy.getSuperType();
434
4/4
✓ Branch 0 taken 337 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 341 times.
342 if isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) && op == BitCompoundOp::SHR {
435 1 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
436 1 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
437 1 return exprResultWithValue(this.builder.createLShr(lhsV, rhsV));
438 }
439
12/12
✓ Branch 0 taken 308 times.
✓ Branch 1 taken 33 times.
✓ Branch 2 taken 304 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 44 times.
✓ Branch 5 taken 260 times.
✓ Branch 6 taken 11 times.
✓ Branch 7 taken 33 times.
✓ Branch 8 taken 27 times.
✓ Branch 9 taken 6 times.
✓ Branch 10 taken 308 times.
✓ Branch 11 taken 33 times.
341 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) || (op == BitCompoundOp::XOR && isComb(l, r, SuperType::TY_CHAR, SuperType::TY_CHAR)) {
440 308 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
441 308 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
442 308 return exprResultWithValue(this.createBitCompoundOp(op, lhsSTy, rhsSTy, lhsV, rhsV));
443 }
444
11/12
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 5 times.
✓ Branch 2 taken 23 times.
✓ Branch 3 taken 5 times.
✓ Branch 4 taken 18 times.
✓ Branch 5 taken 5 times.
✓ Branch 6 taken 13 times.
✓ Branch 7 taken 5 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 5 times.
✓ Branch 10 taken 33 times.
✗ Branch 11 not taken.
33 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
445 33 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
446 33 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
447 33 return exprResultWithValue(this.createBitCompoundOp(op, lhsSTy, rhsSTy, lhsV, rhsCasted));
448 }
449 − raiseOperatorFallthrough(opName); // LCOV_EXCL_LINE
450 − return LLVMExprResult(); // LCOV_EXCL_LINE
451 }
452
453 12 public f<LLVMExprResult> OpRuleConversionManager.getSHLEqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
454 12 return this.getBitCompoundInst(BitCompoundOp::SHL, lhs, lhsSTy, rhs, rhsSTy, "<<=");
455 }
456
457 19 public f<LLVMExprResult> OpRuleConversionManager.getSHREqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
458 19 return this.getBitCompoundInst(BitCompoundOp::SHR, lhs, lhsSTy, rhs, rhsSTy, ">>=");
459 }
460
461 30 public f<LLVMExprResult> OpRuleConversionManager.getAndEqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
462 30 return this.getBitCompoundInst(BitCompoundOp::AND, lhs, lhsSTy, rhs, rhsSTy, "&=");
463 }
464
465 32 public f<LLVMExprResult> OpRuleConversionManager.getOrEqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
466 32 return this.getBitCompoundInst(BitCompoundOp::OR, lhs, lhsSTy, rhs, rhsSTy, "|=");
467 }
468
469 249 public f<LLVMExprResult> OpRuleConversionManager.getXorEqualInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
470 249 return this.getBitCompoundInst(BitCompoundOp::XOR, lhs, lhsSTy, rhs, rhsSTy, "^=");
471 }
472
473 // ---------------------------------------------------------- Bitwise ops --------------------------------------------------------
474
475 // Shared implementation of getBitwiseOrInst, getBitwiseXorInst and getBitwiseAndInst
476 816 f<LLVMExprResult> OpRuleConversionManager.getBitwiseInst(BitCompoundOp op, ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy, unsigned long opIdx, string opName) {
477 816 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
478 816 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
479 816 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
480
481 // Handle operator overloads
482
2/2
✓ Branch 0 taken 11 times.
✓ Branch 1 taken 805 times.
816 if this.callsOverloadedOpFct(node, opIdx) {
483 22 return this.callOperatorOverloadFct(node, resolvers, 2l, opIdx);
484 }
485
486 805 const SuperType l = lhsSTy.getSuperType();
487 805 const SuperType r = rhsSTy.getSuperType();
488
9/10
✓ Branch 0 taken 672 times.
✓ Branch 1 taken 133 times.
✓ Branch 2 taken 653 times.
✓ Branch 3 taken 19 times.
✓ Branch 4 taken 414 times.
✓ Branch 5 taken 239 times.
✓ Branch 6 taken 3 times.
✓ Branch 7 taken 411 times.
✓ Branch 8 taken 805 times.
✗ Branch 9 not taken.
805 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) || isComb(l, r, SuperType::TY_BOOL, SuperType::TY_BOOL) {
489 805 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
490 805 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
491 1610 return exprResultWithValue(this.createBitCompoundOp(op, lhsSTy, rhsSTy, lhsV, rhsV));
492 }
493 − raiseOperatorFallthrough(opName); // LCOV_EXCL_LINE
494 − return LLVMExprResult(); // LCOV_EXCL_LINE
495 816 }
496
497 429 public f<LLVMExprResult> OpRuleConversionManager.getBitwiseOrInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
498 429 return this.getBitwiseInst(BitCompoundOp::OR, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "|");
499 }
500
501 82 public f<LLVMExprResult> OpRuleConversionManager.getBitwiseXorInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
502 82 return this.getBitwiseInst(BitCompoundOp::XOR, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "^");
503 }
504
505 305 public f<LLVMExprResult> OpRuleConversionManager.getBitwiseAndInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
506 305 return this.getBitwiseInst(BitCompoundOp::AND, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "&");
507 }
508
509 // --------------------------------------------------------- Equality ops --------------------------------------------------------
510
511 // Shared implementation of getEqualInst and getNotEqualInst
512 27520 f<LLVMExprResult> OpRuleConversionManager.getEqualityInst(bool isEqual, ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
513 27520 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
514 27520 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
515 27520 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
516 27520 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
517 27520 const llvm::Type rhsT = rhsSTy.toLLVMType(this.irGenerator.sourceFile);
518
2/2
✓ Branch 0 taken 22765 times.
✓ Branch 1 taken 4755 times.
27520 const llvm::LLVMIntPredicate iPred = isEqual ? llvm::LLVMIntPredicate::EQ : llvm::LLVMIntPredicate::NE;
519
2/2
✓ Branch 0 taken 22765 times.
✓ Branch 1 taken 4755 times.
27520 const llvm::LLVMRealPredicate fPred = isEqual ? llvm::LLVMRealPredicate::OEQ : llvm::LLVMRealPredicate::ONE;
520
521 // Handle operator overloads
522
2/2
✓ Branch 0 taken 1706 times.
✓ Branch 1 taken 25814 times.
27520 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
523 3412 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
524 }
525
526 // Check if lhs is of type pointer and rhs is of type long
527
4/4
✓ Branch 0 taken 19590 times.
✓ Branch 1 taken 6224 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25812 times.
25814 if lhsT.isPointerTy() && rhsT.isIntegerTy(64) {
528 2 const llvm::Value lhsInt = this.builder.createPtrToInt(this.lhsV(lhs, lhsSTy), rhsT);
529 2 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
530 4 return exprResultWithValue(this.createICmp(iPred, lhsInt, rhsV));
531 }
532
533 // Check if one value is a string and the other one is a char*
534
7/8
✓ Branch 0 taken 25285 times.
✓ Branch 1 taken 527 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25812 times.
✓ Branch 4 taken 22831 times.
✓ Branch 5 taken 2981 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 25810 times.
25812 if (lhsSTy.is(SuperType::TY_STRING) && rhsSTy.isPtrTo(SuperType::TY_CHAR)) || (lhsSTy.isPtrTo(SuperType::TY_CHAR) && rhsSTy.is(SuperType::TY_STRING)) {
535 4 return this.generateStringEquality(isEqual, lhs, lhsSTy, rhs, rhsSTy);
536 }
537
538 // Check for primitive type combinations
539 25810 const SuperType l = lhsSTy.getSuperType();
540 25810 const SuperType r = rhsSTy.getSuperType();
541
2/2
✓ Branch 0 taken 190 times.
✓ Branch 1 taken 25620 times.
25810 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
542 190 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
543 190 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
544 380 return exprResultWithValue(this.createFCmp(fPred, lhsV, rhsV));
545 }
546
6/6
✓ Branch 0 taken 25618 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25616 times.
✓ Branch 4 taken 6 times.
✓ Branch 5 taken 25614 times.
25620 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_LONG) {
547 6 const llvm::Value rhsFP = this.generateIToFp(rhsSTy, this.rhsV(rhs, rhsSTy), lhsT);
548 6 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
549 12 return exprResultWithValue(this.createFCmp(fPred, lhsV, rhsFP));
550 }
551
6/6
✓ Branch 0 taken 25606 times.
✓ Branch 1 taken 8 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 25604 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 25602 times.
25614 if isComb(l, r, SuperType::TY_INT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_DOUBLE) {
552 12 const llvm::Value lhsFP = this.generateIToFp(lhsSTy, this.lhsV(lhs, lhsSTy), rhsT);
553 12 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
554 24 return exprResultWithValue(this.createFCmp(fPred, lhsFP, rhsV));
555 }
556
12/12
✓ Branch 0 taken 21751 times.
✓ Branch 1 taken 3851 times.
✓ Branch 2 taken 21667 times.
✓ Branch 3 taken 84 times.
✓ Branch 4 taken 12255 times.
✓ Branch 5 taken 9412 times.
✓ Branch 6 taken 12131 times.
✓ Branch 7 taken 124 times.
✓ Branch 8 taken 7141 times.
✓ Branch 9 taken 4990 times.
✓ Branch 10 taken 206 times.
✓ Branch 11 taken 6935 times.
25602 const bool sameIntType = isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_CHAR) || isComb(l, r, SuperType::TY_BOOL, SuperType::TY_BOOL) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_PTR);
557
2/2
✓ Branch 0 taken 24360 times.
✓ Branch 1 taken 1242 times.
25602 if sameIntType {
558 24360 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
559 24360 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
560 48720 return exprResultWithValue(this.createICmp(iPred, lhsV, rhsV));
561 }
562 // Cast the rhs to the lhs type
563
12/12
✓ Branch 0 taken 1240 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 1238 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 1236 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 628 times.
✓ Branch 7 taken 608 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 626 times.
✓ Branch 10 taken 618 times.
✓ Branch 11 taken 624 times.
1242 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_CHAR) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_CHAR) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_CHAR) {
564 618 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
565 618 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
566 1236 return exprResultWithValue(this.createICmp(iPred, lhsV, rhsCasted));
567 }
568 // Cast the lhs to the rhs type
569
12/12
✓ Branch 0 taken 621 times.
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 603 times.
✓ Branch 3 taken 18 times.
✓ Branch 4 taken 601 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 599 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 597 times.
✓ Branch 10 taken 29 times.
✓ Branch 11 taken 595 times.
624 if isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_INT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_LONG) {
570 29 const llvm::Value lhsCasted = this.builder.createIntCast(this.lhsV(lhs, lhsSTy), rhsT, lhsSTy.isSigned());
571 29 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
572 58 return exprResultWithValue(this.createICmp(iPred, lhsCasted, rhsV));
573 }
574
2/2
✓ Branch 0 taken 527 times.
✓ Branch 1 taken 68 times.
595 if isComb(l, r, SuperType::TY_STRING, SuperType::TY_STRING) {
575 1054 return this.generateStringEquality(isEqual, lhs, lhsSTy, rhs, rhsSTy);
576 }
577
3/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 66 times.
✓ Branch 2 taken 68 times.
✗ Branch 3 not taken.
68 if isComb(l, r, SuperType::TY_FUNCTION, SuperType::TY_FUNCTION) || isComb(l, r, SuperType::TY_PROCEDURE, SuperType::TY_PROCEDURE) {
578 68 const unsigned long typeSize = this.irGenerator.module.getTypeSizeInBits(lhsT) / 8l;
579 68 const llvm::Function memcmpFct = this.stdFunctionManager.getMemcmpFct();
580 68 Vector<llvm::Value> args;
581 68 args.pushBack(this.irGenerator.resolveAddress(lhs));
582 68 args.pushBack(this.irGenerator.resolveAddress(rhs));
583 68 args.pushBack(this.builder.getInt64(typeSize));
584 68 const llvm::Value memcmpResult = this.builder.createCall(memcmpFct, args);
585 136 return exprResultWithValue(this.createICmp(iPred, memcmpResult, this.builder.getInt32(0)));
586 68 }
587 − panic(Error(isEqual ? "Operator fallthrough: ==" : "Operator fallthrough: !=")); // LCOV_EXCL_LINE
588 27520 }
589
590 // Generate call to the function isRawEqual(string, string) of the string std (negated for !=)
591 529 f<LLVMExprResult> OpRuleConversionManager.generateStringEquality(bool isEqual, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
592 529 const llvm::Function opFct = this.stdFunctionManager.getStringIsRawEqualStringStringFct();
593 529 Vector<llvm::Value> args;
594 529 args.pushBack(this.lhsV(lhs, lhsSTy));
595 529 args.pushBack(this.rhsV(rhs, rhsSTy));
596 529 const llvm::Value res = this.builder.createCall(opFct, args);
597
2/2
✓ Branch 0 taken 418 times.
✓ Branch 1 taken 111 times.
529 if isEqual {
598 836 return exprResultWithValue(res);
599 }
600 // Negate the result
601 222 return exprResultWithValue(this.builder.createNot(res));
602 529 }
603
604 22765 public f<LLVMExprResult> OpRuleConversionManager.getEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
605 22765 return this.getEqualityInst(true, node, lhs, lhsSTy, rhs, rhsSTy);
606 }
607
608 4755 public f<LLVMExprResult> OpRuleConversionManager.getNotEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
609 4755 return this.getEqualityInst(false, node, lhs, lhsSTy, rhs, rhsSTy);
610 }
611
612 // -------------------------------------------------------- Relational ops -------------------------------------------------------
613
614 // Kinds of relational ops
615 type RelationalOpKind enum {
616 LESS,
617 GREATER,
618 LESS_EQUAL,
619 GREATER_EQUAL
620 }
621
622 191 f<llvm::Value> OpRuleConversionManager.createRelationalFCmp(RelationalOpKind op, llvm::Value lhsV, llvm::Value rhsV) {
623
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 60 times.
✓ Branch 2 taken 33 times.
✓ Branch 3 taken 27 times.
✓ Branch 4 taken 71 times.
191 switch op {
624 60 case RelationalOpKind::LESS: { return this.createFCmp(llvm::LLVMRealPredicate::OLT, lhsV, rhsV); }
625 33 case RelationalOpKind::GREATER: { return this.createFCmp(llvm::LLVMRealPredicate::OGT, lhsV, rhsV); }
626 27 case RelationalOpKind::LESS_EQUAL: { return this.createFCmp(llvm::LLVMRealPredicate::OLE, lhsV, rhsV); }
627 71 case RelationalOpKind::GREATER_EQUAL: { return this.createFCmp(llvm::LLVMRealPredicate::OGE, lhsV, rhsV); }
628 }
629 ✗ }
630
631 16688 f<llvm::Value> OpRuleConversionManager.createRelationalICmp(RelationalOpKind op, const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
632
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 6879 times.
✓ Branch 2 taken 3596 times.
✓ Branch 3 taken 2145 times.
✓ Branch 4 taken 4068 times.
16688 switch op {
633 6879 case RelationalOpKind::LESS: { return this.generateLT(lhsSTy, rhsSTy, lhsV, rhsV); }
634 3596 case RelationalOpKind::GREATER: { return this.generateGT(lhsSTy, rhsSTy, lhsV, rhsV); }
635 2145 case RelationalOpKind::LESS_EQUAL: { return this.generateLE(lhsSTy, rhsSTy, lhsV, rhsV); }
636 4068 case RelationalOpKind::GREATER_EQUAL: { return this.generateGE(lhsSTy, rhsSTy, lhsV, rhsV); }
637 }
638 ✗ }
639
640 16 f<llvm::Value> OpRuleConversionManager.createRelationalPtrCmp(RelationalOpKind op, llvm::Value lhsV, llvm::Value rhsV) {
641
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 4 times.
16 switch op {
642 4 case RelationalOpKind::LESS: { return this.createICmp(llvm::LLVMIntPredicate::ULT, lhsV, rhsV); }
643 4 case RelationalOpKind::GREATER: { return this.createICmp(llvm::LLVMIntPredicate::UGT, lhsV, rhsV); }
644 4 case RelationalOpKind::LESS_EQUAL: { return this.createICmp(llvm::LLVMIntPredicate::ULE, lhsV, rhsV); }
645 4 case RelationalOpKind::GREATER_EQUAL: { return this.createICmp(llvm::LLVMIntPredicate::UGE, lhsV, rhsV); }
646 }
647 ✗ }
648
649 // Shared implementation of getLessInst, getGreaterInst, getLessEqualInst and getGreaterEqualInst
650 16919 f<LLVMExprResult> OpRuleConversionManager.getRelationalInst(RelationalOpKind op, ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy, string opName) {
651 // Handle operator overloads
652
2/2
✓ Branch 0 taken 24 times.
✓ Branch 1 taken 16895 times.
16919 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
653 24 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
654 48 return this.callOperatorOverloadFct(node, resolvers, 2l, DEFAULT_OP_IDX);
655 24 }
656
657 16895 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
658 16895 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
659 16895 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
660 16895 const llvm::Type rhsT = rhsSTy.toLLVMType(this.irGenerator.sourceFile);
661
662 16895 const SuperType l = lhsSTy.getSuperType();
663 16895 const SuperType r = rhsSTy.getSuperType();
664
2/2
✓ Branch 0 taken 129 times.
✓ Branch 1 taken 16766 times.
16895 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
665 129 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
666 129 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
667 129 return exprResultWithValue(this.createRelationalFCmp(op, lhsV, rhsV));
668 }
669
6/6
✓ Branch 0 taken 16724 times.
✓ Branch 1 taken 42 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 16720 times.
✓ Branch 4 taken 50 times.
✓ Branch 5 taken 16716 times.
16766 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_LONG) {
670 50 const llvm::Value rhsFP = this.generateIToFp(rhsSTy, this.rhsV(rhs, rhsSTy), lhsT);
671 50 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
672 50 return exprResultWithValue(this.createRelationalFCmp(op, lhsV, rhsFP));
673 }
674
6/6
✓ Branch 0 taken 16712 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 16708 times.
✓ Branch 4 taken 12 times.
✓ Branch 5 taken 16704 times.
16716 if isComb(l, r, SuperType::TY_INT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_DOUBLE) {
675 12 const llvm::Value lhsFP = this.generateIToFp(lhsSTy, this.lhsV(lhs, lhsSTy), rhsT);
676 12 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
677 12 return exprResultWithValue(this.createRelationalFCmp(op, lhsFP, rhsV));
678 }
679
10/10
✓ Branch 0 taken 14600 times.
✓ Branch 1 taken 2104 times.
✓ Branch 2 taken 14558 times.
✓ Branch 3 taken 42 times.
✓ Branch 4 taken 924 times.
✓ Branch 5 taken 13634 times.
✓ Branch 6 taken 4 times.
✓ Branch 7 taken 920 times.
✓ Branch 8 taken 16349 times.
✓ Branch 9 taken 355 times.
16704 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_CHAR) {
680 16349 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
681 16349 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
682 16349 return exprResultWithValue(this.createRelationalICmp(op, lhsSTy, rhsSTy, lhsV, rhsV));
683 }
684 // Cast the rhs to the lhs type
685
6/6
✓ Branch 0 taken 351 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 176 times.
✓ Branch 3 taken 175 times.
✓ Branch 4 taken 184 times.
✓ Branch 5 taken 171 times.
355 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
686 184 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
687 184 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
688 184 return exprResultWithValue(this.createRelationalICmp(op, lhsSTy, rhsSTy, lhsV, rhsCasted));
689 }
690 // Cast the lhs to the rhs type
691
6/6
✓ Branch 0 taken 81 times.
✓ Branch 1 taken 90 times.
✓ Branch 2 taken 61 times.
✓ Branch 3 taken 20 times.
✓ Branch 4 taken 155 times.
✓ Branch 5 taken 16 times.
171 if isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) {
692 155 const llvm::Value lhsCasted = this.builder.createIntCast(this.lhsV(lhs, lhsSTy), rhsT, lhsSTy.isSigned());
693 155 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
694 155 return exprResultWithValue(this.createRelationalICmp(op, lhsSTy, rhsSTy, lhsCasted, rhsV));
695 }
696
1/2
✓ Branch 0 taken 16 times.
✗ Branch 1 not taken.
16 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_PTR) {
697 16 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
698 16 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
699 16 return exprResultWithValue(this.createRelationalPtrCmp(op, lhsV, rhsV));
700 }
701 − raiseOperatorFallthrough(opName); // LCOV_EXCL_LINE
702 − return LLVMExprResult(); // LCOV_EXCL_LINE
703 }
704
705 6953 public f<LLVMExprResult> OpRuleConversionManager.getLessInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
706 6953 return this.getRelationalInst(RelationalOpKind::LESS, node, lhs, lhsSTy, rhs, rhsSTy, "<");
707 }
708
709 3636 public f<LLVMExprResult> OpRuleConversionManager.getGreaterInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
710 3636 return this.getRelationalInst(RelationalOpKind::GREATER, node, lhs, lhsSTy, rhs, rhsSTy, ">");
711 }
712
713 2181 public f<LLVMExprResult> OpRuleConversionManager.getLessEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
714 2181 return this.getRelationalInst(RelationalOpKind::LESS_EQUAL, node, lhs, lhsSTy, rhs, rhsSTy, "<=");
715 }
716
717 4149 public f<LLVMExprResult> OpRuleConversionManager.getGreaterEqualInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy) {
718 4149 return this.getRelationalInst(RelationalOpKind::GREATER_EQUAL, node, lhs, lhsSTy, rhs, rhsSTy, ">=");
719 }
720
721 // ---------------------------------------------------------- Shift ops ----------------------------------------------------------
722
723 // Shared implementation of getShiftLeftInst and getShiftRightInst
724 986 f<LLVMExprResult> OpRuleConversionManager.getShiftInst(bool isLeft, ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy, unsigned long opIdx) {
725 986 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
726 986 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
727 986 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
728 986 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
729
2/2
✓ Branch 0 taken 666 times.
✓ Branch 1 taken 320 times.
986 const BitCompoundOp op = isLeft ? BitCompoundOp::SHL : BitCompoundOp::SHR;
730
731 // Handle operator overloads
732
2/2
✓ Branch 0 taken 547 times.
✓ Branch 1 taken 439 times.
986 if this.callsOverloadedOpFct(node, opIdx) {
733 1094 return this.callOperatorOverloadFct(node, resolvers, 2l, opIdx);
734 }
735
736 439 const SuperType l = lhsSTy.getSuperType();
737 439 const SuperType r = rhsSTy.getSuperType();
738
8/8
✓ Branch 0 taken 326 times.
✓ Branch 1 taken 113 times.
✓ Branch 2 taken 324 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 253 times.
✓ Branch 5 taken 71 times.
✓ Branch 6 taken 370 times.
✓ Branch 7 taken 69 times.
439 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE) {
739 370 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
740 370 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
741 740 return exprResultWithValue(this.createBitCompoundOp(op, lhsSTy, rhsSTy, lhsV, rhsV));
742 }
743
17/18
✓ Branch 0 taken 67 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 65 times.
✓ Branch 3 taken 2 times.
✓ Branch 4 taken 63 times.
✓ Branch 5 taken 2 times.
✓ Branch 6 taken 61 times.
✓ Branch 7 taken 2 times.
✓ Branch 8 taken 8 times.
✓ Branch 9 taken 53 times.
✓ Branch 10 taken 6 times.
✓ Branch 11 taken 2 times.
✓ Branch 12 taken 4 times.
✓ Branch 13 taken 2 times.
✓ Branch 14 taken 2 times.
✓ Branch 15 taken 2 times.
✓ Branch 16 taken 69 times.
✗ Branch 17 not taken.
69 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_LONG) {
744 69 const llvm::Value rhsInt = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
745 69 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
746 138 return exprResultWithValue(this.createBitCompoundOp(op, lhsSTy, rhsSTy, lhsV, rhsInt));
747 }
748 − panic(Error(isLeft ? "Operator fallthrough: <<" : "Operator fallthrough: >>")); // LCOV_EXCL_LINE
749 986 }
750
751 666 public f<LLVMExprResult> OpRuleConversionManager.getShiftLeftInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
752 666 return this.getShiftInst(true, node, lhs, lhsSTy, rhs, rhsSTy, opIdx);
753 }
754
755 320 public f<LLVMExprResult> OpRuleConversionManager.getShiftRightInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
756 320 return this.getShiftInst(false, node, lhs, lhsSTy, rhs, rhsSTy, opIdx);
757 }
758
759 // -------------------------------------------------------- Arithmetic ops -------------------------------------------------------
760
761 // Kinds of arithmetic ops, that share the same type combinations
762 type ArithmeticOpKind enum {
763 PLUS,
764 MINUS,
765 MUL,
766 DIV
767 }
768
769 558 f<llvm::Value> OpRuleConversionManager.createFloatArithmetic(ArithmeticOpKind op, llvm::Value lhsV, llvm::Value rhsV) {
770
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 293 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 91 times.
✓ Branch 4 taken 128 times.
558 switch op {
771 293 case ArithmeticOpKind::PLUS: { return this.builder.createFAdd(lhsV, rhsV); }
772 46 case ArithmeticOpKind::MINUS: { return this.builder.createFSub(lhsV, rhsV); }
773 91 case ArithmeticOpKind::MUL: { return this.builder.createFMul(lhsV, rhsV); }
774 128 case ArithmeticOpKind::DIV: { return this.builder.createFDiv(lhsV, rhsV); }
775 }
776 ✗ }
777
778 16337 f<llvm::Value> OpRuleConversionManager.createIntArithmetic(ArithmeticOpKind op, llvm::Value lhsV, llvm::Value rhsV, const QualType& lhsSTy, const QualType& rhsSTy) {
779
4/5
✗ Branch 0 not taken.
✓ Branch 1 taken 7423 times.
✓ Branch 2 taken 6421 times.
✓ Branch 3 taken 2307 times.
✓ Branch 4 taken 186 times.
16337 switch op {
780 7423 case ArithmeticOpKind::PLUS: { return this.createAdd(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)); }
781 6421 case ArithmeticOpKind::MINUS: { return this.createSub(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)); }
782 2307 case ArithmeticOpKind::MUL: { return this.createMul(lhsV, rhsV, isNSW(lhsSTy, rhsSTy)); }
783 186 case ArithmeticOpKind::DIV: { return this.generateDiv(lhsSTy, rhsSTy, lhsV, rhsV); }
784 }
785 ✗ }
786
787 // Shared implementation of getPlusInst, getMinusInst, getMulInst and getDivInst
788 19831 f<LLVMExprResult> OpRuleConversionManager.getArithmeticInst(ArithmeticOpKind op, ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy, unsigned long opIdx, string opName) {
789 19831 const OperandResolvers resolvers = getBinaryResolvers(lhs, origLhsSTy, rhs, origRhsSTy);
790 19831 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
791 19831 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
792 19831 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
793 19831 const llvm::Type rhsT = rhsSTy.toLLVMType(this.irGenerator.sourceFile);
794
795 // Handle operator overloads
796
2/2
✓ Branch 0 taken 148 times.
✓ Branch 1 taken 19683 times.
19831 if this.callsOverloadedOpFct(node, opIdx) {
797 296 return this.callOperatorOverloadFct(node, resolvers, 2l, opIdx);
798 }
799
800 19683 const SuperType l = lhsSTy.getSuperType();
801 19683 const SuperType r = rhsSTy.getSuperType();
802
2/2
✓ Branch 0 taken 10253 times.
✓ Branch 1 taken 9430 times.
19683 const bool isPlusOrMinus = op == ArithmeticOpKind::PLUS || op == ArithmeticOpKind::MINUS;
803
2/2
✓ Branch 0 taken 286 times.
✓ Branch 1 taken 19397 times.
19683 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
804 286 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
805 286 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
806 572 return exprResultWithValue(this.createFloatArithmetic(op, lhsV, rhsV));
807 }
808
6/6
✓ Branch 0 taken 19246 times.
✓ Branch 1 taken 151 times.
✓ Branch 2 taken 46 times.
✓ Branch 3 taken 19200 times.
✓ Branch 4 taken 243 times.
✓ Branch 5 taken 19154 times.
19397 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_LONG) {
809 243 const llvm::Value rhsFP = this.generateIToFp(rhsSTy, this.rhsV(rhs, rhsSTy), lhsT);
810 243 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
811 486 return exprResultWithValue(this.createFloatArithmetic(op, lhsV, rhsFP));
812 }
813
6/6
✓ Branch 0 taken 19145 times.
✓ Branch 1 taken 9 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 19141 times.
✓ Branch 4 taken 29 times.
✓ Branch 5 taken 19125 times.
19154 if isComb(l, r, SuperType::TY_INT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_DOUBLE) {
814 29 const llvm::Value lhsFP = this.generateIToFp(lhsSTy, this.lhsV(lhs, lhsSTy), rhsT);
815 29 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
816 58 return exprResultWithValue(this.createFloatArithmetic(op, lhsFP, rhsV));
817 }
818
6/6
✓ Branch 0 taken 18502 times.
✓ Branch 1 taken 623 times.
✓ Branch 2 taken 18488 times.
✓ Branch 3 taken 14 times.
✓ Branch 4 taken 13924 times.
✓ Branch 5 taken 4564 times.
19125 const bool sameType = isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BYTE);
819
1/2
✓ Branch 0 taken 19125 times.
✗ Branch 1 not taken.
19125 const bool charOp = isComb(l, r, SuperType::TY_CHAR, SuperType::TY_CHAR) && op != ArithmeticOpKind::MUL;
820
4/4
✓ Branch 0 taken 14565 times.
✓ Branch 1 taken 4560 times.
✓ Branch 2 taken 14565 times.
✓ Branch 3 taken 4560 times.
19125 if sameType || charOp {
821 14565 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
822 14565 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
823 29130 return exprResultWithValue(this.createIntArithmetic(op, lhsV, rhsV, lhsSTy, rhsSTy));
824 }
825 // Cast the rhs to the lhs type
826
6/6
✓ Branch 0 taken 4556 times.
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 1476 times.
✓ Branch 3 taken 3080 times.
✓ Branch 4 taken 1488 times.
✓ Branch 5 taken 3072 times.
4560 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
827 1488 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
828 1488 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
829 2976 return exprResultWithValue(this.createIntArithmetic(op, lhsV, rhsCasted, lhsSTy, rhsSTy));
830 }
831 // Cast the lhs to the rhs type
832
6/6
✓ Branch 0 taken 2802 times.
✓ Branch 1 taken 270 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2796 times.
✓ Branch 4 taken 284 times.
✓ Branch 5 taken 2788 times.
3072 if isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) {
833 284 const llvm::Value lhsCasted = this.builder.createIntCast(this.lhsV(lhs, lhsSTy), rhsT, lhsSTy.isSigned());
834 284 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
835 568 return exprResultWithValue(this.createIntArithmetic(op, lhsCasted, rhsV, lhsSTy, rhsSTy));
836 }
837 // Pointer arithmetic with the integer on the lhs
838
4/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2788 times.
✓ Branch 2 taken 2788 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 2788 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 2788 times.
2788 if isPlusOrMinus && (isComb(l, r, SuperType::TY_INT, SuperType::TY_PTR) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_PTR) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_PTR)) {
839 ✗ const llvm::Value lhsExt = this.builder.createIntCast(this.lhsV(lhs, lhsSTy), this.builder.getInt64Ty(), lhsSTy.isSigned());
840 ✗ const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
841 ✗ const QualType elementSTy = rhsSTy.getContained();
842 ✗ const llvm::Type elementTy = elementSTy.toLLVMType(this.irGenerator.sourceFile);
843 ✗ return exprResultWithValue(this.builder.createGEP(elementTy, rhsV, lhsExt));
844 }
845 // Pointer arithmetic with the integer on the rhs
846
6/8
✗ Branch 0 not taken.
✓ Branch 1 taken 2788 times.
✓ Branch 2 taken 2765 times.
✓ Branch 3 taken 23 times.
✓ Branch 4 taken 2 times.
✓ Branch 5 taken 2763 times.
✓ Branch 6 taken 2788 times.
✗ Branch 7 not taken.
2788 if isPlusOrMinus && (isComb(l, r, SuperType::TY_PTR, SuperType::TY_INT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_LONG)) {
847 2788 llvm::Value rhsOperand = this.rhsV(rhs, rhsSTy);
848
2/2
✓ Branch 0 taken 2537 times.
✓ Branch 1 taken 251 times.
2788 if op == ArithmeticOpKind::MINUS {
849 251 rhsOperand = this.builder.createNeg(rhsOperand);
850 251 }
851 2788 const llvm::Value rhsExt = this.builder.createIntCast(rhsOperand, this.builder.getInt64Ty(), rhsSTy.isSigned());
852 2788 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
853 2788 const QualType elementSTy = lhsSTy.getContained();
854 2788 const llvm::Type elementTy = elementSTy.toLLVMType(this.irGenerator.sourceFile);
855 5576 return exprResultWithValue(this.builder.createGEP(elementTy, lhsV, rhsExt));
856 }
857 − raiseOperatorFallthrough(opName); // LCOV_EXCL_LINE
858 − return LLVMExprResult(); // LCOV_EXCL_LINE
859 19831 }
860
861 10363 public f<LLVMExprResult> OpRuleConversionManager.getPlusInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
862 10363 return this.getArithmeticInst(ArithmeticOpKind::PLUS, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "+");
863 }
864
865 6720 public f<LLVMExprResult> OpRuleConversionManager.getMinusInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
866 6720 return this.getArithmeticInst(ArithmeticOpKind::MINUS, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "-");
867 }
868
869 2409 public f<LLVMExprResult> OpRuleConversionManager.getMulInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
870 2409 return this.getArithmeticInst(ArithmeticOpKind::MUL, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "*");
871 }
872
873 339 public f<LLVMExprResult> OpRuleConversionManager.getDivInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy, LLVMExprResult& rhs, const QualType& rhsSTy, unsigned long opIdx) {
874 339 return this.getArithmeticInst(ArithmeticOpKind::DIV, node, lhs, lhsSTy, rhs, rhsSTy, opIdx, "/");
875 }
876
877 209 public f<LLVMExprResult> OpRuleConversionManager.getRemInst(ASTNode* _, LLVMExprResult& lhs, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
878 209 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
879 209 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
880 209 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
881 209 const llvm::Type rhsT = rhsSTy.toLLVMType(this.irGenerator.sourceFile);
882
883 209 const SuperType l = lhsSTy.getSuperType();
884 209 const SuperType r = rhsSTy.getSuperType();
885
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 207 times.
209 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_DOUBLE) {
886 // LLVM generates a call to fmod on Linux systems
887
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 if this.irGenerator.cliOptions.targetTriple.isOSLinux() {
888 2 this.irGenerator.resourceManager.linker.requestLibMathLinkage();
889 2 }
890 2 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
891 2 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
892 2 return exprResultWithValue(this.builder.createFRem(lhsV, rhsV));
893 }
894
6/6
✓ Branch 0 taken 154 times.
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 153 times.
✓ Branch 4 taken 201 times.
✓ Branch 5 taken 6 times.
207 if isComb(l, r, SuperType::TY_INT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_LONG) {
895 201 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
896 201 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
897 201 return exprResultWithValue(this.generateRem(lhsSTy, rhsSTy, lhsV, rhsV));
898 }
899 // Cast the rhs to the lhs type
900
6/6
✓ Branch 0 taken 5 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 4 times.
✓ Branch 4 taken 3 times.
✓ Branch 5 taken 3 times.
6 if isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) {
901 3 const llvm::Value rhsCasted = this.builder.createIntCast(this.rhsV(rhs, rhsSTy), lhsT, rhsSTy.isSigned());
902 3 const llvm::Value lhsV = this.lhsV(lhs, lhsSTy);
903 3 return exprResultWithValue(this.generateRem(lhsSTy, rhsSTy, lhsV, rhsCasted));
904 }
905 // Cast the lhs to the rhs type
906
5/6
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 time.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 if isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) {
907 3 const llvm::Value lhsCasted = this.builder.createIntCast(this.lhsV(lhs, lhsSTy), rhsT, lhsSTy.isSigned());
908 3 const llvm::Value rhsV = this.rhsV(rhs, rhsSTy);
909 3 return exprResultWithValue(this.generateRem(lhsSTy, rhsSTy, lhsCasted, rhsV));
910 }
911 − panic(Error("Operator fallthrough: %")); // LCOV_EXCL_LINE
912 }
913
914 // ---------------------------------------------------------- Unary ops ----------------------------------------------------------
915
916 948 public f<LLVMExprResult> OpRuleConversionManager.getPrefixMinusInst(ASTNode* _, LLVMExprResult& lhs, const QualType& origLhsSTy) {
917 948 const QualType originalLhsSTy = origLhsSTy;
918 948 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
919
920
2/3
✗ Branch 0 not taken.
✓ Branch 1 taken 715 times.
✓ Branch 2 taken 233 times.
948 switch lhsSTy.getSuperType() {
921 case SuperType::TY_DOUBLE: {
922 233 return exprResultWithValue(this.builder.createFNeg(this.lhsV(lhs, originalLhsSTy)));
923 }
924 case SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG: {
925 715 return exprResultWithValue(this.builder.createNeg(this.lhsV(lhs, originalLhsSTy)));
926 }
927 default: {
928 − panic(Error("Operator fallthrough: -")); // LCOV_EXCL_LINE
929 }
930 }
931 ✗ }
932
933 // Shared implementation of getPrefixPlusPlusInst, getPrefixMinusMinusInst, getPostfixPlusPlusInst and getPostfixMinusMinusInst
934 8913 f<LLVMExprResult> OpRuleConversionManager.getIncDecInst(bool isInc, LLVMExprResult& lhs, const QualType& origLhsSTy, string opName) {
935 8913 const QualType originalLhsSTy = origLhsSTy;
936 8913 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
937
938
4/5
✓ Branch 0 taken 1383 times.
✓ Branch 1 taken 28 times.
✓ Branch 2 taken 7470 times.
✓ Branch 3 taken 32 times.
✗ Branch 4 not taken.
8913 switch lhsSTy.getSuperType() {
939 case SuperType::TY_INT: {
940 1383 const llvm::Value one = this.builder.getInt32(1);
941 1383 const llvm::Value lhsV = this.lhsV(lhs, originalLhsSTy);
942
2/2
✓ Branch 0 taken 1334 times.
✓ Branch 1 taken 49 times.
1383 return exprResultWithValue(isInc ? this.createAdd(lhsV, one, lhsSTy.isSigned()) : this.createSub(lhsV, one, lhsSTy.isSigned()));
943 }
944 case SuperType::TY_SHORT: {
945 28 const llvm::Value one = this.builder.getInt16(1);
946 28 const llvm::Value lhsV = this.lhsV(lhs, originalLhsSTy);
947
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 16 times.
28 return exprResultWithValue(isInc ? this.createAdd(lhsV, one, lhsSTy.isSigned()) : this.createSub(lhsV, one, lhsSTy.isSigned()));
948 }
949 case SuperType::TY_LONG: {
950 7470 const llvm::Value one = this.builder.getInt64(1);
951 7470 const llvm::Value lhsV = this.lhsV(lhs, originalLhsSTy);
952
2/2
✓ Branch 0 taken 6773 times.
✓ Branch 1 taken 697 times.
7470 return exprResultWithValue(isInc ? this.createAdd(lhsV, one, lhsSTy.isSigned()) : this.createSub(lhsV, one, lhsSTy.isSigned()));
953 }
954 case SuperType::TY_PTR: {
955 32 const QualType elementSTy = lhsSTy.getContained();
956 32 const llvm::Type elementTy = elementSTy.toLLVMType(this.irGenerator.sourceFile);
957
2/2
✓ Branch 0 taken 28 times.
✓ Branch 1 taken 4 times.
32 const llvm::Value offset = isInc ? this.builder.getInt64(1) : llvm::getConstInt(this.builder.getInt64Ty(), cast<unsigned long>(-1l), true);
958 32 const llvm::Value lhsV = this.lhsV(lhs, originalLhsSTy);
959 32 return exprResultWithValue(this.builder.createGEP(elementTy, lhsV, offset));
960 }
961 default: {
962 − raiseOperatorFallthrough(opName); // LCOV_EXCL_LINE
963 ✗ }
964 }
965 − return LLVMExprResult(); // LCOV_EXCL_LINE
966 }
967
968 16 public f<LLVMExprResult> OpRuleConversionManager.getPrefixPlusPlusInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy) {
969 16 return this.getIncDecInst(true, lhs, lhsSTy, "++ (prefix)");
970 }
971
972 39 public f<LLVMExprResult> OpRuleConversionManager.getPrefixMinusMinusInst(ASTNode* _, LLVMExprResult& lhs, const QualType& lhsSTy) {
973 39 return this.getIncDecInst(false, lhs, lhsSTy, "-- (prefix)");
974 }
975
976 3609 public f<LLVMExprResult> OpRuleConversionManager.getPrefixNotInst(ASTNode* _, LLVMExprResult& lhs, const QualType& origLhsSTy) {
977 3609 const QualType originalLhsSTy = origLhsSTy;
978 3609 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
979
980
1/2
✓ Branch 0 taken 3609 times.
✗ Branch 1 not taken.
3609 if lhsSTy.is(SuperType::TY_BOOL) {
981 3609 return exprResultWithValue(this.builder.createNot(this.lhsV(lhs, originalLhsSTy)));
982 }
983 − panic(Error("Operator fallthrough: !")); // LCOV_EXCL_LINE
984 }
985
986 33 public f<LLVMExprResult> OpRuleConversionManager.getPrefixBitwiseNotInst(ASTNode* node, LLVMExprResult& lhs, const QualType& origLhsSTy) {
987 33 const OperandResolvers resolvers = getUnaryResolvers(lhs, origLhsSTy);
988 33 const QualType originalLhsSTy = origLhsSTy;
989 33 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
990
991 // Handle operator overloads
992
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 31 times.
33 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
993 4 return this.callOperatorOverloadFct(node, resolvers, 1l, DEFAULT_OP_IDX);
994 }
995
996
1/2
✓ Branch 0 taken 31 times.
✗ Branch 1 not taken.
31 switch lhsSTy.getSuperType() {
997 case SuperType::TY_INT, SuperType::TY_SHORT, SuperType::TY_LONG, SuperType::TY_BYTE: {
998 62 return exprResultWithValue(this.builder.createNot(this.lhsV(lhs, originalLhsSTy)));
999 }
1000 default: {
1001 − panic(Error("Operator fallthrough: ~")); // LCOV_EXCL_LINE
1002 }
1003 }
1004 33 }
1005
1006 8143 public f<LLVMExprResult> OpRuleConversionManager.getPostfixPlusPlusInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy) {
1007 8143 const OperandResolvers resolvers = getUnaryResolvers(lhs, lhsSTy);
1008
1009 // Handle operator overloads
1010
2/2
✓ Branch 0 taken 12 times.
✓ Branch 1 taken 8131 times.
8143 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
1011 24 return this.callOperatorOverloadFct(node, resolvers, 1l, DEFAULT_OP_IDX);
1012 }
1013
1014 16262 return this.getIncDecInst(true, lhs, lhsSTy, "++ (postfix)");
1015 8143 }
1016
1017 737 public f<LLVMExprResult> OpRuleConversionManager.getPostfixMinusMinusInst(ASTNode* node, LLVMExprResult& lhs, const QualType& lhsSTy) {
1018 737 const OperandResolvers resolvers = getUnaryResolvers(lhs, lhsSTy);
1019
1020 // Handle operator overloads
1021
2/2
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 727 times.
737 if this.callsOverloadedOpFct(node, DEFAULT_OP_IDX) {
1022 20 return this.callOperatorOverloadFct(node, resolvers, 1l, DEFAULT_OP_IDX);
1023 }
1024
1025 1454 return this.getIncDecInst(false, lhs, lhsSTy, "-- (postfix)");
1026 737 }
1027
1028 // ------------------------------------------------------------ Casts ------------------------------------------------------------
1029
1030 11775 public f<LLVMExprResult> OpRuleConversionManager.getCastInst(ASTNode* _, const QualType& origLhsSTy, LLVMExprResult& rhs, const QualType& origRhsSTy) {
1031 11775 const QualType originalRhsSTy = origRhsSTy;
1032 11775 const QualType lhsSTy = origLhsSTy.removeReferenceWrapper();
1033 11775 const QualType rhsSTy = origRhsSTy.removeReferenceWrapper();
1034 11775 const llvm::Type lhsT = lhsSTy.toLLVMType(this.irGenerator.sourceFile);
1035
1036 // Handle identity casts
1037
2/2
✓ Branch 0 taken 1339 times.
✓ Branch 1 taken 10436 times.
11775 if lhsSTy.matches(rhsSTy, false, true, false) {
1038 1339 return rhs;
1039 }
1040
1041 10436 const SuperType l = lhsSTy.getSuperType();
1042 10436 const SuperType r = rhsSTy.getSuperType();
1043 // Identity casts
1044
10/18
✓ Branch 0 taken 8316 times.
✓ Branch 1 taken 2120 times.
✓ Branch 2 taken 2120 times.
✗ Branch 3 not taken.
✓ Branch 4 taken 2120 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 2120 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2120 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 2120 times.
✗ Branch 11 not taken.
✓ Branch 12 taken 2120 times.
✗ Branch 13 not taken.
✗ Branch 14 not taken.
✓ Branch 15 taken 2120 times.
✗ Branch 16 not taken.
✓ Branch 17 taken 10436 times.
10436 if l == r && (l == SuperType::TY_DOUBLE || l == SuperType::TY_INT || l == SuperType::TY_SHORT || l == SuperType::TY_LONG || l == SuperType::TY_BYTE || l == SuperType::TY_CHAR || l == SuperType::TY_STRING || l == SuperType::TY_BOOL) {
1045 ✗ return rhs;
1046 }
1047
2/2
✓ Branch 0 taken 2120 times.
✓ Branch 1 taken 8316 times.
10436 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_PTR) {
1048 // Handle safe struct-pointer upcasts: cast<Base*>(derived) / cast<Interface*>(struct). The pointer must be
1049 // advanced to the embedded subobject (past any vtable prefix) instead of being passed through unchanged.
1050 2120 const QualType lhsContained = lhsSTy.getContained();
1051 2120 const QualType rhsContained = rhsSTy.getContained();
1052
4/4
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 2118 times.
✓ Branch 2 taken 6 times.
✓ Branch 3 taken 2114 times.
2120 if lhsContained.matchesInterfaceImplementedByStruct(rhsContained) || lhsContained.matchesComposedBaseOfStruct(rhsContained) {
1053 6 const llvm::Value rhsV = this.rhsV(rhs, originalRhsSTy);
1054 6 return exprResultWithValue(this.irGenerator.getUpcastedStructPtr(rhsV, lhsSTy, rhsSTy));
1055 }
1056 2114 return rhs;
1057 }
1058
6/6
✓ Branch 0 taken 8302 times.
✓ Branch 1 taken 14 times.
✓ Branch 2 taken 1 time.
✓ Branch 3 taken 8301 times.
✓ Branch 4 taken 37 times.
✓ Branch 5 taken 8279 times.
8316 if isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_DOUBLE, SuperType::TY_LONG) {
1059 37 const llvm::Value rhsV = this.rhsV(rhs, originalRhsSTy);
1060
2/2
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 21 times.
37 return exprResultWithValue(rhsSTy.isSigned() ? this.builder.createSIToFP(rhsV, lhsT) : this.builder.createUIToFP(rhsV, lhsT));
1061 }
1062
6/6
✓ Branch 0 taken 8228 times.
✓ Branch 1 taken 51 times.
✓ Branch 2 taken 41 times.
✓ Branch 3 taken 8187 times.
✓ Branch 4 taken 151 times.
✓ Branch 5 taken 8128 times.
8279 if isComb(l, r, SuperType::TY_INT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_DOUBLE) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_DOUBLE) {
1063 151 const llvm::Value rhsV = this.rhsV(rhs, originalRhsSTy);
1064
2/2
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 12 times.
151 return exprResultWithValue(lhsSTy.isSigned() ? this.builder.createFPToSI(rhsV, lhsT) : this.builder.createFPToUI(rhsV, lhsT));
1065 }
1066
22/22
✓ Branch 0 taken 8045 times.
✓ Branch 1 taken 83 times.
✓ Branch 2 taken 7550 times.
✓ Branch 3 taken 495 times.
✓ Branch 4 taken 7356 times.
✓ Branch 5 taken 194 times.
✓ Branch 6 taken 7081 times.
✓ Branch 7 taken 275 times.
✓ Branch 8 taken 6951 times.
✓ Branch 9 taken 130 times.
✓ Branch 10 taken 6818 times.
✓ Branch 11 taken 133 times.
✓ Branch 12 taken 5325 times.
✓ Branch 13 taken 1493 times.
✓ Branch 14 taken 5270 times.
✓ Branch 15 taken 55 times.
✓ Branch 16 taken 4746 times.
✓ Branch 17 taken 524 times.
✓ Branch 18 taken 4661 times.
✓ Branch 19 taken 85 times.
✓ Branch 20 taken 41 times.
✓ Branch 21 taken 4620 times.
8128 const bool intCast = isComb(l, r, SuperType::TY_INT, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_INT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_INT, SuperType::TY_BYTE) || isComb(l, r, SuperType::TY_INT, SuperType::TY_CHAR) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_INT) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_INT) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_INT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_INT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_SHORT) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_LONG);
1067
2/2
✓ Branch 0 taken 3552 times.
✓ Branch 1 taken 4576 times.
8128 if intCast {
1068 3552 const llvm::Value rhsV = this.rhsV(rhs, originalRhsSTy);
1069 3552 return exprResultWithValue(this.builder.createIntCast(rhsV, lhsT, rhsSTy.isSigned()));
1070 }
1071
8/8
✓ Branch 0 taken 4524 times.
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 4478 times.
✓ Branch 3 taken 46 times.
✓ Branch 4 taken 282 times.
✓ Branch 5 taken 4196 times.
✓ Branch 6 taken 4385 times.
✓ Branch 7 taken 191 times.
4576 if isComb(l, r, SuperType::TY_BYTE, SuperType::TY_CHAR) || isComb(l, r, SuperType::TY_CHAR, SuperType::TY_BYTE) || isComb(l, r, SuperType::TY_STRING, SuperType::TY_PTR) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_STRING) {
1072 4385 return exprResultWithValue(this.rhsV(rhs, originalRhsSTy));
1073 }
1074
8/8
✓ Branch 0 taken 57 times.
✓ Branch 1 taken 134 times.
✓ Branch 2 taken 56 times.
✓ Branch 3 taken 1 time.
✓ Branch 4 taken 1 time.
✓ Branch 5 taken 55 times.
✓ Branch 6 taken 137 times.
✓ Branch 7 taken 54 times.
191 if isComb(l, r, SuperType::TY_INT, SuperType::TY_BOOL) || isComb(l, r, SuperType::TY_SHORT, SuperType::TY_BOOL) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_BOOL) || isComb(l, r, SuperType::TY_BYTE, SuperType::TY_BOOL) {
1075 // Bool is always unsigned (0 or 1), so zero-extend rather than sign-extend to avoid true -> -1
1076 137 return exprResultWithValue(this.builder.createZExt(this.rhsV(rhs, originalRhsSTy), lhsT));
1077 }
1078
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if isComb(l, r, SuperType::TY_ARRAY, SuperType::TY_PTR) || isComb(l, r, SuperType::TY_ARRAY, SuperType::TY_STRING) {
1079 ✗ assert lhsSTy.isArrayOf(SuperType::TY_CHAR);
1080 ✗ assert rhsSTy.isPtrTo(SuperType::TY_CHAR) || rhsSTy.is(SuperType::TY_STRING);
1081 ✗ const llvm::Type rhsT = rhsSTy.toLLVMType(this.irGenerator.sourceFile);
1082 ✗ return exprResultWithValue(this.builder.createBitCast(this.rhsV(rhs, originalRhsSTy), rhsT));
1083 }
1084
2/4
✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 54 times.
54 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_ARRAY) || isComb(l, r, SuperType::TY_STRING, SuperType::TY_ARRAY) {
1085 ✗ assert lhsSTy.isPtrTo(SuperType::TY_CHAR) || lhsSTy.is(SuperType::TY_STRING);
1086 ✗ assert rhsSTy.isArrayOf(SuperType::TY_CHAR);
1087 ✗ const llvm::Value rhsP = this.irGenerator.resolveAddress(rhs);
1088 ✗ return exprResultWithValue(this.builder.createInBoundsGEP(this.builder.getInt8Ty(), rhsP, this.builder.getInt32(0)));
1089 }
1090
4/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 44 times.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 43 times.
54 if isComb(l, r, SuperType::TY_LONG, SuperType::TY_PTR) || isComb(l, r, SuperType::TY_LONG, SuperType::TY_STRING) {
1091 // The type checker only lets a pointer be cast to 'long', which is 64 bit wide on every Spice target, so this
1092 // never truncates. On a target with narrower pointers (e.g. wasm32) 'ptrtoint' zero-extends instead.
1093 11 return exprResultWithValue(this.builder.createPtrToInt(this.rhsV(rhs, originalRhsSTy), lhsT));
1094 }
1095
4/4
✓ Branch 0 taken 7 times.
✓ Branch 1 taken 36 times.
✓ Branch 2 taken 8 times.
✓ Branch 3 taken 35 times.
43 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_LONG) || isComb(l, r, SuperType::TY_STRING, SuperType::TY_LONG) {
1096 8 return exprResultWithValue(this.builder.createIntToPtr(this.rhsV(rhs, originalRhsSTy), lhsT));
1097 }
1098
3/4
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 25 times.
✓ Branch 2 taken 35 times.
✗ Branch 3 not taken.
35 if isComb(l, r, SuperType::TY_PTR, SuperType::TY_FUNCTION) || isComb(l, r, SuperType::TY_PTR, SuperType::TY_PROCEDURE) {
1099 35 assert lhsSTy.isPtrTo(SuperType::TY_BYTE);
1100 35 const llvm::Value rhsP = this.irGenerator.resolveAddress(rhs);
1101 35 const llvm::Value fctPtrPtr = this.irGenerator.insertStructGEP(this.irGenerator.llvmTypes.lambdaFatPtrType, rhsP, 0);
1102 35 const llvm::Value fctPtr = this.irGenerator.insertLoad(this.builder.getPtrTy(), fctPtrPtr);
1103 35 return exprResultWithValue(fctPtr);
1104 }
1105 − panic(Error("Operator fallthrough: (cast)")); // LCOV_EXCL_LINE
1106 }
1107
1108 // ----------------------------------------------------- Operator overloading ----------------------------------------------------
1109
1110 124696 public f<bool> OpRuleConversionManager.callsOverloadedOpFct(ASTNode* node, unsigned long opIdx) {
1111 124696 const Vector<const model::Function*>& opFctList = this.irGenerator.getOpFctPointers(node);
1112
2/2
✓ Branch 0 taken 1743 times.
✓ Branch 1 taken 122953 times.
124696 return opFctList.getSize() > opIdx && opFctList.get(opIdx) != nil<const model::Function*>;
1113 }
1114
1115 /**
1116 * Call the overloaded operator function of the given node
1117 *
1118 * @param node Operator node
1119 * @param opV Resolvers for lhsV, lhsP, rhsV and rhsP (the last two only for binary operators)
1120 * @param n Number of operands (1 for unary, 2 for binary operators)
1121 * @param opIdx Index of the operator
1122 * @return Result of the call
1123 */
1124 4907 public f<LLVMExprResult> OpRuleConversionManager.callOperatorOverloadFct(ASTNode* node, const OperandResolvers& opV, unsigned long n, unsigned long opIdx) {
1125 4907 assert n == 1l || n == 2l; // Only unary and binary operators are overloadable
1126 4907 const unsigned long manIdx = this.irGenerator.manIdx;
1127 4907 const Vector<Vector<const model::Function*>>* opFctPointers = node.getOpFctPointers();
1128 4907 assert !opFctPointers.isEmpty() && opFctPointers.getSize() > manIdx;
1129 4907 const Vector<const model::Function*>& manifestationOpFcts = opFctPointers.get(manIdx);
1130 4907 assert !manifestationOpFcts.isEmpty() && manifestationOpFcts.getSize() > opIdx;
1131 4907 const model::Function* opFct = manifestationOpFcts.get(opIdx);
1132 4907 assert opFct != nil<const model::Function*>;
1133
1134 4907 const String mangledName = opFct.getMangledName();
1135 4907 assert opFct.entry.scope != nil<Scope*>;
1136
1137 // Get arg values
1138 4907 const QualTypeList paramTypes = opFct.getParamTypes();
1139 4907 assert paramTypes.getSize() == n;
1140 // References and decayed arrays are passed as address, everything else as value
1141 4907 Vector<llvm::Value> argValues;
1142
2/2
✓ Branch 0 taken 9790 times.
✓ Branch 1 taken 4907 times.
14697 for unsigned long i = 0l; i < n; i++ {
1143 9790 const QualType& paramType = paramTypes.get(i);
1144 // By-value params of non-trivially copyable types own their argument, so they get a copy of it
1145 9790 const bool isOwnedByValue = paramType.isOwnedByValueParam(node);
1146
4/4
✓ Branch 0 taken 2241 times.
✓ Branch 1 taken 7549 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 2239 times.
9790 const bool passAsAddress = paramType.isRef() || paramType.isDecayedArray() || isOwnedByValue;
1147
2/2
✓ Branch 0 taken 7553 times.
✓ Branch 1 taken 2237 times.
9790 const Resolver& resolver = opV.resolvers.get(passAsAddress ? 2l * i + 1l : 2l * i);
1148 9790 const llvm::Value argValue = this.irGenerator.resolve(resolver);
1149
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 9788 times.
9790 argValues.pushBack(isOwnedByValue ? this.irGenerator.generateOwnedArgValue(argValue, paramType) : argValue);
1150 9790 }
1151 // Decayed array params expect the address of a writable array, which the resolvers above do not guarantee
1152
2/2
✓ Branch 0 taken 9790 times.
✓ Branch 1 taken 4907 times.
14697 for unsigned long i = 0l; i < n; i++ {
1153 9790 const QualType& paramType = paramTypes.get(i);
1154
2/2
✓ Branch 0 taken 9788 times.
✓ Branch 1 taken 2 times.
9790 if paramType.isDecayedArray() {
1155 2 llvm::Value& argValue = argValues.get(i);
1156 2 argValue = this.irGenerator.materializeDecayedArrayArg(argValue, paramType);
1157 2 }
1158 9790 }
1159
1160 // Function is not defined in the current module -> declare it
1161
2/2
✓ Branch 0 taken 1541 times.
✓ Branch 1 taken 3366 times.
4907 const QualType returnType = opFct.isProcedure() ? QualType(SuperType::TY_DYN) : opFct.returnType;
1162 4907 llvm::Module* module = this.irGenerator.module;
1163 4907 llvm::Function callee = module.getFunction(mangledName.getRaw());
1164
2/2
✓ Branch 0 taken 4006 times.
✓ Branch 1 taken 901 times.
4907 if callee.isNull() {
1165 // Get arg types
1166 901 Vector<llvm::Type> argTypes;
1167
2/2
✓ Branch 0 taken 1785 times.
✓ Branch 1 taken 901 times.
2686 foreach const QualType& paramType : paramTypes {
1168 1785 argTypes.pushBack(paramType.getParamLLVMType(this.irGenerator.sourceFile));
1169 1785 }
1170
1171 901 const llvm::Type fctType = this.irGenerator.getFunctionType(returnType, argTypes);
1172 901 callee = module.getOrInsertFunction(mangledName.getRaw(), fctType);
1173 901 const ReturnABIInfo returnABI = this.irGenerator.getReturnABIInfo(returnType);
1174
2/2
✓ Branch 0 taken 836 times.
✓ Branch 1 taken 65 times.
901 if returnABI.isIndirect() {
1175 65 this.irGenerator.addSRetParamAttrs(callee, returnABI.memoryType);
1176 65 }
1177 901 }
1178
1179 // Get callee function
1180 4907 assert !callee.isNull();
1181
1182 // Generate function call. If the value is returned via memory or coerced, the call result lives in memory
1183 4907 llvm::Value resultAddr;
1184 4907 const llvm::Value res = this.irGenerator.insertCall(callee, argValues, returnType, resultAddr);
1185
1186 // If this is a procedure, return true
1187
2/2
✓ Branch 0 taken 1541 times.
✓ Branch 1 taken 3366 times.
4907 if opFct.isProcedure() {
1188 3082 return exprResultWithConstant(this.builder.getTrue());
1189 }
1190
1191 // Attach address to anonymous symbol to keep track of de-allocation
1192 3366 const SymbolTableEntry* anonymousSymbol = nil<const SymbolTableEntry*>;
1193 3366 llvm::Value resultPtr;
1194
2/2
✓ Branch 0 taken 3203 times.
✓ Branch 1 taken 163 times.
3366 if opFct.returnType.is(SuperType::TY_STRUCT) {
1195 163 anonymousSymbol = this.irGenerator.currentScope.symbolTable.lookupAnonymous(node, opIdx);
1196
2/2
✓ Branch 0 taken 79 times.
✓ Branch 1 taken 84 times.
163 if anonymousSymbol != nil<const SymbolTableEntry*> {
1197 84 resultPtr = resultAddr;
1198
1/2
✓ Branch 0 taken 84 times.
✗ Branch 1 not taken.
84 if resultPtr.isNull() {
1199 ✗ resultPtr = this.irGenerator.insertAlloca(res.getType());
1200 ✗ this.irGenerator.insertStore(res, resultPtr);
1201 ✗ }
1202 84 this.irGenerator.updateAddress(anonymousSymbol, resultPtr);
1203 84 }
1204 163 }
1205
1206 // If the return type is reference, return the result value as refPtr
1207 3366 LLVMExprResult exprResult;
1208 3366 exprResult.entry = anonymousSymbol;
1209
2/2
✓ Branch 0 taken 1123 times.
✓ Branch 1 taken 2243 times.
3366 if opFct.returnType.isRef() {
1210 1123 exprResult.ptr = res;
1211 1123 exprResult.refPtr = resultPtr;
1212 2246 return exprResult;
1213 }
1214
1215 // In case the value is returned via memory or coerced, return its address
1216
2/2
✓ Branch 0 taken 163 times.
✓ Branch 1 taken 2080 times.
2243 if !resultAddr.isNull() {
1217 163 exprResult.ptr = resultAddr;
1218 326 return exprResult;
1219 }
1220
1221 // Otherwise as value
1222 2080 exprResult.value = res;
1223 2080 exprResult.ptr = resultPtr;
1224 4160 return exprResult;
1225 4907 }
1226
1227 // ----------------------------------------------------------- Helpers -----------------------------------------------------------
1228
1229 // Abort with an unhandled branch error for the given operator
1230 ✗ p raiseOperatorFallthrough(string opName) {
1231 ✗ const String message = String("Operator fallthrough: ") + opName;
1232 ✗ panic(Error(message.getRaw()));
1233 ✗ }
1234
1235 352 f<llvm::Value> OpRuleConversionManager.generateIToFp(const QualType& srcSTy, llvm::Value srcV, llvm::Type tgtT) {
1236
2/2
✓ Branch 0 taken 338 times.
✓ Branch 1 taken 14 times.
352 if srcSTy.isSigned() {
1237 338 return this.builder.createSIToFP(srcV, tgtT);
1238 } else {
1239 14 return this.builder.createUIToFP(srcV, tgtT);
1240 }
1241 ✗ }
1242
1243 336 f<llvm::Value> OpRuleConversionManager.generateSHR(const QualType& lhsSTy, const QualType& _, llvm::Value lhsV, llvm::Value rhsV) {
1244
2/2
✓ Branch 0 taken 56 times.
✓ Branch 1 taken 280 times.
336 if lhsSTy.isSigned() {
1245 56 return this.builder.createAShr(lhsV, rhsV);
1246 } else {
1247 280 return this.builder.createLShr(lhsV, rhsV);
1248 }
1249 ✗ }
1250
1251 6879 f<llvm::Value> OpRuleConversionManager.generateLT(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1252
2/2
✓ Branch 0 taken 1170 times.
✓ Branch 1 taken 5709 times.
6879 if isSignedOperation(lhsSTy, rhsSTy) {
1253 1170 return this.createICmp(llvm::LLVMIntPredicate::SLT, lhsV, rhsV);
1254 } else {
1255 5709 return this.createICmp(llvm::LLVMIntPredicate::ULT, lhsV, rhsV);
1256 }
1257 ✗ }
1258
1259 2145 f<llvm::Value> OpRuleConversionManager.generateLE(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1260
2/2
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 2072 times.
2145 if isSignedOperation(lhsSTy, rhsSTy) {
1261 73 return this.createICmp(llvm::LLVMIntPredicate::SLE, lhsV, rhsV);
1262 } else {
1263 2072 return this.createICmp(llvm::LLVMIntPredicate::ULE, lhsV, rhsV);
1264 }
1265 ✗ }
1266
1267 3596 f<llvm::Value> OpRuleConversionManager.generateGT(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1268
2/2
✓ Branch 0 taken 795 times.
✓ Branch 1 taken 2801 times.
3596 if isSignedOperation(lhsSTy, rhsSTy) {
1269 795 return this.createICmp(llvm::LLVMIntPredicate::SGT, lhsV, rhsV);
1270 } else {
1271 2801 return this.createICmp(llvm::LLVMIntPredicate::UGT, lhsV, rhsV);
1272 }
1273 ✗ }
1274
1275 4068 f<llvm::Value> OpRuleConversionManager.generateGE(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1276
2/2
✓ Branch 0 taken 201 times.
✓ Branch 1 taken 3867 times.
4068 if isSignedOperation(lhsSTy, rhsSTy) {
1277 201 return this.createICmp(llvm::LLVMIntPredicate::SGE, lhsV, rhsV);
1278 } else {
1279 3867 return this.createICmp(llvm::LLVMIntPredicate::UGE, lhsV, rhsV);
1280 }
1281 ✗ }
1282
1283 214 f<llvm::Value> OpRuleConversionManager.generateDiv(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1284
2/2
✓ Branch 0 taken 100 times.
✓ Branch 1 taken 114 times.
214 if isSignedOperation(lhsSTy, rhsSTy) {
1285 100 return this.builder.createSDiv(lhsV, rhsV);
1286 } else {
1287 114 return this.builder.createUDiv(lhsV, rhsV);
1288 }
1289 ✗ }
1290
1291 267 f<llvm::Value> OpRuleConversionManager.generateRem(const QualType& lhsSTy, const QualType& rhsSTy, llvm::Value lhsV, llvm::Value rhsV) {
1292
2/2
✓ Branch 0 taken 85 times.
✓ Branch 1 taken 182 times.
267 if isSignedOperation(lhsSTy, rhsSTy) {
1293 85 return this.builder.createSRem(lhsV, rhsV);
1294 } else {
1295 182 return this.builder.createURem(lhsV, rhsV);
1296 }
1297 ✗ }
1298