|
7 | 7 | // |
8 | 8 | //===----------------------------------------------------------------------===// |
9 | 9 |
|
10 | | -#include "gen/llvm.h" |
| 10 | +#include "gen/binops.h" |
11 | 11 | #include "declaration.h" |
12 | 12 | #include "gen/complex.h" |
13 | 13 | #include "gen/dvalue.h" |
14 | 14 | #include "gen/irstate.h" |
| 15 | +#include "gen/llvm.h" |
15 | 16 | #include "gen/llvmhelpers.h" |
16 | 17 | #include "gen/logger.h" |
17 | 18 | #include "gen/tollvm.h" |
18 | 19 |
|
19 | 20 | ////////////////////////////////////////////////////////////////////////////// |
20 | 21 |
|
21 | | -DImValue *DtoBinAdd(DRValue *lhs, DRValue *rhs) { |
22 | | - Type *t = lhs->type; |
23 | | - LLValue *l = DtoRVal(lhs); |
24 | | - LLValue *r = DtoRVal(rhs); |
| 22 | +dinteger_t undoStrideMul(Loc &loc, Type *t, dinteger_t offset) { |
| 23 | + assert(t->ty == Tpointer); |
| 24 | + d_uns64 elemSize = t->nextOf()->size(loc); |
| 25 | + assert((offset % elemSize) == 0 && |
| 26 | + "Expected offset by an integer amount of elements"); |
25 | 27 |
|
26 | | - LLValue *res; |
27 | | - if (t->isfloating()) { |
28 | | - res = gIR->ir->CreateFAdd(l, r); |
| 28 | + return offset / elemSize; |
| 29 | +} |
| 30 | + |
| 31 | +////////////////////////////////////////////////////////////////////////////// |
| 32 | + |
| 33 | +namespace { |
| 34 | +struct RVals { |
| 35 | + DRValue *lhs, *rhs; |
| 36 | +}; |
| 37 | + |
| 38 | +RVals evalSides(DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { |
| 39 | + RVals rvals; |
| 40 | + |
| 41 | + if (!loadLhsAfterRhs) { |
| 42 | + rvals.lhs = lhs->getRVal(); |
| 43 | + rvals.rhs = toElem(rhs)->getRVal(); |
29 | 44 | } else { |
30 | | - res = gIR->ir->CreateAdd(l, r); |
| 45 | + rvals.rhs = toElem(rhs)->getRVal(); |
| 46 | + rvals.lhs = lhs->getRVal(); |
31 | 47 | } |
32 | 48 |
|
33 | | - return new DImValue(t, res); |
| 49 | + return rvals; |
34 | 50 | } |
35 | 51 |
|
36 | | -////////////////////////////////////////////////////////////////////////////// |
| 52 | +/// Tries to remove a MulExp by a constant value of baseSize from e. Returns |
| 53 | +/// NULL if not possible. |
| 54 | +Expression *extractNoStrideInc(Expression *e, d_uns64 baseSize, bool &negate) { |
| 55 | + MulExp *mul; |
| 56 | + while (true) { |
| 57 | + if (e->op == TOKneg) { |
| 58 | + negate = !negate; |
| 59 | + e = static_cast<NegExp *>(e)->e1; |
| 60 | + continue; |
| 61 | + } |
37 | 62 |
|
38 | | -DImValue *DtoBinSub(DRValue *lhs, DRValue *rhs) { |
39 | | - Type *t = lhs->type; |
40 | | - LLValue *l = DtoRVal(lhs); |
41 | | - LLValue *r = DtoRVal(rhs); |
| 63 | + if (e->op == TOKmul) { |
| 64 | + mul = static_cast<MulExp *>(e); |
| 65 | + break; |
| 66 | + } |
42 | 67 |
|
43 | | - LLValue *res; |
44 | | - if (t->isfloating()) { |
45 | | - res = gIR->ir->CreateFSub(l, r); |
| 68 | + return nullptr; |
| 69 | + } |
| 70 | + |
| 71 | + if (!mul->e2->isConst()) { |
| 72 | + return nullptr; |
| 73 | + } |
| 74 | + dinteger_t stride = mul->e2->toInteger(); |
| 75 | + |
| 76 | + if (stride != baseSize) { |
| 77 | + return nullptr; |
| 78 | + } |
| 79 | + |
| 80 | + return mul->e1; |
| 81 | +} |
| 82 | + |
| 83 | +DValue *emitPointerOffset(Loc loc, DValue *base, Expression *offset, |
| 84 | + bool negateOffset, Type *resultType, |
| 85 | + bool loadLhsAfterRhs) { |
| 86 | + // The operand emitted by the frontend is in units of bytes, and not |
| 87 | + // pointer elements. We try to undo this before resorting to |
| 88 | + // temporarily bitcasting the pointer to i8. |
| 89 | + |
| 90 | + LLValue *llBase = nullptr; |
| 91 | + LLValue *llOffset = nullptr; |
| 92 | + LLValue *llResult = nullptr; |
| 93 | + |
| 94 | + if (offset->isConst()) { |
| 95 | + llBase = DtoRVal(base); |
| 96 | + dinteger_t byteOffset = offset->toInteger(); |
| 97 | + if (byteOffset == 0) { |
| 98 | + llResult = llBase; |
| 99 | + } else { |
| 100 | + llOffset = DtoConstSize_t(undoStrideMul(loc, base->type, byteOffset)); |
| 101 | + } |
46 | 102 | } else { |
47 | | - res = gIR->ir->CreateSub(l, r); |
| 103 | + Expression *noStrideInc = extractNoStrideInc( |
| 104 | + offset, base->type->nextOf()->size(loc), negateOffset); |
| 105 | + auto rvals = |
| 106 | + evalSides(base, noStrideInc ? noStrideInc : offset, loadLhsAfterRhs); |
| 107 | + llBase = DtoRVal(rvals.lhs); |
| 108 | + llOffset = DtoRVal(rvals.rhs); |
| 109 | + if (!noStrideInc) // byte offset => cast base to i8* |
| 110 | + llBase = DtoBitCast(llBase, getVoidPtrType()); |
| 111 | + } |
| 112 | + |
| 113 | + if (!llResult) { |
| 114 | + if (negateOffset) |
| 115 | + llOffset = gIR->ir->CreateNeg(llOffset); |
| 116 | + llResult = DtoGEP1(llBase, llOffset, false); |
48 | 117 | } |
49 | 118 |
|
50 | | - return new DImValue(t, res); |
| 119 | + return new DImValue(resultType, DtoBitCast(llResult, DtoType(resultType))); |
| 120 | +} |
51 | 121 | } |
52 | 122 |
|
53 | 123 | ////////////////////////////////////////////////////////////////////////////// |
54 | 124 |
|
55 | | -DImValue *DtoBinMul(Type *targettype, DRValue *lhs, DRValue *rhs) { |
56 | | - Type *t = lhs->type; |
57 | | - LLValue *l = DtoRVal(lhs); |
58 | | - LLValue *r = DtoRVal(rhs); |
| 125 | +DValue *binAdd(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 126 | + bool loadLhsAfterRhs) { |
| 127 | + Type *lhsType = lhs->type->toBasetype(); |
| 128 | + Type *rhsType = rhs->type->toBasetype(); |
59 | 129 |
|
60 | | - LLValue *res; |
61 | | - if (t->isfloating()) { |
62 | | - res = gIR->ir->CreateFMul(l, r); |
63 | | - } else { |
64 | | - res = gIR->ir->CreateMul(l, r); |
| 130 | + if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { |
| 131 | + Logger::println("Adding integer to pointer"); |
| 132 | + return emitPointerOffset(loc, lhs, rhs, false, type, loadLhsAfterRhs); |
65 | 133 | } |
66 | 134 |
|
67 | | - return new DImValue(targettype, res); |
| 135 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
| 136 | + |
| 137 | + if (type->iscomplex()) |
| 138 | + return DtoComplexAdd(loc, type, rvals.lhs, rvals.rhs); |
| 139 | + |
| 140 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 141 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
| 142 | + LLValue *res = (type->isfloating() ? gIR->ir->CreateFAdd(l, r) |
| 143 | + : gIR->ir->CreateAdd(l, r)); |
| 144 | + |
| 145 | + return new DImValue(type, res); |
68 | 146 | } |
69 | 147 |
|
70 | 148 | ////////////////////////////////////////////////////////////////////////////// |
71 | 149 |
|
72 | | -DImValue *DtoBinDiv(Type *targettype, DRValue *lhs, DRValue *rhs) { |
73 | | - Type *t = lhs->type; |
74 | | - LLValue *l = DtoRVal(lhs); |
75 | | - LLValue *r = DtoRVal(rhs); |
| 150 | +DValue *binMin(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 151 | + bool loadLhsAfterRhs) { |
| 152 | + Type *lhsType = lhs->type->toBasetype(); |
| 153 | + Type *rhsType = rhs->type->toBasetype(); |
76 | 154 |
|
| 155 | + if (lhsType != rhsType && lhsType->ty == Tpointer && rhsType->isintegral()) { |
| 156 | + Logger::println("Subtracting integer from pointer"); |
| 157 | + return emitPointerOffset(loc, lhs, rhs, true, type, loadLhsAfterRhs); |
| 158 | + } |
| 159 | + |
| 160 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
| 161 | + |
| 162 | + if (lhsType->ty == Tpointer && rhsType->ty == Tpointer) { |
| 163 | + LLValue *l = DtoRVal(rvals.lhs); |
| 164 | + LLValue *r = DtoRVal(rvals.rhs); |
| 165 | + LLType *llSizeT = DtoSize_t(); |
| 166 | + l = gIR->ir->CreatePtrToInt(l, llSizeT); |
| 167 | + r = gIR->ir->CreatePtrToInt(r, llSizeT); |
| 168 | + LLValue *diff = gIR->ir->CreateSub(l, r); |
| 169 | + LLType *llType = DtoType(type); |
| 170 | + if (diff->getType() != llType) |
| 171 | + diff = gIR->ir->CreateIntToPtr(diff, llType); |
| 172 | + return new DImValue(type, diff); |
| 173 | + } |
| 174 | + |
| 175 | + if (type->iscomplex()) |
| 176 | + return DtoComplexMin(loc, type, rvals.lhs, rvals.rhs); |
| 177 | + |
| 178 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 179 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
| 180 | + LLValue *res = (type->isfloating() ? gIR->ir->CreateFSub(l, r) |
| 181 | + : gIR->ir->CreateSub(l, r)); |
| 182 | + |
| 183 | + return new DImValue(type, res); |
| 184 | +} |
| 185 | + |
| 186 | +////////////////////////////////////////////////////////////////////////////// |
| 187 | + |
| 188 | +DValue *binMul(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 189 | + bool loadLhsAfterRhs) { |
| 190 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
| 191 | + |
| 192 | + if (type->iscomplex()) |
| 193 | + return DtoComplexMul(loc, type, rvals.lhs, rvals.rhs); |
| 194 | + |
| 195 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 196 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
| 197 | + LLValue *res = (type->isfloating() ? gIR->ir->CreateFMul(l, r) |
| 198 | + : gIR->ir->CreateMul(l, r)); |
| 199 | + |
| 200 | + return new DImValue(type, res); |
| 201 | +} |
| 202 | + |
| 203 | +////////////////////////////////////////////////////////////////////////////// |
| 204 | + |
| 205 | +DValue *binDiv(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 206 | + bool loadLhsAfterRhs) { |
| 207 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
| 208 | + |
| 209 | + if (type->iscomplex()) |
| 210 | + return DtoComplexDiv(loc, type, rvals.lhs, rvals.rhs); |
| 211 | + |
| 212 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 213 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
77 | 214 | LLValue *res; |
78 | | - if (t->isfloating()) { |
| 215 | + if (type->isfloating()) { |
79 | 216 | res = gIR->ir->CreateFDiv(l, r); |
80 | | - } else if (!isLLVMUnsigned(t)) { |
| 217 | + } else if (!isLLVMUnsigned(type)) { |
81 | 218 | res = gIR->ir->CreateSDiv(l, r); |
82 | 219 | } else { |
83 | 220 | res = gIR->ir->CreateUDiv(l, r); |
84 | 221 | } |
85 | 222 |
|
86 | | - return new DImValue(targettype, res); |
| 223 | + return new DImValue(type, res); |
87 | 224 | } |
88 | 225 |
|
89 | 226 | ////////////////////////////////////////////////////////////////////////////// |
90 | 227 |
|
91 | | -DImValue *DtoBinRem(Type *targettype, DRValue *lhs, DRValue *rhs) { |
92 | | - Type *t = lhs->type; |
93 | | - LLValue *l = DtoRVal(lhs); |
94 | | - LLValue *r = DtoRVal(rhs); |
| 228 | +DValue *binMod(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 229 | + bool loadLhsAfterRhs) { |
| 230 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
95 | 231 |
|
| 232 | + if (type->iscomplex()) |
| 233 | + return DtoComplexMod(loc, type, rvals.lhs, rvals.rhs); |
| 234 | + |
| 235 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 236 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
96 | 237 | LLValue *res; |
97 | | - if (t->isfloating()) { |
| 238 | + if (type->isfloating()) { |
98 | 239 | res = gIR->ir->CreateFRem(l, r); |
99 | | - } else if (!isLLVMUnsigned(t)) { |
| 240 | + } else if (!isLLVMUnsigned(type)) { |
100 | 241 | res = gIR->ir->CreateSRem(l, r); |
101 | 242 | } else { |
102 | 243 | res = gIR->ir->CreateURem(l, r); |
103 | 244 | } |
104 | 245 |
|
105 | | - return new DImValue(targettype, res); |
| 246 | + return new DImValue(type, res); |
| 247 | +} |
| 248 | + |
| 249 | +////////////////////////////////////////////////////////////////////////////// |
| 250 | + |
| 251 | +namespace { |
| 252 | +DValue *binBitwise(llvm::Instruction::BinaryOps binOp, Loc &loc, Type *type, |
| 253 | + DValue *lhs, Expression *rhs, bool loadLhsAfterRhs) { |
| 254 | + auto rvals = evalSides(lhs, rhs, loadLhsAfterRhs); |
| 255 | + |
| 256 | + LLValue *l = DtoRVal(DtoCast(loc, rvals.lhs, type)); |
| 257 | + LLValue *r = DtoRVal(DtoCast(loc, rvals.rhs, type)); |
| 258 | + LLValue *res = llvm::BinaryOperator::Create(binOp, l, r, "", gIR->scopebb()); |
| 259 | + |
| 260 | + return new DImValue(type, res); |
| 261 | +} |
| 262 | +} |
| 263 | + |
| 264 | +DValue *binAnd(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 265 | + bool loadLhsAfterRhs) { |
| 266 | + return binBitwise(llvm::Instruction::And, loc, type, lhs, rhs, |
| 267 | + loadLhsAfterRhs); |
| 268 | +} |
| 269 | + |
| 270 | +DValue *binOr(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 271 | + bool loadLhsAfterRhs) { |
| 272 | + return binBitwise(llvm::Instruction::Or, loc, type, lhs, rhs, |
| 273 | + loadLhsAfterRhs); |
| 274 | +} |
| 275 | + |
| 276 | +DValue *binXor(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 277 | + bool loadLhsAfterRhs) { |
| 278 | + return binBitwise(llvm::Instruction::Xor, loc, type, lhs, rhs, |
| 279 | + loadLhsAfterRhs); |
| 280 | +} |
| 281 | + |
| 282 | +DValue *binShl(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 283 | + bool loadLhsAfterRhs) { |
| 284 | + return binBitwise(llvm::Instruction::Shl, loc, type, lhs, rhs, |
| 285 | + loadLhsAfterRhs); |
| 286 | +} |
| 287 | + |
| 288 | +DValue *binShr(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 289 | + bool loadLhsAfterRhs) { |
| 290 | + auto op = (isLLVMUnsigned(type) ? llvm::Instruction::LShr |
| 291 | + : llvm::Instruction::AShr); |
| 292 | + return binBitwise(op, loc, type, lhs, rhs, loadLhsAfterRhs); |
| 293 | +} |
| 294 | + |
| 295 | +DValue *binUshr(Loc &loc, Type *type, DValue *lhs, Expression *rhs, |
| 296 | + bool loadLhsAfterRhs) { |
| 297 | + return binBitwise(llvm::Instruction::LShr, loc, type, lhs, rhs, |
| 298 | + loadLhsAfterRhs); |
106 | 299 | } |
107 | 300 |
|
108 | 301 | ////////////////////////////////////////////////////////////////////////////// |
|
0 commit comments